source: trunk/Lucide/SOURCE/gui/print.cpp @ 91

Last change on this file since 91 was 91, checked in by Eugene Romanenko, 15 years ago

bitmap printing, preliminary postscript printing, export to PS for djvu plugin, other improvements

File size: 13.9 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * Version: CDDL 1.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the COMMON DEVELOPMENT AND
5 * DISTRIBUTION LICENSE (CDDL) Version 1.0 (the "License"); you may not use
6 * this file except in compliance with the License. You may obtain a copy of
7 * the License at http://www.sun.com/cddl/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Initial Developer of the Original Code is
15 * Eugene Romanenko, netlabs.org.
16 * Portions created by the Initial Developer are Copyright (C) 2006
17 * the Initial Developer. All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the terms of
22 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23 * in which case the provisions of the LGPL are applicable instead of those
24 * above. If you wish to allow use of your version of this file only under the
25 * terms of the LGPL, and not to allow others to use your version of this file
26 * under the terms of the CDDL, indicate your decision by deleting the
27 * provisions above and replace them with the notice and other provisions
28 * required by the LGPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under the terms of any one of the CDDL
30 * or the LGPL.
31 *
32 * ***** END LICENSE BLOCK ***** */
33
34
35#define INCL_WIN
36#define INCL_GPI
37#define INCL_DOS
38#define INCL_DEV
39#define INCL_ERRORS
40#define INCL_SPL
41#define INCL_SPLDOSPRINT
42#include <os2.h>
43
44#include <ludoc.xh>
45
46#include <string.h>
47#include <process.h>
48#include <stdio.h>
49#include <io.h>
50
51#include "globals.h"
52#include "progressDlg.h"
53#include "print.h"
54#include "luutils.h"
55#include "messages.h"
56
57// OpenWatcom headers doesn't have GpiDrawBits() declaration
58extern "C" {
59    LONG APIENTRY GpiDrawBits(HPS hps, PVOID pBits, PBITMAPINFO2 pbmiInfoTable,
60                              LONG lCount, PPOINTL aptlPoints, LONG lRop, ULONG flOptions);
61}
62
63#define UNITS_MULTIPLIER    100
64#define STD_IMAGE_ZOOM      2.0
65#define HIGH_IMAGE_ZOOM     3.0
66#define PS_PRINT_BUF_SIZE   32768
67#define TEST_MARGIN         10
68
69
70class LucidePrinting
71{
72    public:
73        LucidePrinting( HWND hWndFrame, LuDocument *_doc,
74                        const char *_title, PrintSetup *_psetup );
75        ~LucidePrinting();
76        void doPrint();
77
78    private:
79        bool queryCurrentForm( HAB lhab, PHCINFO pcurForm );
80        void printPagePm( long page, HPS hpsPrinter, PHCINFO pcurForm );
81        bool doPmPrint( HAB lhab );
82        bool doPsPrint( HAB lhab );
83
84        HWND hFrame;
85        LuDocument *doc;
86        char *title;
87        PrintSetup *psetup;
88        bool abortPrinting;
89        ProgressDlg *progressDlg;
90
91        static void printabort( void *data );
92        static void printthread( void *data );
93};
94
95
96void printDocument( HWND hWndFrame, LuDocument *doc, const char *title, PrintSetup *psetup )
97{
98    LucidePrinting *p = new LucidePrinting( hWndFrame, doc, title, psetup );
99    p->doPrint();
100}
101
102
103LucidePrinting::LucidePrinting( HWND hWndFrame, LuDocument *_doc,
104                                const char *_title, PrintSetup *_psetup )
105{
106    hFrame = hWndFrame;
107    doc    = _doc;
108    title  = newstrdup( _title );
109    psetup = new PrintSetup;
110    memcpy( psetup, _psetup, sizeof( PrintSetup ) );
111    abortPrinting = false;
112    progressDlg = new ProgressDlg( hWndFrame );
113}
114
115LucidePrinting::~LucidePrinting()
116{
117    delete title;
118    delete psetup;
119    delete progressDlg;
120}
121
122void LucidePrinting::doPrint()
123{
124    progressDlg->setBreakFunc( printabort, this );
125    progressDlg->setText( "" );
126    progressDlg->show( printthread, this );
127}
128
129bool LucidePrinting::doPmPrint( HAB lhab )
130{
131    CHAR         achDriverName[ DRIVERNAME_LENGTH ] = "";
132    DEVOPENSTRUC dos   = { 0 };
133    SIZEL        sizel = { 0 };
134
135    HCINFO curForm = { 0 };
136    if ( !queryCurrentForm( lhab, &curForm ) ) {
137        return false;
138    }
139
140    // build a devopenstruct for the call to DevOpenDC
141    dos.pszLogAddress = psetup->QueueInfo.pszName;              // 1
142    strcpy( achDriverName, psetup->QueueInfo.pszDriverName );
143    achDriverName[ strcspn( achDriverName, "." ) ] = '\0';
144    dos.pszDriverName = achDriverName;                          // 2
145    dos.pdriv         = psetup->QueueInfo.pDriverData;          // 3
146    dos.pszDataType   = "PM_Q_STD";                             // 4
147
148    HDC hdcPrinter = DevOpenDC( lhab, OD_QUEUED, "*", 4L, (PDEVOPENDATA)&dos, NULLHANDLE );
149    if ( hdcPrinter == DEV_ERROR ) {
150        return false;
151    }
152
153    // PS in HiMetric, 0.01 mm
154    HPS hpsPrinter = GpiCreatePS( lhab, hdcPrinter, &sizel, PU_HIMETRIC | GPIA_ASSOC );
155    if ( hpsPrinter == DEV_ERROR ) {
156        DevCloseDC( hdcPrinter );
157        return false;
158    }
159
160    // Issue STARTDOC to begin printing
161    DevEscape( hdcPrinter, DEVESC_STARTDOC, strlen(title), (PBYTE)title, NULL, NULL );
162
163    long totalpages = psetup->pgto - psetup->pgfrom + 1;
164    for ( long pg = psetup->pgfrom; pg <= psetup->pgto; pg++ )
165    {
166        char *fmt = newstrdupL( PRINT_PRINTING_PAGE_OF );
167        char *buf = new char[ 255 ];
168        snprintf( buf, 255, fmt, pg, totalpages );
169        progressDlg->setText( buf );
170        delete fmt;
171        delete buf;
172
173        printPagePm( pg - 1, hpsPrinter, &curForm );
174
175        if ( pg != psetup->pgto ) {
176            DevEscape( hdcPrinter, DEVESC_NEWFRAME, 0L, NULL, NULL, NULL );
177        }
178
179        if ( abortPrinting ) {
180            break;
181        }
182    }
183
184    // Issue DEVESC_ENDDOC, or DEVESC_ABORTDOC if printing was aborted
185    DevEscape( hdcPrinter, abortPrinting ? DEVESC_ABORTDOC : DEVESC_ENDDOC,
186               0L, NULL, NULL, NULL );
187
188    // Release PS and DC
189    GpiAssociate( hpsPrinter, NULLHANDLE );
190    GpiDestroyPS( hpsPrinter );
191    DevCloseDC( hdcPrinter );
192    return true;
193}
194
195
196void LucidePrinting::printPagePm( long page, HPS hpsPrinter, PHCINFO pcurForm )
197{
198    long bpp = doc->getBpp( ev );
199    double w = 0, h = 0;
200    doc->getPageSize( ev, page, &w, &h );
201
202    // Magrins
203    LONG mLeft   = __max( TEST_MARGIN, pcurForm->xLeftClip );
204    LONG mBottom = __max( TEST_MARGIN, pcurForm->yBottomClip );
205    LONG mRight  = __max( TEST_MARGIN, pcurForm->cx - pcurForm->xRightClip );
206    LONG mTop    = __max( TEST_MARGIN, pcurForm->cy - pcurForm->yTopClip );
207
208    // Count paper page size in hi-metric
209    LONG pwidth = ( pcurForm->cx - mLeft - mRight ) * UNITS_MULTIPLIER;
210    LONG pheight = ( pcurForm->cy - mTop - mBottom ) * UNITS_MULTIPLIER;
211
212    double zoom = 1.0;
213    if ( doc->isScalable( ev ) )
214    {
215        double maxcoeff = psetup->higherQuality ? HIGH_IMAGE_ZOOM : STD_IMAGE_ZOOM;
216        zoom = __min( (double)pwidth / w, (double)pheight / h );
217        if ( zoom > maxcoeff ) {
218            zoom = maxcoeff;
219        }
220    }
221
222    //somPrintf( "Doc pgsz: %g/%g  zoom: %g\n", w, h, zoom );
223    //somPrintf( "Paper %s, pgsz: %d/%d\n", pcurForm->szFormname, pcurForm->cx, pcurForm->cy );
224    //somPrintf( "pw/ph %d/%d\n", pwidth, pheight );
225
226    w *= zoom;
227    h *= zoom;
228    double pgzoom = __min( (double)pwidth / w, (double)pheight / h );
229
230    // Printed size
231    LONG prwidth = w * pgzoom;
232    LONG prheight = h * pgzoom;
233    LONG yPos = 0;
234    if ( prheight < pheight ) {
235        yPos = pheight - prheight;
236    }
237    RECTL rclDraw = { mLeft*UNITS_MULTIPLIER, (mBottom*UNITS_MULTIPLIER)+yPos,
238                      prwidth, prheight+yPos };
239
240    LONG rclx = w;
241    LONG rcly = h;
242    if ( doc->isRenderIntoPS( ev ) )
243    {
244        doc->renderPageToPS( ev, page, 0, 0, rclx, rcly, zoom, 0, hpsPrinter, &rclDraw );
245    }
246    else
247    {
248        LuPixbuf *pixbuf = new LuPixbuf( ev, rclx, rcly, bpp );
249        POINTL aptlPoints[4]={ rclDraw.xLeft, rclDraw.yBottom,
250                               rclDraw.xRight-1, rclDraw.yTop-1,
251                               0, 0, rclx, rcly };
252
253        doc->renderPageToPixbuf( ev, page, 0, 0, rclx, rcly, zoom, 0, pixbuf );
254
255        LONG lRop = ROP_SRCCOPY;
256        BITMAPINFO2 pbmi;
257        pbmi.cbFix = 16L;
258        pbmi.cx = rclx;
259        pbmi.cy = rcly;
260        pbmi.cPlanes = 1;
261        pbmi.cBitCount = bpp * 8;
262        GpiDrawBits( hpsPrinter, pixbuf->getDataPtr( ev ), &pbmi, 4L,
263                     aptlPoints, lRop, BBO_IGNORE );
264        delete pixbuf;
265    }
266}
267
268
269
270bool LucidePrinting::doPsPrint( HAB lhab )
271{
272    CHAR         achDriverName[ DRIVERNAME_LENGTH ] = "";
273    DEVOPENSTRUC dos   = { 0 };
274    SIZEL        sizel = { 0 };
275
276    HCINFO curForm = { 0 };
277    if ( !queryCurrentForm( lhab, &curForm ) ) {
278        return false;
279    }
280
281    char *generating_ps = newstrdupL( PRINT_GENERATING_POSTSCRIPT );
282    progressDlg->setText( generating_ps );
283    delete generating_ps;
284
285    // Magrins
286    LONG mLeft   = __max( TEST_MARGIN, curForm.xLeftClip );
287    LONG mBottom = __max( TEST_MARGIN, curForm.yBottomClip );
288    LONG mRight  = __max( TEST_MARGIN, curForm.cx - curForm.xRightClip );
289    LONG mTop    = __max( TEST_MARGIN, curForm.cy - curForm.yTopClip );
290
291    // Count paper page size in 1/72 inches
292    double pwidth = ( (double)( curForm.cx - mLeft - mRight ) / 25.4 ) * 72.0;
293    double pheight = ( (double)( curForm.cy - mTop - mBottom ) / 25.4 ) * 72.0;
294
295    char *tmpps = "TMPLUCID.PS";
296    BOOL rc = doc->exportToPostScript( ev, tmpps, psetup->pgfrom-1, psetup->pgto-1,
297                                       pwidth, pheight, false );
298    if ( !rc ) {
299        unlink( tmpps );
300        return false;
301    }
302    if ( abortPrinting ) {
303        unlink( tmpps );
304        return true;
305    }
306
307    char *spooling_ps = newstrdupL( PRINT_SPOOLING_POSTSCRIPT );
308    progressDlg->setText( spooling_ps );
309    delete spooling_ps;
310
311    // build a devopenstruct for the call to SplQmOpen
312    dos.pszLogAddress = psetup->QueueInfo.pszName;              // 1
313    strcpy( achDriverName, psetup->QueueInfo.pszDriverName );
314    achDriverName[ strcspn( achDriverName, "." ) ] = '\0';
315    dos.pszDriverName = achDriverName;                          // 2
316    dos.pdriv         = psetup->QueueInfo.pDriverData;          // 3
317    dos.pszDataType   = "PM_Q_RAW";                             // 4
318
319    HSPL hspl = SplQmOpen( "*", 4L, (PQMOPENDATA)&dos );
320    if ( hspl == SPL_ERROR ) {
321        unlink( tmpps );
322        return false;
323    }
324
325    rc = SplQmStartDoc( hspl, title );
326    if ( !rc ) {
327        SplQmAbort( hspl );
328        unlink( tmpps );
329        return false;
330    }
331
332    FILE *f = fopen( tmpps, "rb" );
333    if ( f == NULL ) {
334        SplQmAbort( hspl );
335        unlink( tmpps );
336        return false;
337    }
338
339    bool splerr = false;
340    void *buf = malloc( PS_PRINT_BUF_SIZE );
341    int rd = 0;
342    while ( rc && ( rd = fread( buf, 1, PS_PRINT_BUF_SIZE, f ) ) != 0 ) {
343        rc = SplQmWrite( hspl, rd, buf );
344        if ( !rc || abortPrinting ) {
345            splerr = true;
346            break;
347        }
348    }
349    free( buf );
350    fclose( f );
351    unlink( tmpps );
352
353    if ( splerr ) {
354        SplQmAbort( hspl );
355        if ( !abortPrinting ) {
356            return false;
357        }
358    }
359    else {
360        SplQmEndDoc( hspl );
361        SplQmClose( hspl );
362    }
363
364    return true;
365}
366
367bool LucidePrinting::queryCurrentForm( HAB lhab, PHCINFO pcurForm )
368{
369    CHAR         achDriverName[ DRIVERNAME_LENGTH ] = "";
370    DEVOPENSTRUC dos   = { 0 };
371    // build a devopenstruct for the call to DevOpenDC
372    dos.pszLogAddress = psetup->QueueInfo.pszName;              // 1
373    strcpy( achDriverName, psetup->QueueInfo.pszDriverName );
374    achDriverName[ strcspn( achDriverName, "." ) ] = '\0';
375    dos.pszDriverName = achDriverName;                          // 2
376    dos.pdriv = psetup->QueueInfo.pDriverData;                  // 3
377
378    HDC hdcPrinterInfo = DevOpenDC( lhab, OD_INFO, "*", 3L, (PDEVOPENDATA)&dos, NULLHANDLE );
379    if ( hdcPrinterInfo == DEV_ERROR ) {
380        return false;
381    }
382
383    //long lTech = 0;
384    //DevQueryCaps( hdcPrinterInfo, CAPS_TECHNOLOGY, sizeof(long), &lTech );
385    //somPrintf( "lTech: 0x%x\n", lTech );
386
387    LONG lForms = DevQueryHardcopyCaps( hdcPrinterInfo, 0, 0, NULL );
388    if ( lForms == DQHC_ERROR ) {
389        DevCloseDC( hdcPrinterInfo );
390        return false;
391    }
392
393    HCINFO *forms = new HCINFO[ lForms ];
394    memset( forms, 0, sizeof( HCINFO ) * lForms );
395    lForms = DevQueryHardcopyCaps( hdcPrinterInfo, 0, lForms, forms );
396    if ( lForms == DQHC_ERROR ) {
397        delete forms;
398        DevCloseDC( hdcPrinterInfo );
399        return false;
400    }
401
402    for ( LONG i = 0; i < lForms; i++ ) {
403        if ( forms[i].flAttributes & HCAPS_CURRENT ) {
404            memcpy( pcurForm, &( forms[i] ), sizeof( HCINFO ) );
405            break;
406        }
407    }
408
409    delete forms;
410    DevCloseDC( hdcPrinterInfo );
411    return true;
412}
413
414// static method
415void LucidePrinting::printabort( void *data )
416{
417    ((LucidePrinting *)data)->abortPrinting = true;
418}
419
420// static method, thread for asynchronous printing
421void LucidePrinting::printthread( void *p )
422{
423    DosSetPriority( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MAXIMUM, 0 );
424    LucidePrinting *_this = (LucidePrinting *)p;
425
426    HAB thab = WinInitialize( 0 );
427    HMQ thmq = WinCreateMsgQueue( thab, 0 );
428
429    bool printOk = false;
430    if ( _this->psetup->ptype == TypePostScript ) {
431        printOk = _this->doPsPrint( thab );
432    }
433    else {
434        printOk = _this->doPmPrint( thab );
435    }
436    _this->progressDlg->hide();
437
438    if ( !printOk )
439    {
440        char *printfailed = newstrdupL( PRINT_FAILED );
441        WinMessageBox( HWND_DESKTOP, _this->hFrame, printfailed, NULL,
442                       1, MB_OK | MB_ERROR | MB_MOVEABLE );
443        delete printfailed;
444    }
445
446    WinDestroyMsgQueue( thmq );
447    WinTerminate( thab );
448    _endthread();
449
450    delete _this;
451}
452
Note: See TracBrowser for help on using the repository browser.