]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dcprint.cpp
1. fixed (to test) the bug with bitmaps without masks in wxImageList
[wxWidgets.git] / src / msw / dcprint.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dcprint.cpp
3 // Purpose: wxPrinterDC class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "dcprint.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/string.h"
33 #include "wx/log.h"
34 #include "wx/window.h"
35 #endif
36
37 #include "wx/msw/private.h"
38 #include "wx/dcprint.h"
39 #include "math.h"
40
41 #if wxUSE_COMMON_DIALOGS || defined(__WXWINE__)
42 #include <commdlg.h>
43 #endif
44
45 #ifndef __WIN32__
46 #include <print.h>
47 #endif
48
49 // ----------------------------------------------------------------------------
50 // wxWin macros
51 // ----------------------------------------------------------------------------
52 IMPLEMENT_CLASS(wxPrinterDC, wxDC)
53
54 // ============================================================================
55 // implementation
56 // ============================================================================
57
58 // ----------------------------------------------------------------------------
59 // wxPrinterDC construction
60 // ----------------------------------------------------------------------------
61
62 // This form is deprecated
63 wxPrinterDC::wxPrinterDC(const wxString& driver_name, const wxString& device_name, const wxString& file, bool interactive, int orientation)
64 {
65 m_isInteractive = interactive;
66
67 if ( !!file )
68 m_printData.SetFilename(file);
69
70 #if wxUSE_COMMON_DIALOGS
71 if (interactive)
72 {
73 PRINTDLG pd;
74
75 pd.lStructSize = sizeof( PRINTDLG );
76 pd.hwndOwner=(HWND) NULL;
77 pd.hDevMode=(HANDLE)NULL;
78 pd.hDevNames=(HANDLE)NULL;
79 pd.Flags=PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS;
80 pd.nFromPage=0;
81 pd.nToPage=0;
82 pd.nMinPage=0;
83 pd.nMaxPage=0;
84 pd.nCopies=1;
85 pd.hInstance=(HINSTANCE)NULL;
86
87 if ( PrintDlg( &pd ) != 0 )
88 {
89 m_hDC = (WXHDC) pd.hDC;
90 m_ok = TRUE;
91 }
92 else
93 {
94 m_ok = FALSE;
95 return;
96 }
97
98 // m_dontDelete = TRUE;
99 }
100 else
101 #endif // wxUSE_COMMON_DIALOGS
102 if ((!driver_name.IsNull() && driver_name != wxT("")) &&
103 (!device_name.IsNull() && device_name != wxT("")) &&
104 (!file.IsNull() && file != wxT("")))
105 {
106 m_hDC = (WXHDC) CreateDC(WXSTRINGCAST driver_name, WXSTRINGCAST device_name, WXSTRINGCAST file, NULL);
107 m_ok = m_hDC ? TRUE: FALSE;
108 }
109 else
110 {
111 wxPrintData printData;
112 printData.SetOrientation(orientation);
113 m_hDC = wxGetPrinterDC(printData);
114 m_ok = m_hDC ? TRUE: FALSE;
115 }
116
117 if (m_hDC)
118 {
119 // int width = GetDeviceCaps(m_hDC, VERTRES);
120 // int height = GetDeviceCaps(m_hDC, HORZRES);
121 SetMapMode(wxMM_TEXT);
122 }
123 SetBrush(*wxBLACK_BRUSH);
124 SetPen(*wxBLACK_PEN);
125 }
126
127 wxPrinterDC::wxPrinterDC(const wxPrintData& printData)
128 {
129 m_printData = printData;
130
131 m_isInteractive = FALSE;
132
133 m_hDC = wxGetPrinterDC(printData);
134 m_ok = (m_hDC != 0);
135
136 if (m_hDC)
137 SetMapMode(wxMM_TEXT);
138
139 SetBrush(*wxBLACK_BRUSH);
140 SetPen(*wxBLACK_PEN);
141 }
142
143
144 wxPrinterDC::wxPrinterDC(WXHDC theDC)
145 {
146 m_isInteractive = FALSE;
147
148 m_hDC = theDC;
149 m_ok = TRUE;
150 if (m_hDC)
151 {
152 // int width = GetDeviceCaps(m_hDC, VERTRES);
153 // int height = GetDeviceCaps(m_hDC, HORZRES);
154 SetMapMode(wxMM_TEXT);
155 }
156 SetBrush(*wxBLACK_BRUSH);
157 SetPen(*wxBLACK_PEN);
158 }
159
160 wxPrinterDC::~wxPrinterDC()
161 {
162 }
163
164 // ----------------------------------------------------------------------------
165 // wxPrinterDC {Start/End}{Page/Doc} methods
166 // ----------------------------------------------------------------------------
167
168 bool wxPrinterDC::StartDoc(const wxString& message)
169 {
170 DOCINFO docinfo;
171 docinfo.cbSize = sizeof(DOCINFO);
172 docinfo.lpszDocName = (const wxChar*)message;
173
174 wxString filename(m_printData.GetFilename());
175
176 if (filename.IsEmpty())
177 docinfo.lpszOutput = NULL;
178 else
179 docinfo.lpszOutput = (const wxChar *) filename;
180
181 #if defined(__WIN95__)
182 docinfo.lpszDatatype = NULL;
183 docinfo.fwType = 0;
184 #endif
185
186 if (!m_hDC)
187 return FALSE;
188
189 int ret = ::StartDoc(GetHdc(), &docinfo);
190
191 #ifndef __WIN16__
192 if (ret <= 0)
193 {
194 DWORD lastError = GetLastError();
195 wxLogDebug(wxT("wxDC::StartDoc failed with error: %d\n"), lastError);
196 }
197 #endif
198
199 return (ret > 0);
200 }
201
202 void wxPrinterDC::EndDoc()
203 {
204 if (m_hDC) ::EndDoc((HDC) m_hDC);
205 }
206
207 void wxPrinterDC::StartPage()
208 {
209 if (m_hDC)
210 ::StartPage((HDC) m_hDC);
211 }
212
213 void wxPrinterDC::EndPage()
214 {
215 if (m_hDC)
216 ::EndPage((HDC) m_hDC);
217 }
218
219 // Returns default device and port names
220 static bool wxGetDefaultDeviceName(wxString& deviceName, wxString& portName)
221 {
222 deviceName = "";
223
224 LPDEVNAMES lpDevNames;
225 LPSTR lpszDriverName;
226 LPSTR lpszDeviceName;
227 LPSTR lpszPortName;
228
229 PRINTDLG pd;
230
231 // Cygwin has trouble believing PRINTDLG is 66 bytes - thinks it is 68
232 #ifdef __GNUWIN32__
233 pd.lStructSize = 66; // sizeof(PRINTDLG);
234 #else
235 pd.lStructSize = sizeof(PRINTDLG);
236 #endif
237
238 pd.hwndOwner = (HWND)NULL;
239 pd.hDevMode = NULL; // Will be created by PrintDlg
240 pd.hDevNames = NULL; // Ditto
241 pd.Flags = PD_RETURNDEFAULT;
242 pd.nCopies = 1;
243
244 if (!PrintDlg((LPPRINTDLG)&pd))
245 {
246 if ( pd.hDevMode )
247 GlobalFree(pd.hDevMode);
248 if (pd.hDevNames)
249 GlobalFree(pd.hDevNames);
250
251 return FALSE;
252 }
253
254 if (pd.hDevNames)
255 {
256 lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
257 lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;
258 lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;
259 lpszPortName = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;
260
261 deviceName = lpszDeviceName;
262 portName = lpszPortName;
263
264 GlobalUnlock(pd.hDevNames);
265 GlobalFree(pd.hDevNames);
266 pd.hDevNames=NULL;
267 }
268
269 if (pd.hDevMode)
270 {
271 GlobalFree(pd.hDevMode);
272 pd.hDevMode=NULL;
273 }
274 return ( deviceName != wxT("") );
275 }
276
277 #if 0
278 // This uses defaults, except for orientation, so we should eliminate this function
279 // and use the 2nd form (passing wxPrintData) instead.
280 WXHDC wxGetPrinterDC(int orientation)
281 {
282 HDC hDC;
283 LPDEVMODE lpDevMode = NULL;
284 LPDEVNAMES lpDevNames;
285 LPSTR lpszDriverName;
286 LPSTR lpszDeviceName;
287 LPSTR lpszPortName;
288
289 PRINTDLG pd;
290 // __GNUWIN32__ has trouble believing PRINTDLG is 66 bytes - thinks it is 68
291 #ifdef __GNUWIN32__
292 pd.lStructSize = 66; // sizeof(PRINTDLG);
293 #else
294 pd.lStructSize = sizeof(PRINTDLG);
295 #endif
296 pd.hwndOwner = (HWND)NULL;
297 pd.hDevMode = NULL; // Will be created by PrintDlg
298 pd.hDevNames = NULL; // Ditto
299 pd.Flags = PD_RETURNDEFAULT;
300 pd.nCopies = 1;
301
302 if (!PrintDlg((LPPRINTDLG)&pd))
303 {
304 if ( pd.hDevMode )
305 GlobalFree(pd.hDevMode);
306 if (pd.hDevNames)
307 GlobalFree(pd.hDevNames);
308
309 return(0);
310 }
311
312 if (!pd.hDevNames)
313 {
314 if ( pd.hDevMode )
315 GlobalFree(pd.hDevMode);
316 }
317
318 lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
319 lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;
320 lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;
321 lpszPortName = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;
322 GlobalUnlock(pd.hDevNames);
323
324 if ( pd.hDevMode )
325 {
326 lpDevMode = (DEVMODE*) GlobalLock(pd.hDevMode);
327 lpDevMode->dmOrientation = orientation;
328 lpDevMode->dmFields |= DM_ORIENTATION;
329 }
330
331 #ifdef __WIN32__
332 hDC = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, (DEVMODE *)lpDevMode);
333 #else
334 hDC = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, (LPSTR)lpDevMode);
335 #endif
336
337 if (pd.hDevMode && lpDevMode)
338 GlobalUnlock(pd.hDevMode);
339
340 if (pd.hDevNames)
341 {
342 GlobalFree(pd.hDevNames);
343 pd.hDevNames=NULL;
344 }
345 if (pd.hDevMode)
346 {
347 GlobalFree(pd.hDevMode);
348 pd.hDevMode=NULL;
349 }
350 return (WXHDC) hDC;
351 }
352 #endif
353
354 // Gets an HDC for the specified printer configuration
355 WXHDC WXDLLEXPORT wxGetPrinterDC(const wxPrintData& printDataConst)
356 {
357 wxPrintData printData = printDataConst;
358 printData.ConvertToNative();
359
360 wxChar* driverName = (wxChar*) NULL;
361
362 wxString devNameStr = printData.GetPrinterName();
363 wxChar* portName = (wxChar*) NULL; // Obsolete in WIN32
364
365 const wxChar* deviceName;
366 if ( !devNameStr )
367 deviceName = (wxChar*) NULL;
368 else
369 deviceName = devNameStr.c_str();
370
371 LPDEVMODE lpDevMode = (LPDEVMODE) NULL;
372
373 HGLOBAL hDevMode = (HGLOBAL)(DWORD) printData.GetNativeData();
374
375 if ( hDevMode )
376 lpDevMode = (DEVMODE*) GlobalLock(hDevMode);
377
378 if ( !devNameStr )
379 {
380 // Retrieve the default device name
381 wxString portName;
382 #ifdef __WXDEBUG__
383 bool ret =
384 #else // !Debug
385 (void)
386 #endif // Debug/Release
387 wxGetDefaultDeviceName(devNameStr, portName);
388
389 wxASSERT_MSG( ret, wxT("Could not get default device name.") );
390
391 deviceName = devNameStr.c_str();
392 }
393
394 #ifdef __WIN32__
395 HDC hDC = CreateDC(driverName, deviceName, portName, (DEVMODE *) lpDevMode);
396 #else
397 HDC hDC = CreateDC(driverName, deviceName, portName, (LPSTR) lpDevMode);
398 #endif
399
400 if (hDevMode && lpDevMode)
401 GlobalUnlock(hDevMode);
402
403 return (WXHDC) hDC;
404 }
405
406 // ----------------------------------------------------------------------------
407 // wxPrinterDC bit blitting/bitmap drawing
408 // ----------------------------------------------------------------------------
409
410 void wxPrinterDC::DoDrawBitmap(const wxBitmap &bmp,
411 wxCoord x, wxCoord y,
412 bool useMask)
413 {
414 wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxPrinterDC::DrawBitmap") );
415
416 int width = bmp.GetWidth(),
417 height = bmp.GetHeight();
418
419 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
420 {
421 BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
422 memset( info, 0, sizeof( BITMAPINFOHEADER ) );
423
424 int iBitsSize = ((width + 3 ) & ~3 ) * height;
425
426 void* bits = malloc( iBitsSize );
427
428 info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
429 info->bmiHeader.biWidth = width;
430 info->bmiHeader.biHeight = height;
431 info->bmiHeader.biPlanes = 1;
432 info->bmiHeader.biBitCount = 8;
433 info->bmiHeader.biCompression = BI_RGB;
434
435 ScreenHDC display;
436 if ( GetDIBits(display, GetHbitmapOf(bmp), 0,
437 bmp.GetHeight(), bits, info,
438 DIB_RGB_COLORS) )
439 {
440 if ( ::StretchDIBits(GetHdc(), x, y,
441 width, height,
442 0 , 0, width, height,
443 bits, info,
444 DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR )
445 {
446 wxLogLastError("StretchDIBits");
447 }
448 }
449
450 free(bits);
451 free(info);
452 }
453 else // no support for StretchDIBits()
454 {
455 wxMemoryDC memDC;
456 memDC.SelectObject(bmp);
457
458 Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
459
460 memDC.SelectObject(wxNullBitmap);
461 }
462 }
463
464 bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest,
465 wxCoord width, wxCoord height,
466 wxDC *source,
467 wxCoord xsrc, wxCoord ysrc,
468 int rop, bool useMask)
469 {
470 bool success = TRUE;
471
472 if ( useMask )
473 {
474 // If we are printing source colours are screen colours
475 // not printer colours and so we need copy the bitmap
476 // pixel by pixel.
477 RECT rect;
478 HDC dc_src = GetHdcOf(*source);
479 HDC dc_mask = ::CreateCompatibleDC(dc_src);
480
481 ::SelectObject(dc_mask, (HBITMAP) source->GetSelectedBitmap().GetMask()->GetMaskBitmap());
482 for (int x = 0; x < width; x++)
483 {
484 for (int y = 0; y < height; y++)
485 {
486 COLORREF cref = ::GetPixel(dc_mask, x, y);
487 if (cref)
488 {
489 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
490 rect.left = xdest + x;
491 rect.right = rect.left + 1;
492 rect.top = ydest + y;
493 rect.bottom = rect.top + 1;
494 ::FillRect(GetHdc(), &rect, brush);
495 ::DeleteObject(brush);
496 }
497 }
498 }
499 ::SelectObject(dc_mask, 0);
500 ::DeleteDC(dc_mask);
501 }
502 else // no mask
503 {
504 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
505 {
506 wxBitmap& bmp = source->GetSelectedBitmap();
507 int width = bmp.GetWidth(),
508 height = bmp.GetHeight();
509
510 BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
511 int iBitsSize = ((width + 3 ) & ~3 ) * height;
512
513 void* bits = malloc( iBitsSize );
514
515 memset( info , 0 , sizeof( BITMAPINFOHEADER ) );
516
517 info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
518 info->bmiHeader.biWidth = width;
519 info->bmiHeader.biHeight = height;
520 info->bmiHeader.biPlanes = 1;
521 info->bmiHeader.biBitCount = 8;
522 info->bmiHeader.biCompression = BI_RGB;
523
524 ScreenHDC display;
525 if ( !::GetDIBits(display, GetHbitmapOf(bmp), 0,
526 height, bits, info, DIB_RGB_COLORS) )
527 {
528 wxLogLastError("GetDIBits");
529
530 success = FALSE;
531 }
532
533 if ( success )
534 {
535 success = ::StretchDIBits(GetHdc(), xdest, ydest,
536 width, height,
537 xsrc, ysrc,
538 width, height,
539 bits, info ,
540 DIB_RGB_COLORS,
541 SRCCOPY) != GDI_ERROR;
542 if ( !success )
543 {
544 wxLogLastError("StretchDIBits");
545 }
546 }
547
548 free(bits);
549 free(info);
550 }
551 else // no support for StretchDIBits
552 {
553 // as we are printing, source colours are screen colours not printer
554 // colours and so we need copy the bitmap pixel by pixel.
555 HDC dc_src = GetHdcOf(*source);
556 RECT rect;
557 for (int y = 0; y < height; y++)
558 {
559 // This is Stefan Csomor's optimisation, where identical adjacent
560 // pixels are drawn together.
561 for (int x = 0; x < width; x++)
562 {
563 COLORREF col = ::GetPixel(dc_src, x, y);
564 HBRUSH brush = ::CreateSolidBrush( col );
565
566 rect.left = xdest + x;
567 rect.top = ydest + y;
568 while( (x + 1 < width) && (::GetPixel(dc_src, x + 1, y) == col ) )
569 {
570 ++x;
571 }
572 rect.right = xdest + x + 1;
573 rect.bottom = rect.top + 1;
574 ::FillRect((HDC) m_hDC, &rect, brush);
575 ::DeleteObject(brush);
576 }
577 }
578 }
579 }
580
581 return success;
582 }