ホーム ] わが家のPC環境 ] 64ビットPC自作 ] 地デジ ] PC音楽システム ] PC写真システム ] Exifファイル入門 ]

上へ
ワークフロー
画像仕様
フォルダ構成
データベース構成
システム運用系
植物写真系
Web処理系
写真表示コントロール
写真画像生成
現像(Nikon Capture 4)との連携
写真印刷

PC写真システム

写真印刷

最終更新日:2006/09/17  修正

 市販のアプリで印刷はできるが、自分のワークフロー内で印刷する場合は、やはり自製アプリでも印刷できた方が便利。

●印刷仕様

  • 四辺縁なし印刷

    焼き付けの代わりとなるものは、高精細印刷での(エプソンの)四辺縁なし印刷に対応する。
     
  • 単一印刷

    一品一葉の印刷。ランドスケープ、ポートレートは自動識別され印刷される。
     
  • 一覧印刷

    一覧表示を印刷。印刷サイズは長辺が約 5cm となる。
     
  • センタリング

    縁なし以外では、自動的にセンタリング(頁中央合せ)される。
     
  • 印刷対象

    CurrentSelect、Select 及び指定された全数。
     

●縁なし印刷とは?

 これは、用紙の余白が完全に 0 になるもので、物理オフセット値も 0 になる。実際の印刷では写真専用紙やアート紙など、強度のある紙を使用しないといけない。

 四辺縁なしで写真(画像)の場合は、用紙サイズ一杯に指定する。従って、写真のアスペクトレシオと用紙のそれは異なるので、用紙のアスペクトレシオにて写真をトリミングすることになる。エプソンによれば、縁なしの場合は、ドライバにて、僅かに写真を拡大し、少し 、はみ出るように調整されるらしい。これは、プリンタの機械的誤差を吸収するための処置らしい。 従って、実際の印刷では、用紙サイズより縦、横共に1.5% だけ縮めて印刷する。

●"縁なし"の認識

 "縁なし"を指定しても、アプリ側でこれを認識できないと縁なし印刷は自分でできない。実験の結果、以下のことが分った。

 印刷ダイアログ(エプソン提供)で縁なしを指定すると、デフォールトセッティングのPaperSource の値が特定値になる。

pdgD は印刷設定ダイアログとすれば、PaperSource のKind プロパティ、

pdgD.PrinterSettings.DefaultPageSettings.PaperSource.Kind

が、値 257(Integer変換) となる。これを検出すれば良い。

 ちなみに、ダイアログでの紙質設定は、全て、解像度に反映するようだ。

●UI

 以下のようなUIとなっている。

  1. 写真の通常表示で表示している写真群を対象とし、コンテキストメニューで対象と印刷方法を選ぶ。
  2. 必ず、印刷設定ダイアログが表示されるので、ここで、用紙、用紙サイズ、方向、品質、縁なしなどを指定する。
  3. すると、必ず、プレビューが自動表示される。ここで全ての頁の確認を行える。
  4. プレビュー窓から印刷を指示する。


プレビューの例

●自動センタリング

 これは、用紙の四辺の余白を、上下と左右で均等になるように自動調整するものである。これは単純な処理ではない。これについては、ここここを参照方。

●事例

 以下に実際のコード例を紹介する。

○コンテキストメニュー処理

Case "単一印刷"(CurrentSelect)
   PrintPhotos(1)
Case "単一印刷"
   PrintPhotos(2)
Case "一覧印刷(選択)"
   PrintPhotos(3)
Case "一覧印刷(全頁)"
   PrintPhotos(4)

○印刷設定とプリビュー

pdgD は印刷設定ダイログ
pdcD はドキュメントオブジェクト
prvD はプリビューダイアログ

Private Sub PrintPhotos(ByVal m As Integer)
   Dim i, p As Integer
   pdgD.Document = pdcD
   pdgD.AllowPrintToFile = False
   pdgD.AllowSelection = False
   pdgD.AllowSomePages = False
   pdgD.PrintToFile = False
   pdgD.ShowHelp = False
   DlgR = pdgD.ShowDialog()
   Select Case DlgR
      Case DialogResult.OK, DialogResult.Yes
         PrintMode = m
         CPSKind = CInt(pdgD.PrinterSettings.DefaultPageSettings.PaperSource.Kind)
         If CPSKind = EpsonNoMargin Then      '縁なし、物理オフセット値=0
            ReDim POffs(3)
            Vmgn = 0
            Hmgn = 0
            Voffs = 0
            Hoffs = 0
         Else
            GParam.GetPrinterMarginsEx(pdgD.PrinterSettings.PrinterName, POffs)
     'プリンタの物理オフセット値を獲得

            For i = 0 To 3
               POffs(i) = POffs(i) * 100        '1/100インチ単位、A4縦基準
            Next
            Vmgn = Math.Max(POffs(0), POffs(1)) '上下の空白
            Hmgn = Math.Max(POffs(2), POffs(3)) '左右の空白
            Voffs = POffs(0)
            Hoffs = POffs(2)
         End If
         Dim prc As Rectangle = pdgD.PrinterSettings.DefaultPageSettings.Bounds
         Select Case m
             (mに応じて設定する、一覧では予め頁数や画像配置を算出しておく)
         End Select
         PreV = 0
         pdcD.DocumentName = MMsg
         prvD.Document = pdcD
         prvD.AutoScroll = False
         prvD.WindowState = FormWindowState.Maximized
         prvD.StartPosition = FormStartPosition.CenterScreen
         prvD.ShowDialog()                     'プリビューし印刷する
      Case Else
         Exit Sub
      End Select
End Sub

○pdcD のイベント処理

    Private Sub pdcD_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles pdcD.BeginPrint
        CPPage = 0
        PreV = PreV + 1
    End Sub
 

単一画像の場合は、画像に応じて用紙方向を自動設定する

    Private Sub pdcD_QueryPageSettings(ByVal sender As Object, ByVal e As System.Drawing.Printing.QueryPageSettingsEventArgs) Handles pdcD.QueryPageSettings
        Select Case PrintMode
            Case 1, 2                   '単一画像の場合は、方向は強制設定
                Select Case PS(pOrientation, PrintIXT(CPPage))
                    Case "P"
                        e.PageSettings.Landscape = False
                    Case "L"
                        e.PageSettings.Landscape = True
                End Select
            Case Else
                'NOP
        End Select
    End Sub

印刷処理(プリビュー時も実行される)

PrintIXT は、印刷対象写真のインデックスリスト

    Private Sub pdcD_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles pdcD.PrintPage
        Dim g As Graphics = e.Graphics
        Dim bmp As Bitmap
        Dim ft As New Font(Me.Font.Name, 6, FontStyle.Regular)
        Dim PW, PH, W, H, nw, nh, ACnt, i, Ix, ta, yo As Integer
        Dim X, Y As Single
        Dim FP As String
        Select Case PreV    'オフセット設定
            Case 1             'プリビュー
                Xoffs = 0 : Yoffs = 0
                Select Case e.PageSettings.Landscape
                    Case False
                        Xmgn = Hmgn
                        Ymgn = Vmgn
                    Case True
                        Xmgn = Vmgn
                        Ymgn = Hmgn
                End Select
            Case Else         '実印刷
                If CPSKind = EpsonNoMargin Then   '空白はなし
                    Xoffs = 0 : Yoffs = 0
                    Xmgn = 0 : Ymgn = 0
                Else
                    Select Case e.PageSettings.Landscape
                        Case False
                            Xoffs = Hoffs
                            Yoffs = Voffs
                            Xmgn = Hmgn
                            Ymgn = Vmgn
                        Case True
                            Xoffs = Voffs
                            Yoffs = Hoffs
                            Xmgn = Vmgn
                            Ymgn = Hmgn
                    End Select
                End If
        End Select
        Select Case PrintMode
            Case 1, 2
                If PreV = 1 Then    'プリビューの場合は小さい画像を確保
                    FP = LargeWebPath(PS(pPNo, PrintIXT(CPPage)), PS(pFld, PrintIXT(CPPage)))
                Else
                    FP = PrintPath(PS(pPNo, PrintIXT(CPPage)), PS(pFld, PrintIXT(CPPage)))
                End If
                Dim st As Stream = File.Open(FP, FileMode.Open)
                bmp = Bitmap.FromStream(st)
                st.Close()
                W = bmp.Width
                H = bmp.Height
                Dim prc As Rectangle = e.PageBounds
                Dim drc As Rectangle
                PW = prc.Width - 2 * Xmgn        '印刷可能範囲
                PH = prc.Height - 2 * Ymgn
                If CPSKind = EpsonNoMargin Then  '四辺縁なし処理
                    If PW / PH > W / H Then
                        nw = W
                        nh = nw * PH / PW
                    Else
                        nh = H
                        nw = nh * PW / PH
                    End If
          '原画を切抜く矩形
                    Dim src As New Rectangle((W - nw) / 2, (H - nh) / 2, nw, nh)  '画像切抜き範囲
                    drc = prc   '描画領域は紙全体
                    If PreV <> 1 Then drc.Inflate(-PW * 0.015, -PH * 0.015)  '印刷時は少し縮める
                    g.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic
                    g.DrawImage(bmp, drc, src, GraphicsUnit.Pixel)

                Else
                    If W / H > PW / PH Then
                        nw = PW
                        nh = PW * H / W
                    Else
                        nh = PH
                        nw = nh * W / H
                    End If
                    drc = New Rectangle((prc.Width - nw) / 2 - Xoffs, (prc.Height - nh) / 2 - Yoffs, nw, nh)
                    g.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic
                    g.DrawImage(bmp, drc)
                End If
                Dim fmt As New StringFormat()
                fmt.Alignment = StringAlignment.Far
                fmt.LineAlignment = StringAlignment.Far
                g.DrawString(Rights, Me.Font, Brushes.Yellow, drc.Right , drc.Bottom - 4, fmt)
                Dim T As String
                T = PS(pName, PrintIXT(CPPage))
                T = T + " (" + PS(pLand, PrintIXT(CPPage)) + ", " + CDate(PS(pDate, PrintIXT(CPPage))).ToString("yyyy/MM/dd") + ")"
                fmt.Alignment = StringAlignment.Center
                g.DrawString(T, Me.Font, Brushes.Yellow, (drc.Left + drc.Right) / 2 , drc.Bottom - 4 , fmt)
                fmt.Dispose()
            Case 3, 4                    '一覧印刷
                If CPPage >= (PPages - 1) Then
                    ACnt = PImages - (CPPage * PageImages)
                Else
                    ACnt = PageImages
                End If
                For i = 0 To ACnt - 1
                    Ix = CPPage * PageImages + i
                    ta = i \ PYoko
                    yo = i Mod PYoko
                    X = yo * MiniW + Prec.Left
                    Y = ta * MiniH + Prec.Top
                    FP = SmallWebPath(PS(pPNo, PrintIXT(Ix)), PS(pFld, PrintIXT(Ix)))
                    Dim st As Stream = File.Open(FP, FileMode.Open)
                    bmp = Bitmap.FromStream(st)
                    st.Close()
                    W = bmp.Width
                    H = bmp.Height
                    If W > H Then
                        nw = MiniLong
                        nh = nw * H / W
                    Else
                        nh = MiniLong
                        nw = nh * W / H
                    End If
                    Dim drc As New RectangleF(X + (MiniW - nw) / 2 - Xoffs, Y + MiniH - (MiniSpanY + nh) - Yoffs, nw, nh)
                    g.DrawImage(bmp, drc)
                    Dim fmt As New StringFormat()
                    fmt.Alignment = StringAlignment.Center
                    fmt.LineAlignment = StringAlignment.Near
                    Dim T As String
                    T = PS(pName, PrintIXT(Ix))
                     T = T + " (" + CDate(PS(pDate, PrintIXT(Ix))).ToString("yyyy/MM/dd") + ", " + PS(pLand, PrintIXT(Ix)) + ")"
                     g.DrawString(T, ft, Brushes.Black, X + MiniW / 2 - Xoffs, drc.Bottom + 12 - Yoffs, fmt)
                Next
        End Select
        CPPage = CPPage + 1
        If CPPage < PPages Then
            e.HasMorePages = True
        Else
            e.HasMorePages = False
        End If
        ft.Dispose
        bmp.Dispose()
    End Sub