1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dcprint.cpp
3 // Purpose: wxPrinterDC class
4 // Author: Julian Smart
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
26 #if wxUSE_PRINTING_ARCHITECTURE
28 #include "wx/dcprint.h"
29 #include "wx/msw/dcprint.h"
32 #include "wx/msw/wrapcdlg.h"
33 #include "wx/string.h"
35 #include "wx/window.h"
36 #include "wx/dcmemory.h"
40 #include "wx/msw/private.h"
43 #include "wx/msw/dib.h"
46 #include "wx/printdlg.h"
47 #include "wx/msw/printdlg.h"
53 // mingw32 defines GDI_ERROR incorrectly
54 #if defined(__GNUWIN32__) || !defined(GDI_ERROR)
56 #define GDI_ERROR ((int)-1)
59 #if defined(__WXUNIVERSAL__) && wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW
60 #define wxUSE_PS_PRINTING 1
62 #define wxUSE_PS_PRINTING 0
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
69 IMPLEMENT_ABSTRACT_CLASS(wxPrinterDCImpl
, wxMSWDCImpl
)
71 // ============================================================================
73 // ============================================================================
75 // ----------------------------------------------------------------------------
76 // wxPrinterDC construction
77 // ----------------------------------------------------------------------------
80 // This form is deprecated
81 wxPrinterDC::wxPrinterDC(const wxString
& driver_name
,
82 const wxString
& device_name
,
85 wxPrintOrientation orientation
)
87 m_isInteractive
= interactive
;
90 m_printData
.SetFilename(file
);
92 #if wxUSE_COMMON_DIALOGS
97 pd
.lStructSize
= sizeof( PRINTDLG
);
98 pd
.hwndOwner
= (HWND
) NULL
;
99 pd
.hDevMode
= (HANDLE
)NULL
;
100 pd
.hDevNames
= (HANDLE
)NULL
;
101 pd
.Flags
= PD_RETURNDC
| PD_NOSELECTION
| PD_NOPAGENUMS
;
107 pd
.hInstance
= (HINSTANCE
)NULL
;
109 m_ok
= PrintDlg( &pd
) != 0;
112 m_hDC
= (WXHDC
) pd
.hDC
;
116 #endif // wxUSE_COMMON_DIALOGS
118 if ( !driver_name
.empty() && !device_name
.empty() && !file
.empty() )
120 m_hDC
= (WXHDC
) CreateDC(driver_name
.t_str(),
125 else // we don't have all parameters, ask the user
127 wxPrintData printData
;
128 printData
.SetOrientation(orientation
);
129 m_hDC
= wxGetPrinterDC(printData
);
132 m_ok
= m_hDC
? true: false;
134 // as we created it, we must delete it as well
142 wxPrinterDCImpl::wxPrinterDCImpl( wxPrinterDC
*owner
, const wxPrintData
& printData
) :
145 m_printData
= printData
;
147 m_isInteractive
= false;
149 m_hDC
= wxGetPrinterDC(printData
);
157 wxPrinterDCImpl::wxPrinterDCImpl( wxPrinterDC
*owner
, WXHDC dc
) :
160 m_isInteractive
= false;
167 void wxPrinterDCImpl::Init()
171 // int width = GetDeviceCaps(m_hDC, VERTRES);
172 // int height = GetDeviceCaps(m_hDC, HORZRES);
173 SetMapMode(wxMM_TEXT
);
175 SetBrush(*wxBLACK_BRUSH
);
176 SetPen(*wxBLACK_PEN
);
180 // ----------------------------------------------------------------------------
181 // wxPrinterDCImpl {Start/End}{Page/Doc} methods
182 // ----------------------------------------------------------------------------
184 bool wxPrinterDCImpl::StartDoc(const wxString
& message
)
187 docinfo
.cbSize
= sizeof(DOCINFO
);
188 docinfo
.lpszDocName
= message
.t_str();
190 wxString
filename(m_printData
.GetFilename());
192 if (filename
.empty())
193 docinfo
.lpszOutput
= NULL
;
195 docinfo
.lpszOutput
= filename
.t_str();
197 docinfo
.lpszDatatype
= NULL
;
203 if ( ::StartDoc(GetHdc(), &docinfo
) <= 0 )
205 wxLogLastError(wxT("StartDoc"));
212 void wxPrinterDCImpl::EndDoc()
214 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
217 void wxPrinterDCImpl::StartPage()
220 ::StartPage((HDC
) m_hDC
);
223 void wxPrinterDCImpl::EndPage()
226 ::EndPage((HDC
) m_hDC
);
230 wxRect
wxPrinterDCImpl::GetPaperRect() const
233 if (!IsOk()) return wxRect(0, 0, 0, 0);
234 int w
= ::GetDeviceCaps((HDC
) m_hDC
, PHYSICALWIDTH
);
235 int h
= ::GetDeviceCaps((HDC
) m_hDC
, PHYSICALHEIGHT
);
236 int x
= -::GetDeviceCaps((HDC
) m_hDC
, PHYSICALOFFSETX
);
237 int y
= -::GetDeviceCaps((HDC
) m_hDC
, PHYSICALOFFSETY
);
238 return wxRect(x
, y
, w
, h
);
242 #if !wxUSE_PS_PRINTING
244 // Returns default device and port names
245 static bool wxGetDefaultDeviceName(wxString
& deviceName
, wxString
& portName
)
249 LPDEVNAMES lpDevNames
;
250 LPTSTR lpszDeviceName
;
255 // Cygwin has trouble believing PRINTDLG is 66 bytes - thinks it is 68
258 pd
.lStructSize
= 66; // sizeof(PRINTDLG);
260 memset(&pd
, 0, sizeof(PRINTDLG
));
261 pd
.lStructSize
= sizeof(PRINTDLG
);
264 pd
.hwndOwner
= (HWND
)NULL
;
265 pd
.hDevMode
= NULL
; // Will be created by PrintDlg
266 pd
.hDevNames
= NULL
; // Ditto
267 pd
.Flags
= PD_RETURNDEFAULT
;
270 if (!PrintDlg((LPPRINTDLG
)&pd
))
273 GlobalFree(pd
.hDevMode
);
275 GlobalFree(pd
.hDevNames
);
282 lpDevNames
= (LPDEVNAMES
)GlobalLock(pd
.hDevNames
);
283 lpszDeviceName
= (LPTSTR
)lpDevNames
+ lpDevNames
->wDeviceOffset
;
284 lpszPortName
= (LPTSTR
)lpDevNames
+ lpDevNames
->wOutputOffset
;
286 deviceName
= lpszDeviceName
;
287 portName
= lpszPortName
;
289 GlobalUnlock(pd
.hDevNames
);
290 GlobalFree(pd
.hDevNames
);
296 GlobalFree(pd
.hDevMode
);
299 return ( !deviceName
.empty() );
302 #endif // !wxUSE_PS_PRINTING
304 // Gets an HDC for the specified printer configuration
305 WXHDC WXDLLEXPORT
wxGetPrinterDC(const wxPrintData
& printDataConst
)
307 #if wxUSE_PS_PRINTING
309 wxUnusedVar(printDataConst
);
311 #else // native Windows printing
312 wxWindowsPrintNativeData
*data
=
313 (wxWindowsPrintNativeData
*) printDataConst
.GetNativeData();
315 data
->TransferFrom( printDataConst
);
317 wxString deviceName
= printDataConst
.GetPrinterName();
318 if ( deviceName
.empty() )
320 // Retrieve the default device name
322 if ( !wxGetDefaultDeviceName(deviceName
, portName
) )
324 return 0; // Could not get default device name
329 GlobalPtrLock lockDevMode
;
330 const HGLOBAL devMode
= data
->GetDevMode();
332 lockDevMode
.Init(devMode
);
336 NULL
, // no driver name as we use device name
339 static_cast<DEVMODE
*>(lockDevMode
.Get())
343 wxLogLastError(wxT("CreateDC(printer)"));
347 #endif // PostScript/Windows printing
350 // ----------------------------------------------------------------------------
351 // wxPrinterDCImpl bit blitting/bitmap drawing
352 // ----------------------------------------------------------------------------
354 // helper of DoDrawBitmap() and DoBlit()
356 bool DrawBitmapUsingStretchDIBits(HDC hdc
,
358 wxCoord x
, wxCoord y
)
362 bool ok
= dib
.IsOk();
367 if ( !::GetObject(dib
.GetHandle(), sizeof(ds
), &ds
) )
369 wxLogLastError(wxT("GetObject(DIBSECTION)"));
374 // ok, we've got all data we need, do blit it
379 ds
.dsBmih
.biWidth
, ds
.dsBmih
.biHeight
,
381 ds
.dsBmih
.biWidth
, ds
.dsBmih
.biHeight
,
383 (LPBITMAPINFO
)&ds
.dsBmih
,
388 wxLogLastError(wxT("StretchDIBits"));
399 void wxPrinterDCImpl::DoDrawBitmap(const wxBitmap
& bmp
,
400 wxCoord x
, wxCoord y
,
403 wxCHECK_RET( bmp
.IsOk(), wxT("invalid bitmap in wxPrinterDC::DrawBitmap") );
405 int width
= bmp
.GetWidth(),
406 height
= bmp
.GetHeight();
408 if ( !(::GetDeviceCaps(GetHdc(), RASTERCAPS
) & RC_STRETCHDIB
) ||
409 !DrawBitmapUsingStretchDIBits(GetHdc(), bmp
, x
, y
) )
411 // no support for StretchDIBits() or an error occurred if we got here
414 memDC
.SelectObjectAsSource(bmp
);
416 GetOwner()->Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
418 memDC
.SelectObject(wxNullBitmap
);
422 bool wxPrinterDCImpl::DoBlit(wxCoord xdest
, wxCoord ydest
,
423 wxCoord width
, wxCoord height
,
425 wxCoord
WXUNUSED(xsrc
), wxCoord
WXUNUSED(ysrc
),
426 wxRasterOperationMode
WXUNUSED(rop
), bool useMask
,
427 wxCoord
WXUNUSED(xsrcMask
), wxCoord
WXUNUSED(ysrcMask
))
429 wxDCImpl
*impl
= source
->GetImpl();
430 wxMSWDCImpl
*msw_impl
= wxDynamicCast(impl
, wxMSWDCImpl
);
434 wxBitmap
& bmp
= msw_impl
->GetSelectedBitmap();
435 wxMask
*mask
= useMask
? bmp
.GetMask() : NULL
;
438 // If we are printing source colours are screen colours not printer
439 // colours and so we need copy the bitmap pixel by pixel.
441 HDC dcSrc
= GetHdcOf(*msw_impl
);
442 MemoryHDC
dcMask(dcSrc
);
443 SelectInHDC
selectMask(dcMask
, (HBITMAP
)mask
->GetMaskBitmap());
445 for (int x
= 0; x
< width
; x
++)
447 for (int y
= 0; y
< height
; y
++)
449 COLORREF cref
= ::GetPixel(dcMask
, x
, y
);
452 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dcSrc
, x
, y
));
453 rect
.left
= xdest
+ x
;
454 rect
.right
= rect
.left
+ 1;
455 rect
.top
= ydest
+ y
;
456 rect
.bottom
= rect
.top
+ 1;
457 ::FillRect(GetHdc(), &rect
, brush
);
458 ::DeleteObject(brush
);
465 if ( !(::GetDeviceCaps(GetHdc(), RASTERCAPS
) & RC_STRETCHDIB
) ||
466 !DrawBitmapUsingStretchDIBits(GetHdc(), bmp
, xdest
, ydest
) )
468 // no support for StretchDIBits
470 // as we are printing, source colours are screen colours not
471 // printer colours and so we need copy the bitmap pixel by pixel.
472 HDC dcSrc
= GetHdcOf(*msw_impl
);
474 for (int y
= 0; y
< height
; y
++)
476 // optimization: draw identical adjacent pixels together.
477 for (int x
= 0; x
< width
; x
++)
479 COLORREF col
= ::GetPixel(dcSrc
, x
, y
);
480 HBRUSH brush
= ::CreateSolidBrush( col
);
482 rect
.left
= xdest
+ x
;
483 rect
.top
= ydest
+ y
;
484 while( (x
+ 1 < width
) &&
485 (::GetPixel(dcSrc
, x
+ 1, y
) == col
) )
489 rect
.right
= xdest
+ x
+ 1;
490 rect
.bottom
= rect
.top
+ 1;
491 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
492 ::DeleteObject(brush
);
502 // wxUSE_PRINTING_ARCHITECTURE