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

Last change on this file since 171 was 171, checked in by Eugene Romanenko, 14 years ago

to rediuce size of spool data: reduce number of colors when multiple pages printed as image

File size: 18.0 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#include "neuquant.h"
57
58
59#ifndef DEVESC_ERROR
60#define DEVESC_ERROR        (-1L)
61#endif
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
68void rgb_to_pal8( LuPixbuf *dst, LuPixbuf *src, int width, int height, BYTE *p_pal );
69
70
71class LucidePrinting
72{
73    public:
74        LucidePrinting( HWND hWndFrame, LuDocument *_doc,
75                        const char *_title, PrintSetup *_psetup );
76        ~LucidePrinting();
77        void doPrint();
78
79    private:
80        bool queryCurrentForm( HAB lhab, PHCINFO pcurForm );
81        void printPagePm( long page, HPS hpsPrinter, PHCINFO pcurForm, bool reduceColors );
82        bool doPmPrint( HAB lhab );
83        bool doPsPrint( HAB lhab );
84
85        HWND hFrame;
86        LuDocument *doc;
87        char *title;
88        PrintSetup *psetup;
89        boolean abortPrinting;
90        ProgressDlg *progressDlg;
91
92        static void printabort( void *data );
93        static void printthread( void *data );
94};
95
96
97void printDocument( HWND hWndFrame, LuDocument *doc, const char *title, PrintSetup *psetup )
98{
99    LucidePrinting *p = new LucidePrinting( hWndFrame, doc, title, psetup );
100    p->doPrint();
101}
102
103
104LucidePrinting::LucidePrinting( HWND hWndFrame, LuDocument *_doc,
105                                const char *_title, PrintSetup *_psetup )
106{
107    hFrame = hWndFrame;
108    doc    = _doc;
109    title  = newstrdup( _title );
110    psetup = new PrintSetup;
111    memcpy( psetup, _psetup, sizeof( PrintSetup ) );
112    abortPrinting = false;
113    progressDlg = new ProgressDlg( hWndFrame );
114}
115
116LucidePrinting::~LucidePrinting()
117{
118    delete title;
119    delete psetup;
120    delete progressDlg;
121}
122
123void LucidePrinting::doPrint()
124{
125    progressDlg->setBreakFunc( printabort, this );
126    progressDlg->setText( "" );
127    progressDlg->show( printthread, this );
128}
129
130bool LucidePrinting::doPmPrint( HAB lhab )
131{
132    CHAR         achDriverName[ DRIVERNAME_LENGTH ] = "";
133    CHAR         achQueueProcParams[ 8 ] = "";
134    DEVOPENSTRUC dos   = { 0 };
135    SIZEL        sizel = { 0 };
136
137    HCINFO curForm = { 0 };
138    if ( !queryCurrentForm( lhab, &curForm ) ) {
139        return false;
140    }
141
142    // build a devopenstruct for the call to DevOpenDC
143    dos.pszLogAddress      = psetup->QueueInfo.pszName;              // 1
144    strcpy( achDriverName, psetup->QueueInfo.pszDriverName );
145    achDriverName[ strcspn( achDriverName, "." ) ] = '\0';
146    dos.pszDriverName      = achDriverName;                          // 2
147    dos.pdriv              = psetup->QueueInfo.pDriverData;          // 3
148    dos.pszDataType        = "PM_Q_STD";                             // 4
149    dos.pszComment         = (PSZ)appName;                           // 5
150    dos.pszQueueProcName   = NULL;                                   // 6
151    snprintf( achQueueProcParams, sizeof( achQueueProcParams ), "COP=%d", psetup->copies );
152    dos.pszQueueProcParams = achQueueProcParams;                     // 7
153
154    HDC hdcPrinter = DevOpenDC( lhab, OD_QUEUED, "*", 7L, (PDEVOPENDATA)&dos, NULLHANDLE );
155    if ( hdcPrinter == DEV_ERROR ) {
156        return false;
157    }
158
159    // PS in HiMetric, 0.01 mm
160    HPS hpsPrinter = GpiCreatePS( lhab, hdcPrinter, &sizel, PU_HIMETRIC | GPIA_ASSOC );
161    if ( hpsPrinter == DEV_ERROR ) {
162        DevCloseDC( hdcPrinter );
163        return false;
164    }
165
166    // Issue STARTDOC to begin printing
167    DevEscape( hdcPrinter, DEVESC_STARTDOC, strlen(title), (PBYTE)title, NULL, NULL );
168
169
170    long totalpages = abs( psetup->pgto - psetup->pgfrom ) + 1;
171    long pg = psetup->pgfrom;
172    for ( long i = 0; i < totalpages; i++ )
173    {
174        char *fmt = newstrdupL( PRINT_PRINTING_PAGE_OF );
175        char *buf = new char[ 255 ];
176        snprintf( buf, 255, fmt, pg, i + 1, totalpages );
177        progressDlg->setText( buf );
178        delete fmt;
179        delete buf;
180
181        printPagePm( pg - 1, hpsPrinter, &curForm, ( totalpages > 1 ) );
182
183        if ( pg != psetup->pgto ) {
184            DevEscape( hdcPrinter, DEVESC_NEWFRAME, 0L, NULL, NULL, NULL );
185        }
186
187        if ( abortPrinting ) {
188            break;
189        }
190
191        pg += ( psetup->pgfrom <= psetup->pgto ) ? 1 : -1;
192    }
193
194    // Issue DEVESC_ENDDOC, or DEVESC_ABORTDOC if printing was aborted
195    DevEscape( hdcPrinter, abortPrinting ? DEVESC_ABORTDOC : DEVESC_ENDDOC,
196               0L, NULL, NULL, NULL );
197
198    // Release PS and DC
199    GpiAssociate( hpsPrinter, NULLHANDLE );
200    GpiDestroyPS( hpsPrinter );
201    DevCloseDC( hdcPrinter );
202    return true;
203}
204
205
206void LucidePrinting::printPagePm( long page, HPS hpsPrinter,
207                                  PHCINFO pcurForm, bool reduceColors )
208{
209    long bpp = doc->getBpp( ev );
210    double w = 0, h = 0;
211    doc->getPageSize( ev, page, &w, &h );
212
213    // Magrins
214    LONG mLeft   = __max( psetup->margin_left, pcurForm->xLeftClip );
215    LONG mBottom = __max( psetup->margin_bottom, pcurForm->yBottomClip );
216    LONG mRight  = __max( psetup->margin_right, pcurForm->cx - pcurForm->xRightClip );
217    LONG mTop    = __max( psetup->margin_top, pcurForm->cy - pcurForm->yTopClip );
218
219    // Count paper page size in hi-metric
220    LONG pwidth = ( pcurForm->cx - mLeft - mRight ) * UNITS_MULTIPLIER;
221    LONG pheight = ( pcurForm->cy - mTop - mBottom ) * UNITS_MULTIPLIER;
222
223    double zoom = 1.0;
224    if ( doc->isScalable( ev ) && !doc->isFixedImage( ev ) )
225    {
226        double maxcoeff = psetup->higherQuality ? HIGH_IMAGE_ZOOM : STD_IMAGE_ZOOM;
227        zoom = __min( (double)pwidth / w, (double)pheight / h );
228        if ( zoom > maxcoeff ) {
229            zoom = maxcoeff;
230        }
231    }
232
233    //somPrintf( "Doc pgsz: %g/%g  zoom: %g\n", w, h, zoom );
234    //somPrintf( "Paper %s, pgsz: %d/%d\n", pcurForm->szFormname, pcurForm->cx, pcurForm->cy );
235    //somPrintf( "pw/ph %d/%d\n", pwidth, pheight );
236
237    w *= zoom;
238    h *= zoom;
239    double pgzoom = __min( (double)pwidth / w, (double)pheight / h );
240
241    // Printed size
242    LONG prwidth = w * pgzoom;
243    LONG prheight = h * pgzoom;
244    LONG yPos = 0;
245    if ( prheight < pheight ) {
246        yPos = pheight - prheight;
247    }
248    RECTL rclDraw = { mLeft*UNITS_MULTIPLIER, (mBottom*UNITS_MULTIPLIER)+yPos,
249                      prwidth, prheight+yPos };
250
251    LONG rclx = w;
252    LONG rcly = h;
253
254    if ( doc->isRenderIntoPS( ev ) )
255    {
256        doc->renderPageToPS( ev, page, 0, 0, rclx, rcly, zoom, 0, hpsPrinter, &rclDraw,
257                             NULL, NULL );
258    }
259    else
260    {
261        LuPixbuf *pixbuf = new LuPixbuf( ev, rclx, rcly, bpp );
262        POINTL aptlPoints[4]={ rclDraw.xLeft, rclDraw.yBottom,
263                               rclDraw.xRight-1, rclDraw.yTop-1,
264                               0, 0, rclx, rcly };
265
266        doc->renderPageToPixbuf( ev, page, 0, 0, rclx, rcly, zoom, 0, pixbuf,
267                                 NULL, NULL );
268
269        LONG lRop = ROP_SRCCOPY;
270        if ( reduceColors )
271        {
272            LONG bhsz = sizeof( BITMAPINFOHEADER2 ) + ( sizeof( RGB2 ) * 256 );
273            BITMAPINFO2 *pbmi = (BITMAPINFO2 *)malloc( bhsz );
274            memset( pbmi, 0, bhsz );
275            pbmi->cbFix = sizeof( BITMAPINFOHEADER2 );
276            pbmi->cx = rclx;
277            pbmi->cy = rcly;
278            pbmi->cPlanes = 1;
279            pbmi->cBitCount = 8;
280            pbmi->ulCompression = BCA_UNCOMP;
281            pbmi->cbImage = 0;
282            pbmi->cxResolution = 0;
283            pbmi->cyResolution = 0;
284            pbmi->cclrUsed = 0;
285            pbmi->cclrImportant = 0;
286            pbmi->usUnits = BRU_METRIC;
287            pbmi->usReserved = 0;
288            pbmi->usRecording = BRA_BOTTOMUP;
289            pbmi->usRendering = BRH_NOTHALFTONED;
290            pbmi->cSize1 = 0;
291            pbmi->cSize2 = 0;
292            pbmi->ulColorEncoding = BCE_RGB;
293            pbmi->ulIdentifier = 0;
294
295            PBYTE pal = ((PBYTE)pbmi) + sizeof( BITMAPINFOHEADER2 );
296            LuPixbuf *p = new LuPixbuf( ev, rclx, rcly, 1 );
297
298            rgb_to_pal8( p, pixbuf, rclx, rcly, pal );
299
300            GpiDrawBits( hpsPrinter, p->getDataPtr( ev ), pbmi, 4L,
301                         aptlPoints, lRop, BBO_IGNORE );
302            delete p;
303            free( pbmi );
304        }
305        else
306        {
307            BITMAPINFO2 pbmi;
308            pbmi.cbFix = 16L;
309            pbmi.cx = rclx;
310            pbmi.cy = rcly;
311            pbmi.cPlanes = 1;
312            pbmi.cBitCount = bpp * 8;
313            GpiDrawBits( hpsPrinter, pixbuf->getDataPtr( ev ), &pbmi, 4L,
314                         aptlPoints, lRop, BBO_IGNORE );
315        }
316        delete pixbuf;
317    }
318}
319
320
321bool LucidePrinting::doPsPrint( HAB lhab )
322{
323    CHAR         achDriverName[ DRIVERNAME_LENGTH ] = "";
324    CHAR         achQueueProcParams[ 8 ] = "";
325    DEVOPENSTRUC dos   = { 0 };
326    SIZEL        sizel = { 0 };
327
328    HCINFO curForm = { 0 };
329    if ( !queryCurrentForm( lhab, &curForm ) ) {
330        return false;
331    }
332
333    char *generating_ps = newstrdupL( PRINT_GENERATING_POSTSCRIPT );
334    progressDlg->setText( generating_ps );
335    delete generating_ps;
336
337    // Magrins
338    LONG mLeft   = __max( psetup->margin_left, curForm.xLeftClip );
339    LONG mBottom = __max( psetup->margin_bottom, curForm.yBottomClip );
340    LONG mRight  = __max( psetup->margin_right, curForm.cx - curForm.xRightClip );
341    LONG mTop    = __max( psetup->margin_top, curForm.cy - curForm.yTopClip );
342
343    // Count paper page size in 1/72 inches
344    double pwidth = ( (double)( curForm.cx - mLeft - mRight ) / 25.4 ) * 72.0;
345    double pheight = ( (double)( curForm.cy - mTop - mBottom ) / 25.4 ) * 72.0;
346
347    char tmpps[ CCHMAXPATH ] = "";
348    if ( psetup->psToFile ) {
349        strcpy( tmpps, psetup->psFile );
350    }
351    else {
352        getTmpDir( tmpps );
353        strcat( tmpps, "TMPLUCID.PS" );
354    }
355
356    boolean rcexp = doc->exportToPostScript( ev, tmpps, psetup->pgfrom-1, psetup->pgto-1,
357                                             pwidth, pheight, &abortPrinting );
358
359    if ( abortPrinting ) {
360        unlink( tmpps );
361        return true;
362    }
363    if ( !rcexp ) {
364        unlink( tmpps );
365        return false;
366    }
367
368    if ( !psetup->psToFile )
369    {
370        char *spooling_ps = newstrdupL( PRINT_SPOOLING_POSTSCRIPT );
371        progressDlg->setText( spooling_ps );
372        delete spooling_ps;
373
374        // build a devopenstruct for the call to DevOpenDC
375        dos.pszLogAddress      = psetup->QueueInfo.pszName;              // 1
376        strcpy( achDriverName, psetup->QueueInfo.pszDriverName );
377        achDriverName[ strcspn( achDriverName, "." ) ] = '\0';
378        dos.pszDriverName      = achDriverName;                          // 2
379        dos.pdriv              = psetup->QueueInfo.pDriverData;          // 3
380        dos.pszDataType        = "PM_Q_RAW";                             // 4
381        dos.pszComment         = (PSZ)appName;                           // 5
382        dos.pszQueueProcName   = NULL;                                   // 6
383        snprintf( achQueueProcParams, sizeof( achQueueProcParams ), "COP=%d", psetup->copies );
384        dos.pszQueueProcParams = achQueueProcParams;                     // 7
385
386        HDC hdcPrinter = DevOpenDC( lhab, OD_QUEUED, "*", 7L, (PDEVOPENDATA)&dos, NULLHANDLE );
387        if ( hdcPrinter == DEV_ERROR ) {
388            unlink( tmpps );
389            return false;
390        }
391
392        // Issue STARTDOC to begin printing
393        LONG rc = DevEscape( hdcPrinter, DEVESC_STARTDOC, strlen(title), (PBYTE)title, NULL, NULL );
394        if ( rc == DEVESC_ERROR ) {
395            DevCloseDC( hdcPrinter );
396            unlink( tmpps );
397            return false;
398        }
399
400        FILE *f = fopen( tmpps, "rb" );
401        if ( f == NULL ) {
402            DevEscape( hdcPrinter, DEVESC_ABORTDOC, 0L, NULL, NULL, NULL );
403            DevCloseDC( hdcPrinter );
404            unlink( tmpps );
405            return false;
406        }
407
408        bool splerr = false;
409        void *buf = malloc( PS_PRINT_BUF_SIZE );
410        int rd = 0;
411        while ( ( rc != DEVESC_ERROR ) && ( rd = fread( buf, 1, PS_PRINT_BUF_SIZE, f ) ) != 0 )
412        {
413            rc = DevEscape( hdcPrinter, DEVESC_RAWDATA, rd, (char *)buf, NULL, NULL );
414            if ( ( rc == DEVESC_ERROR ) || abortPrinting ) {
415                splerr = true;
416                break;
417            }
418        }
419        free( buf );
420        fclose( f );
421        unlink( tmpps );
422
423        DevEscape( hdcPrinter, splerr ? DEVESC_ABORTDOC : DEVESC_ENDDOC,
424                   0L, NULL, NULL, NULL );
425        DevCloseDC( hdcPrinter );
426
427        if ( splerr && !abortPrinting ) {
428            return false;
429        }
430    }
431
432    return true;
433}
434
435
436bool LucidePrinting::queryCurrentForm( HAB lhab, PHCINFO pcurForm )
437{
438    CHAR         achDriverName[ DRIVERNAME_LENGTH ] = "";
439    DEVOPENSTRUC dos   = { 0 };
440    // build a devopenstruct for the call to DevOpenDC
441    dos.pszLogAddress = psetup->QueueInfo.pszName;              // 1
442    strcpy( achDriverName, psetup->QueueInfo.pszDriverName );
443    achDriverName[ strcspn( achDriverName, "." ) ] = '\0';
444    dos.pszDriverName = achDriverName;                          // 2
445    dos.pdriv = psetup->QueueInfo.pDriverData;                  // 3
446
447    HDC hdcPrinterInfo = DevOpenDC( lhab, OD_INFO, "*", 3L, (PDEVOPENDATA)&dos, NULLHANDLE );
448    if ( hdcPrinterInfo == DEV_ERROR ) {
449        return false;
450    }
451
452    LONG lForms = DevQueryHardcopyCaps( hdcPrinterInfo, 0, 0, NULL );
453    if ( lForms == DQHC_ERROR ) {
454        DevCloseDC( hdcPrinterInfo );
455        return false;
456    }
457
458    HCINFO *forms = new HCINFO[ lForms ];
459    memset( forms, 0, sizeof( HCINFO ) * lForms );
460    lForms = DevQueryHardcopyCaps( hdcPrinterInfo, 0, lForms, forms );
461    if ( lForms == DQHC_ERROR ) {
462        delete forms;
463        DevCloseDC( hdcPrinterInfo );
464        return false;
465    }
466
467    for ( LONG i = 0; i < lForms; i++ ) {
468        if ( forms[i].flAttributes & HCAPS_CURRENT ) {
469            memcpy( pcurForm, &( forms[i] ), sizeof( HCINFO ) );
470            break;
471        }
472    }
473
474    delete forms;
475    DevCloseDC( hdcPrinterInfo );
476    return true;
477}
478
479// static method
480void LucidePrinting::printabort( void *data )
481{
482    ((LucidePrinting *)data)->abortPrinting = true;
483}
484
485// static method, thread for asynchronous printing
486void LucidePrinting::printthread( void *p )
487{
488    DosSetPriority( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MAXIMUM, 0 );
489    LucidePrinting *_this = (LucidePrinting *)p;
490
491    HAB thab = WinInitialize( 0 );
492    HMQ thmq = WinCreateMsgQueue( thab, 0 );
493
494    bool printOk = false;
495    if ( _this->psetup->ptype == TypePostScript ) {
496        printOk = _this->doPsPrint( thab );
497    }
498    else {
499        printOk = _this->doPmPrint( thab );
500    }
501    _this->progressDlg->hide();
502
503    if ( !printOk )
504    {
505        char *printfailed = newstrdupL( PRINT_FAILED );
506        WinMessageBox( HWND_DESKTOP, _this->hFrame, printfailed, NULL,
507                       1, MB_OK | MB_ERROR | MB_MOVEABLE );
508        delete printfailed;
509    }
510
511    WinDestroyMsgQueue( thmq );
512    WinTerminate( thab );
513    _endthread();
514
515    delete _this;
516}
517
518
519// Convert RGB 24/32 bit pixbuf into 8 bit palettized
520static void rgb_to_pal8( LuPixbuf *dst, LuPixbuf *src, int width, int height, BYTE *p_pal )
521{
522    NeuQuantizer *nq = new NeuQuantizer( src, 256 );
523
524    nq->initnet();
525    nq->learn( 10 );
526    nq->unbiasnet();
527
528    int *palette = (int *)nq->getNetwork();
529    for ( int i = 0; i < ( 256 * 4 ); i++ ) {
530        p_pal[ i ] = palette[ i ];
531    }
532    nq->inxbuild();
533
534    unsigned char *p_src = (unsigned char *)src->getDataPtr( ev );
535    unsigned char *p_dst = (unsigned char *)dst->getDataPtr( ev );
536    long rowsize_src = src->getRowSize( ev );
537    long rowsize_dst = dst->getRowSize( ev );
538    long x = src->getWidth( ev );
539    long y = src->getHeight( ev );
540    long bpp = src->getBpp( ev );
541
542    for ( long py = 0; py < y; py++ )
543    {
544        BYTE *row_src = p_src + ( rowsize_src * py );
545        long row_dst = rowsize_dst * py;
546        for ( long px = 0; px < x; px++ )
547        {
548            BYTE *pix = row_src + ( px * bpp );
549            p_dst[ row_dst + px ] = nq->inxsearch( pix[0], pix[1], pix[2] );
550        }
551    }
552
553    delete nq;
554}
555
Note: See TracBrowser for help on using the repository browser.