]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/dcprint.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dcprint.cpp
3 // Purpose: wxPrinterDC class
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "dcprint.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
32 #include "wx/string.h"
34 #include "wx/window.h"
35 #include "wx/dcmemory.h"
38 #if wxUSE_PRINTING_ARCHITECTURE
40 #include "wx/msw/private.h"
41 #include "wx/dcprint.h"
44 #if wxUSE_COMMON_DIALOGS
52 // mingw32 defines GDI_ERROR incorrectly
55 #define GDI_ERROR ((int)-1)
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 IMPLEMENT_CLASS(wxPrinterDC
, wxDC
)
64 // ============================================================================
66 // ============================================================================
68 // ----------------------------------------------------------------------------
69 // wxPrinterDC construction
70 // ----------------------------------------------------------------------------
72 // This form is deprecated
73 wxPrinterDC::wxPrinterDC(const wxString
& driver_name
,
74 const wxString
& device_name
,
79 m_isInteractive
= interactive
;
82 m_printData
.SetFilename(file
);
84 #if wxUSE_COMMON_DIALOGS
89 pd
.lStructSize
= sizeof( PRINTDLG
);
90 pd
.hwndOwner
= (HWND
) NULL
;
91 pd
.hDevMode
= (HANDLE
)NULL
;
92 pd
.hDevNames
= (HANDLE
)NULL
;
93 pd
.Flags
= PD_RETURNDC
| PD_NOSELECTION
| PD_NOPAGENUMS
;
99 pd
.hInstance
= (HINSTANCE
)NULL
;
101 m_ok
= PrintDlg( &pd
) != 0;
104 m_hDC
= (WXHDC
) pd
.hDC
;
108 #endif // wxUSE_COMMON_DIALOGS
110 if ( !driver_name
.empty() && !device_name
.empty() && !file
.empty() )
112 m_hDC
= (WXHDC
) CreateDC(driver_name
, device_name
, file
, NULL
);
114 else // we don't have all parameters, ask the user
116 wxPrintData printData
;
117 printData
.SetOrientation(orientation
);
118 m_hDC
= wxGetPrinterDC(printData
);
121 m_ok
= m_hDC
? TRUE
: FALSE
;
123 // as we created it, we must delete it as well
130 wxPrinterDC::wxPrinterDC(const wxPrintData
& printData
)
132 m_printData
= printData
;
134 m_isInteractive
= FALSE
;
136 m_hDC
= wxGetPrinterDC(printData
);
144 wxPrinterDC::wxPrinterDC(WXHDC dc
)
146 m_isInteractive
= FALSE
;
153 void wxPrinterDC::Init()
157 // int width = GetDeviceCaps(m_hDC, VERTRES);
158 // int height = GetDeviceCaps(m_hDC, HORZRES);
159 SetMapMode(wxMM_TEXT
);
161 SetBrush(*wxBLACK_BRUSH
);
162 SetPen(*wxBLACK_PEN
);
166 // ----------------------------------------------------------------------------
167 // wxPrinterDC {Start/End}{Page/Doc} methods
168 // ----------------------------------------------------------------------------
170 bool wxPrinterDC::StartDoc(const wxString
& message
)
173 docinfo
.cbSize
= sizeof(DOCINFO
);
174 docinfo
.lpszDocName
= (const wxChar
*)message
;
176 wxString
filename(m_printData
.GetFilename());
178 if (filename
.IsEmpty())
179 docinfo
.lpszOutput
= NULL
;
181 docinfo
.lpszOutput
= (const wxChar
*) filename
;
183 #if defined(__WIN95__)
184 docinfo
.lpszDatatype
= NULL
;
191 int ret
= ::StartDoc(GetHdc(), &docinfo
);
196 DWORD lastError
= GetLastError();
197 wxLogDebug(wxT("wxDC::StartDoc failed with error: %ld\n"), lastError
);
204 void wxPrinterDC::EndDoc()
206 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
209 void wxPrinterDC::StartPage()
212 ::StartPage((HDC
) m_hDC
);
215 void wxPrinterDC::EndPage()
218 ::EndPage((HDC
) m_hDC
);
221 // Returns default device and port names
222 static bool wxGetDefaultDeviceName(wxString
& deviceName
, wxString
& portName
)
226 LPDEVNAMES lpDevNames
;
227 LPTSTR lpszDriverName
;
228 LPTSTR lpszDeviceName
;
233 // Cygwin has trouble believing PRINTDLG is 66 bytes - thinks it is 68
236 pd
.lStructSize
= 66; // sizeof(PRINTDLG);
238 memset(&pd
, 0, sizeof(PRINTDLG
));
239 pd
.lStructSize
= sizeof(PRINTDLG
);
242 pd
.hwndOwner
= (HWND
)NULL
;
243 pd
.hDevMode
= NULL
; // Will be created by PrintDlg
244 pd
.hDevNames
= NULL
; // Ditto
245 pd
.Flags
= PD_RETURNDEFAULT
;
248 if (!PrintDlg((LPPRINTDLG
)&pd
))
251 GlobalFree(pd
.hDevMode
);
253 GlobalFree(pd
.hDevNames
);
260 lpDevNames
= (LPDEVNAMES
)GlobalLock(pd
.hDevNames
);
261 lpszDriverName
= (LPTSTR
)lpDevNames
+ lpDevNames
->wDriverOffset
;
262 lpszDeviceName
= (LPTSTR
)lpDevNames
+ lpDevNames
->wDeviceOffset
;
263 lpszPortName
= (LPTSTR
)lpDevNames
+ lpDevNames
->wOutputOffset
;
265 deviceName
= lpszDeviceName
;
266 portName
= lpszPortName
;
268 GlobalUnlock(pd
.hDevNames
);
269 GlobalFree(pd
.hDevNames
);
275 GlobalFree(pd
.hDevMode
);
278 return ( deviceName
!= wxT("") );
282 // This uses defaults, except for orientation, so we should eliminate this function
283 // and use the 2nd form (passing wxPrintData) instead.
284 WXHDC
wxGetPrinterDC(int orientation
)
287 LPDEVMODE lpDevMode
= NULL
;
288 LPDEVNAMES lpDevNames
;
289 LPSTR lpszDriverName
;
290 LPSTR lpszDeviceName
;
294 // __GNUWIN32__ has trouble believing PRINTDLG is 66 bytes - thinks it is 68
296 pd
.lStructSize
= 66; // sizeof(PRINTDLG);
298 pd
.lStructSize
= sizeof(PRINTDLG
);
300 pd
.hwndOwner
= (HWND
)NULL
;
301 pd
.hDevMode
= NULL
; // Will be created by PrintDlg
302 pd
.hDevNames
= NULL
; // Ditto
303 pd
.Flags
= PD_RETURNDEFAULT
;
306 if (!PrintDlg((LPPRINTDLG
)&pd
))
309 GlobalFree(pd
.hDevMode
);
311 GlobalFree(pd
.hDevNames
);
319 GlobalFree(pd
.hDevMode
);
322 lpDevNames
= (LPDEVNAMES
)GlobalLock(pd
.hDevNames
);
323 lpszDriverName
= (LPSTR
)lpDevNames
+ lpDevNames
->wDriverOffset
;
324 lpszDeviceName
= (LPSTR
)lpDevNames
+ lpDevNames
->wDeviceOffset
;
325 lpszPortName
= (LPSTR
)lpDevNames
+ lpDevNames
->wOutputOffset
;
326 GlobalUnlock(pd
.hDevNames
);
330 lpDevMode
= (DEVMODE
*) GlobalLock(pd
.hDevMode
);
331 lpDevMode
->dmOrientation
= orientation
;
332 lpDevMode
->dmFields
|= DM_ORIENTATION
;
336 hDC
= CreateDC(lpszDriverName
, lpszDeviceName
, lpszPortName
, (DEVMODE
*)lpDevMode
);
338 hDC
= CreateDC(lpszDriverName
, lpszDeviceName
, lpszPortName
, (LPSTR
)lpDevMode
);
341 if (pd
.hDevMode
&& lpDevMode
)
342 GlobalUnlock(pd
.hDevMode
);
346 GlobalFree(pd
.hDevNames
);
351 GlobalFree(pd
.hDevMode
);
358 // Gets an HDC for the specified printer configuration
359 WXHDC WXDLLEXPORT
wxGetPrinterDC(const wxPrintData
& printDataConst
)
361 wxPrintData printData
= printDataConst
;
362 printData
.ConvertToNative();
364 wxChar
* driverName
= (wxChar
*) NULL
;
366 wxString devNameStr
= printData
.GetPrinterName();
367 wxChar
* portName
= (wxChar
*) NULL
; // Obsolete in WIN32
369 const wxChar
* deviceName
;
371 deviceName
= (wxChar
*) NULL
;
373 deviceName
= devNameStr
.c_str();
375 LPDEVMODE lpDevMode
= (LPDEVMODE
) NULL
;
377 HGLOBAL hDevMode
= (HGLOBAL
)(DWORD
) printData
.GetNativeData();
380 lpDevMode
= (DEVMODE
*) GlobalLock(hDevMode
);
384 // Retrieve the default device name
390 #endif // Debug/Release
391 wxGetDefaultDeviceName(devNameStr
, portName
);
393 wxASSERT_MSG( ret
, wxT("Could not get default device name.") );
395 deviceName
= devNameStr
.c_str();
399 HDC hDC
= CreateDC(driverName
, deviceName
, portName
, (DEVMODE
*) lpDevMode
);
401 HDC hDC
= CreateDC(driverName
, deviceName
, portName
, (LPSTR
) lpDevMode
);
404 if (hDevMode
&& lpDevMode
)
405 GlobalUnlock(hDevMode
);
410 // ----------------------------------------------------------------------------
411 // wxPrinterDC bit blitting/bitmap drawing
412 // ----------------------------------------------------------------------------
414 // Win16 doesn't define GDI_ERROR.
419 // Just in case we want to go back to using 8 bits for
420 // any reason: set this to 0 for 8 bits.
421 #define wxUSE_DRAWBITMAP_24BITS 1
423 void wxPrinterDC::DoDrawBitmap(const wxBitmap
&bmp
,
424 wxCoord x
, wxCoord y
,
427 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxPrinterDC::DrawBitmap") );
429 int width
= bmp
.GetWidth(),
430 height
= bmp
.GetHeight();
432 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS
) & RC_STRETCHDIB
)
434 #if wxUSE_DIB_FOR_BITMAP
435 if(bmp
.GetHFileMap()) // we already have a dib
438 if ( ::GetObject(GetHbitmapOf(bmp
),
440 &dib
) == sizeof(dib
) )
450 (LPBITMAPINFO
)&dib
.dsBmih
,
455 wxLogLastError(wxT("StretchDIBits"));
460 wxLogLastError(wxT("GetObject"));
464 #endif // wxUSE_DIB_FOR_BITMAP
466 BITMAPINFO
*info
= (BITMAPINFO
*) malloc( sizeof( BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
) );
467 memset( info
, 0, sizeof( BITMAPINFOHEADER
) );
469 #if wxUSE_DRAWBITMAP_24BITS
470 int iBitsSize
= (((width
* 3) + 3 ) & ~3 ) * height
;
472 int iBitsSize
= ((width
+ 3 ) & ~3 ) * height
;
475 void* bits
= malloc( iBitsSize
);
477 info
->bmiHeader
.biSize
= sizeof( BITMAPINFOHEADER
);
478 info
->bmiHeader
.biWidth
= width
;
479 info
->bmiHeader
.biHeight
= height
;
480 info
->bmiHeader
.biPlanes
= 1;
481 #if wxUSE_DRAWBITMAP_24BITS
482 info
->bmiHeader
.biBitCount
= 24;
484 info
->bmiHeader
.biBitCount
= 8;
486 info
->bmiHeader
.biCompression
= BI_RGB
;
489 if ( GetDIBits(display
, GetHbitmapOf(bmp
), 0,
490 bmp
.GetHeight(), bits
, info
,
493 if ( ::StretchDIBits(GetHdc(), x
, y
,
495 0 , 0, width
, height
,
497 DIB_RGB_COLORS
, SRCCOPY
) == GDI_ERROR
)
499 wxLogLastError(wxT("StretchDIBits"));
507 else // no support for StretchDIBits()
510 memDC
.SelectObject(bmp
);
512 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
514 memDC
.SelectObject(wxNullBitmap
);
518 bool wxPrinterDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
519 wxCoord width
, wxCoord height
,
521 wxCoord xsrc
, wxCoord ysrc
,
522 int WXUNUSED(rop
), bool useMask
,
523 wxCoord
WXUNUSED(xsrcMask
), wxCoord
WXUNUSED(ysrcMask
))
529 // If we are printing source colours are screen colours not printer
530 // colours and so we need copy the bitmap pixel by pixel.
532 HDC dc_src
= GetHdcOf(*source
);
533 HDC dc_mask
= ::CreateCompatibleDC(dc_src
);
535 ::SelectObject(dc_mask
, (HBITMAP
) source
->GetSelectedBitmap().GetMask()->GetMaskBitmap());
536 for (int x
= 0; x
< width
; x
++)
538 for (int y
= 0; y
< height
; y
++)
540 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
543 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
544 rect
.left
= xdest
+ x
;
545 rect
.right
= rect
.left
+ 1;
546 rect
.top
= ydest
+ y
;
547 rect
.bottom
= rect
.top
+ 1;
548 ::FillRect(GetHdc(), &rect
, brush
);
549 ::DeleteObject(brush
);
553 ::SelectObject(dc_mask
, 0);
558 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS
) & RC_STRETCHDIB
)
560 wxBitmap
& bmp
= source
->GetSelectedBitmap();
561 int width
= bmp
.GetWidth(),
562 height
= bmp
.GetHeight();
563 #if wxUSE_DIB_FOR_BITMAP
564 if(bmp
.GetHFileMap()) // we already have a dib
567 if( ::GetObject(GetHbitmapOf(bmp
),
569 &dib
) == sizeof(dib
) )
579 (LPBITMAPINFO
)&dib
.dsBmih
,
584 wxLogLastError(wxT("StretchDIBits"));
589 wxLogLastError(wxT("GetObject"));
593 #endif // wxUSE_DIB_FOR_BITMAP
595 BITMAPINFO
*info
= (BITMAPINFO
*) malloc( sizeof( BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
) );
596 #if wxUSE_DRAWBITMAP_24BITS
597 int iBitsSize
= (((width
* 3) + 3 ) & ~3 ) * height
;
599 int iBitsSize
= ((width
+ 3 ) & ~3 ) * height
;
602 void* bits
= malloc( iBitsSize
);
604 memset( info
, 0 , sizeof( BITMAPINFOHEADER
) );
606 info
->bmiHeader
.biSize
= sizeof( BITMAPINFOHEADER
);
607 info
->bmiHeader
.biWidth
= width
;
608 info
->bmiHeader
.biHeight
= height
;
609 info
->bmiHeader
.biPlanes
= 1;
610 #if wxUSE_DRAWBITMAP_24BITS
611 info
->bmiHeader
.biBitCount
= 24;
613 info
->bmiHeader
.biBitCount
= 8;
615 info
->bmiHeader
.biCompression
= BI_RGB
;
618 if ( !::GetDIBits(display
, GetHbitmapOf(bmp
), 0,
619 height
, bits
, info
, DIB_RGB_COLORS
) )
621 wxLogLastError(wxT("GetDIBits"));
628 success
= ::StretchDIBits(GetHdc(), xdest
, ydest
,
634 SRCCOPY
) != GDI_ERROR
;
637 wxLogLastError(wxT("StretchDIBits"));
645 else // no support for StretchDIBits
647 // as we are printing, source colours are screen colours not
648 // printer colours and so we need copy the bitmap pixel by pixel.
649 HDC dc_src
= GetHdcOf(*source
);
651 for (int y
= 0; y
< height
; y
++)
653 // optimization: draw identical adjacent pixels together.
654 for (int x
= 0; x
< width
; x
++)
656 COLORREF col
= ::GetPixel(dc_src
, x
, y
);
657 HBRUSH brush
= ::CreateSolidBrush( col
);
659 rect
.left
= xdest
+ x
;
660 rect
.top
= ydest
+ y
;
661 while( (x
+ 1 < width
) && (::GetPixel(dc_src
, x
+ 1, y
) == col
) )
665 rect
.right
= xdest
+ x
+ 1;
666 rect
.bottom
= rect
.top
+ 1;
667 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
668 ::DeleteObject(brush
);
678 // wxUSE_PRINTING_ARCHITECTURE