libxml2: copy the xml2-config to the crosstoolsdir and patch the paths in the native...
[AROS-Contrib.git] / vpdf / poppler_printer.cpp
blob1f6c740074c944f384c158ae6d65d767fb4aafb2
2 #include "Object.h"
4 #if defined(__MORPHOS__)
5 #include <proto/charsets.h>
6 #endif
7 #define AROS_ALMOST_COMPATIBLE
8 #define _NO_PPCINLINE
9 #include <proto/keymap.h>
10 #include <proto/exec.h>
11 #include <proto/dos.h>
12 #include <proto/graphics.h>
13 #include <proto/iffparse.h>
14 #include <dos/stdio.h>
15 #if defined(__AROS__)
16 #include <aros/debug.h>
17 #define KPrintF kprintf
18 #else
19 #include <clib/debug_protos.h>
20 #endif
21 #include <exec/semaphores.h>
22 #include <exec/lists.h>
23 #include <prefs/prefhdr.h>
24 #include <constructor.h>
25 #include <prefs/printertxt.h>
27 #define USE_FLOAT 1
28 #include <poppler-config.h>
29 #include <config.h>
31 #include <stddef.h>
32 #include <stdlib.h>
33 #include <memory.h>
34 #include <math.h>
35 #include <time.h>
37 #include "PDFDoc.h"
38 #include "Outline.h"
39 #include "Link.h"
40 #include "GlobalParams.h"
41 #include "PDFDocEncoding.h"
42 #include "goo/GooList.h"
44 //#define USE_SPLASH
45 #ifdef USE_SPLASH
46 #include "splash/SplashBitmap.h"
47 #include "splash/Splash.h"
48 #include "SplashOutputDev.h"
49 #include "TextOutputDev.h"
50 #else
51 #include "CairoOutputDev.h"
52 #endif
53 #include "PSOutputDev.h"
55 #include "poppler.h"
56 #include "poppler_io.h"
57 #include "poppler_device.h"
58 #include "poppler_printer.h"
60 extern struct Library *LocaleBase;
61 #define LOCALE_BASE_NAME LocaleBase
62 #warning TODO: make the semaphore per-document
63 extern struct SignalSemaphore semaphore;
65 extern struct Library *CairoBase;
68 // turboprint includes
69 #include <devices/printer.h>
70 #include <devices/prtbase.h>
71 #include <datatypes/datatypesclass.h>
72 #include "turboprint.h"
74 #if 1
75 #define ENTER_SECTION \
76 { ObtainSemaphore(&semaphore);}
77 #else // time delay needed to enter critical section
78 #define ENTER_SECTION \
79 { clock_t t0 = clock(); ObtainSemaphore(&semaphore); t0 = clock() - t0; kprintf("section enter:%f:%s\n", (float)t0/CLOCKS_PER_SEC, __FUNCTION__);}
80 #endif
82 //#define ENTER_SECTION
83 #define LEAVE_SECTION ReleaseSemaphore(&semaphore);
84 //#define LEAVE_SECTION
86 #define OUTPUTBUFFERSIZE 262144
88 typedef struct
90 int w;
91 int h;
92 } PAGE_SIZES;
94 static const PAGE_SIZES page_sizes[]= {
95 {1,1 }, //PS_US_LETTER
96 {1,1 }, //PS_US_LEGAL
97 {1,1}, //PS_N_TRACTOR
98 {1,1 }, //PS_W_TRACTOR
99 {1,1 }, //PS_CUSTOM
100 {841,1189}, //PS_EURO_A0
101 {594,841 }, //PS_EURO_A1
102 {420,594}, //PS_EURO_A2
103 {297,420}, //PS_EURO_A3
104 {210,297 }, //PS_EURO_A4
105 {148,210 }, //PS_EURO_A5
106 {1,1, }, //PS_EURO_A6
107 {1,1}, //PS_EURO_A7
108 {1,1 }, //PS_EURO_A8
111 int get_pagesize()
113 struct IFFHandle *iffhandle;
114 struct StoredProperty *sp;
115 int ifferror;
116 struct PrinterTxtPrefs tmp;
117 int ret = -1;
119 if (iffhandle = AllocIFF())
121 if (iffhandle->iff_Stream = (LONG)Open("env:sys/printer.prefs", MODE_OLDFILE))
123 D(kprintf("prefs file opened\n"));
124 InitIFFasDOS (iffhandle);
125 if ((ifferror = OpenIFF (iffhandle, IFFF_READ)) == 0)
127 D(kprintf("iff opened\n"));
128 PropChunk(iffhandle, ID_PREF, ID_PTXT);
130 for (;;)
132 ifferror = ParseIFF(iffhandle, IFFPARSE_STEP);
134 if (ifferror == IFFERR_EOC)
135 continue;
136 else if (ifferror)
137 break;
140 if (sp = FindProp(iffhandle, ID_PREF, ID_PTXT))
142 ret = ((struct PrinterTxtPrefs *)sp->sp_Data)->pt_PaperSize;
145 CloseIFF(iffhandle);
148 Close ((BPTR)iffhandle->iff_Stream);
150 FreeIFF(iffhandle);
152 return ret;
156 struct printercontext
158 ULONG format;
159 PDFDoc *doc;
161 PSOutputDev *dev;
162 BPTR file;
164 cairo_surface_t *surface;
165 cairo_t *cairo;
166 CairoOutputDev *cairo_dev;
167 struct MsgPort *PrinterMP;
168 union printerIO *PIO;
169 struct PrinterData *PD;
170 struct TPExtIODRP ExtIoDrp;
171 BOOL TP_Installed;
172 UWORD TPVersion;
173 int last_page;
174 int page_size;
175 char buffer[OUTPUTBUFFERSIZE];
179 static void outputstreamfunc(void *stream, const char *data, int len)
181 struct printercontext *pctx = (struct printercontext*)stream;
182 FWrite(pctx->file, (void*)data, (LONG)len, 1);
185 struct printercontext *init_turboprint(struct printercontext *pctx)
187 pctx->PrinterMP = NULL;
188 pctx->PIO = NULL;
190 D(kprintf("init_turboprint() started\n!"));
191 if((pctx->PrinterMP = (struct MsgPort*)CreateMsgPort()))
193 if((pctx->PIO = (union printerIO *)CreateIORequest(pctx->PrinterMP, sizeof(union printerIO))))
195 if(!(OpenDevice((STRPTR)"printer.device", 0, (struct IORequest *)pctx->PIO, 0)))
197 pctx->PD = (struct PrinterData *)pctx->PIO->iodrp.io_Device;
198 pctx->TP_Installed = (((ULONG *)(pctx->PD->pd_OldStk))[2] == TPMATCHWORD);
200 pctx->TPVersion = pctx->PIO->iodrp.io_Device->dd_Library.lib_Version;
201 // pctx->TPIdString = (char*)(pctx->PIO->iodrp.io_Device->dd_Library.lib_IdString);
203 if(pctx->TP_Installed && pctx->TPVersion >= 39)
205 struct PrinterData *PD = pctx->PD;
207 D(kprintf("PrinterName = '%s', Version=%u, Revision=%u\n",
208 PD->pd_SegmentData->ps_PED.ped_PrinterName, PD->pd_SegmentData->ps_Version,
209 PD->pd_SegmentData->ps_Revision));
210 D(kprintf("PrinterClass=%u, ColorClass=%u\n",
211 PD->pd_SegmentData->ps_PED.ped_PrinterClass, PD->pd_SegmentData->ps_PED.ped_ColorClass));
212 D(kprintf("MaxColumns=%u, NumCharSets=%u, NumRows=%u\n",
213 PD->pd_SegmentData->ps_PED.ped_MaxColumns, PD->pd_SegmentData->ps_PED.ped_NumCharSets, PD->pd_SegmentData->ps_PED.ped_NumRows));
214 D(kprintf("MaxXDots=%lu, MaxYDots=%lu, XDotsInch=%u, YDotsInch=%u\n",
215 PD->pd_SegmentData->ps_PED.ped_MaxXDots, PD->pd_SegmentData->ps_PED.ped_MaxYDots,
216 PD->pd_SegmentData->ps_PED.ped_XDotsInch, PD->pd_SegmentData->ps_PED.ped_YDotsInch));
217 D(kprintf("PrintLeftMargin=%d, PrintRightMargin=%d\n",
218 pctx->PD->pd_Preferences.PrintLeftMargin,pctx->PD->pd_Preferences.PrintRightMargin));
220 D(kprintf("PrintAspect: %d\n", PD->pd_Preferences.PrintAspect));
222 pctx->PIO->iodrp.io_Command = PRD_TPEXTDUMPRPORT;
223 pctx->PIO->iodrp.io_SrcX = 0; // x offset in rastport to start printing from
224 pctx->PIO->iodrp.io_SrcY = 0; // y offset in rastpoty to start printing from
226 // new: io.Modes must point to a new Structure (ExtIoDrp)
227 pctx->PIO->iodrp.io_Modes = (ULONG)&pctx->ExtIoDrp;
229 // fill in the new structure
230 pctx->ExtIoDrp.PixAspX = 1; // for the correct aspect ratio
231 pctx->ExtIoDrp.PixAspY = 1; // normally the values of the monitor-structure
233 pctx->PD->pd_Preferences.PrintFlags = (pctx->PD->pd_Preferences.PrintFlags & ~DIMENSIONS_MASK) | IGNORE_DIMENSIONS;
234 D(kprintf("init_turboprint() initiated\n!"));
236 if (-1!=(pctx->page_size = get_pagesize()))
237 return pctx;
239 CloseDevice((struct IORequest *)pctx->PIO);
241 DeleteIORequest((struct IORequest *)pctx->PIO);
242 pctx->PIO = NULL;
244 DeleteMsgPort(pctx->PrinterMP);
245 pctx->PrinterMP = NULL;
248 D(kprintf("init_turboprint() bad!\n"));
249 return NULL;
252 void *pdfPrintInit(void *_ctx, const char *path, int first, int last, struct printerjob *pj)
254 struct devicecontext *ctx = (struct devicecontext*)_ctx;
255 struct printercontext *pctx = (struct printercontext*)calloc(1, sizeof(*pctx));
257 if(pctx != NULL)
259 if(pj->mode == VPDF_PRINT_POSTSCRIPT_2 || pj->mode == VPDF_PRINT_POSTSCRIPT_3)
263 pctx->format = pj->mode;
264 pctx->doc = ctx->doc;
265 pctx->file = Open(path, MODE_NEWFILE);
266 SetVBuf(pctx->file, pctx->buffer, BUF_FULL, OUTPUTBUFFERSIZE);
268 if(pctx->file != BNULL)
270 globalParams->setPSLevel((pctx->format == VPDF_PRINT_POSTSCRIPT_2)?psLevel2:psLevel3);
271 pctx->dev = new PSOutputDev(outputstreamfunc, pctx, "vpdf ps document output", pctx->doc,
272 first, last, psModePS);
274 else
276 free(pctx);
277 return NULL;
280 //pctx->dev->startDoc(pctx->doc->getXRef());
282 catch(...)
284 if(pctx->file != BNULL)
285 Close(pctx->file);
287 if(pctx->dev != NULL)
288 delete pctx->dev;
290 free(pctx);
291 pctx = NULL;
294 else if (init_turboprint(pctx))
296 // Cairo device init
297 pctx->format = pj->mode;
298 pctx->doc = ctx->doc;
300 pctx->cairo_dev = new CairoOutputDev();
301 pctx->cairo_dev->setPrinting(false);
302 pctx->surface = NULL;
303 pctx->last_page = -1; // indicate that we haven't printed anything yet
304 pctx->cairo = NULL;
305 pctx->cairo_dev->startDoc(pctx->doc);
306 return pctx;
308 else
310 free(pctx);
311 return NULL;
314 return pctx;
319 int pdfPrintPage(void *_pctx, int *_page, int center, int pages_per_sheet)
321 int page = _page[0];
322 struct printercontext *pctx = (struct printercontext*)_pctx;
323 Page *pdfpage = pctx->doc->getCatalog()->getPage(page);
325 ENTER_SECTION
329 if(pctx->format == VPDF_PRINT_POSTSCRIPT_2 || pctx->format == VPDF_PRINT_POSTSCRIPT_3 )
331 pctx->doc->displayPage(pctx->dev, page, 72, 72, 0, gTrue, gFalse, gTrue);
333 else
335 struct RastPort MyRastPort;
336 struct BitMap MyBitMap;
337 __unused char not_changed = FALSE;
338 cairo_surface_t *surface_back=NULL;
339 cairo_t *cairo_back = NULL;
341 int slide2xmode = FALSE;
342 int width_mm = round((pdfpage->getMediaWidth()/72.0) *25.4);
343 int height_mm = round((pdfpage->getMediaHeight()/72.0)*25.4);
345 int dpi_x = pctx->PD->pd_SegmentData->ps_PED.ped_XDotsInch;
346 int dpi_y = pctx->PD->pd_SegmentData->ps_PED.ped_YDotsInch;
347 int printer_w_mm = round((pctx->PD->pd_SegmentData->ps_PED.ped_MaxXDots/dpi_y)*25.4);
348 int printer_h_mm = round((pctx->PD->pd_SegmentData->ps_PED.ped_MaxYDots/dpi_y)*25.4);
349 int landscape_mode = (width_mm>height_mm);
350 float x_scale;
351 float y_scale;
353 if (landscape_mode)
355 x_scale = (height_mm/(1.0*page_sizes[pctx->page_size].w));
356 y_scale = (width_mm/(1.0*page_sizes[pctx->page_size].h));
358 else
360 x_scale = (width_mm/(1.0*page_sizes[pctx->page_size].w));
361 y_scale = (height_mm/(1.0*page_sizes[pctx->page_size].h));
363 KPrintF("X_SCALE: %f, Y_SCALE: %f\nPrinter W: %d, Printer H: %d, Page W: %d, Page H: %d\n",
364 x_scale, y_scale, page_sizes[pctx->page_size].w, page_sizes[pctx->page_size].h, width_mm, height_mm);
366 if (x_scale<1)
367 x_scale=1;
368 if (y_scale<1)
369 y_scale=1;
371 if (x_scale<y_scale)
372 x_scale = y_scale;
373 else
374 y_scale = x_scale;
375 D(kprintf("pdfPrintPage() turboprint mode: input w/h %d/%d\n!", width_mm, height_mm));
377 struct pdfBitmap bm;
379 int width = width_mm *dpi_x/25.4;
380 int height = height_mm*dpi_y/25.4;
382 if ((pages_per_sheet==2) && (height_mm<width_mm))
384 height *= 2;
385 height_mm *= 2;
386 D(kprintf(" slide mode 2x\n"));
387 slide2xmode = TRUE;
391 // check if we had to create new surface
392 if(pctx->surface != NULL)
394 if(cairo_image_surface_get_width(pctx->surface) != width || cairo_image_surface_get_height(pctx->surface) != height)
396 cairo_surface_destroy(pctx->surface);
397 pctx->surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
398 D(kprintf(" wrong sizes - new surface ok\n"));
400 else
402 not_changed = TRUE;
403 D(kprintf(" not changed ok\n"));
406 else
408 pctx->surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
409 D(kprintf("new surface ok\n"));
413 D(kprintf("pdfPrintPage() tuw\n"));
414 if(pctx->surface == NULL)
416 LEAVE_SECTION
417 return FALSE;
420 // check if we print the same page 2nd time
421 if (pctx->last_page != page)
423 pctx->cairo_dev->setCairo(NULL);
424 if (pctx->cairo) // if any context exist - delete context
425 cairo_destroy(pctx->cairo);
426 pctx->cairo = cairo_create(pctx->surface); // create new cairo context from surface
428 cairo_save(pctx->cairo); // save context on stack
430 cairo_set_source_rgb(pctx->cairo, 1., 1., 1); // change color to white
431 cairo_paint(pctx->cairo); // paint all surface
432 pctx->cairo_dev->setCairo(pctx->cairo);
433 D(kprintf("setCairo ok\n"));
434 D(kprintf("Display page: %d\n", page));
436 if (pages_per_sheet==2)
438 surface_back = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height/2);
439 if(surface_back == NULL)
441 LEAVE_SECTION
442 return FALSE;
445 cairo_back = cairo_create(surface_back);
446 if (!slide2xmode)
448 pctx->doc->displayPage(pctx->cairo_dev, _page[0], dpi_y/M_SQRT2, dpi_x/M_SQRT2, 90, gTrue, gFalse, gTrue);
450 else
452 pctx->doc->displayPage(pctx->cairo_dev, _page[0], dpi_x, dpi_y, 0, gTrue, gFalse, gTrue);
455 cairo_restore(pctx->cairo); // restore old cairo context
457 if ((_page[1]>0))
459 cairo_save(cairo_back);
460 cairo_set_source_rgb(cairo_back, 1., 1., 1); // change color to white
461 cairo_paint(cairo_back); // paint all surface
462 pctx->cairo_dev->setCairo(cairo_back);
463 kprintf("Display page: %d\n", _page[1]);
465 if (!slide2xmode)
467 pctx->doc->displayPage(pctx->cairo_dev, _page[1], dpi_y/M_SQRT2, dpi_x/M_SQRT2, 90, gTrue, gFalse, gTrue);
469 else
471 pctx->doc->displayPage(pctx->cairo_dev, _page[1], dpi_x, dpi_y, 0, gTrue, gFalse, gTrue);
474 cairo_restore(cairo_back);
475 cairo_save(pctx->cairo); // save context on stack
476 cairo_set_source_surface(pctx->cairo, surface_back, 0, height/2);
477 cairo_paint (pctx->cairo);
478 cairo_restore(pctx->cairo);
481 else
482 pctx->doc->displayPage(pctx->cairo_dev, _page[0], dpi_x, dpi_y, 0, gTrue, gFalse, gTrue);
485 D(kprintf(" displayPage ok\n"));
488 InitRastPort(&MyRastPort);
489 MyRastPort.BitMap = &MyBitMap;
490 // we need only one BitPlane, because it's chunky format
491 InitBitMap(&MyBitMap, 1, width, height);
492 MyBitMap.BytesPerRow = width * 3;
493 MyBitMap.Planes[0] = cairo_image_surface_get_data(pctx->surface);
494 #ifdef _RZK_TEST
495 cairo_surface_write_to_png(surface_back, "ram:image.png"); // only for testing
496 cairo_surface_write_to_png(pctx->surface , "ram:image_back.png"); // only for testing
497 #endif
499 if (pages_per_sheet==2)
501 cairo_destroy(cairo_back);
502 cairo_surface_destroy(surface_back);
505 if (pctx->last_page != page) // if we
507 int i, j;
508 LONG pixel, *ARGB_ptr;
509 char *tmp2;
511 ARGB_ptr = (LONG *)cairo_image_surface_get_data(pctx->surface);
512 tmp2 = (char *)ARGB_ptr;
514 // RGBA to RGB inline conversion
515 for(j = 0; j < height; j++)
517 for(i = 0; i < width; i++)
519 pixel = *ARGB_ptr++;
520 *tmp2++ = (pixel & 0xFF0000) >> 16;
521 *tmp2++ = (pixel & 0xFF00) >> 8;
522 *tmp2++ = (pixel & 0xFF);
525 D(kprintf(" conversion run ok\n"));
528 if (landscape_mode && center)
529 pctx->PD->pd_Preferences.PrintAspect=ASPECT_VERT;
531 pctx->PIO->iodrp.io_RastPort = &MyRastPort;
532 pctx->PIO->iodrp.io_SrcWidth = width; // width of rastport
533 pctx->PIO->iodrp.io_SrcHeight = height; // height of rastport
534 pctx->PIO->iodrp.io_DestCols =
535 (LONG)(((width_mm)/25.4) * 1000.); // width in printer pixels format
536 pctx->PIO->iodrp.io_DestRows =
537 (LONG)(((height_mm)/25.4) * 1000.); // height in printer pixel format
538 pctx->PIO->iodrp.io_Special = SPECIAL_MILROWS | SPECIAL_MILCOLS | (center)?SPECIAL_CENTER:0;
539 // save aspect ratio of picture,
541 if ((pctx->PIO->iodrp.io_DestCols>pctx->PD->pd_SegmentData->ps_PED.ped_MaxXDots) && (pctx->PD->pd_Preferences.PrintAspect!=ASPECT_VERT))
543 double aspect = (height_mm*1.0)/width_mm;
544 pctx->PIO->iodrp.io_DestCols = pctx->PD->pd_SegmentData->ps_PED.ped_MaxXDots;
545 pctx->PIO->iodrp.io_DestRows = aspect*pctx->PIO->iodrp.io_DestCols;
546 } // turn on inches input for above fields
548 //if(data->img.bpp == 24)
550 pctx->ExtIoDrp.Mode = TPFMT_RGB24;
551 pctx->PIO->iodrp.io_ColorMap = 0;
552 #ifndef _RZK_TEST
553 DoIO((struct IORequest *)pctx->PIO);
554 #endif
557 else
559 int i;
560 ExtIoDrp.Mode = TPFMT_Chunky8;
561 PD->pd_Preferences.PrintShade = SHADE_GREYSCALE;
562 // PD->pd_Preferences.PrintAspect = ASPECT_HORIZ;
563 PIO->iodrp.io_ColorMap = GetColorMap(256L);
564 for(i = 0 ; i < 256 ; i++)
565 SetRGB32CM(PIO->iodrp.io_ColorMap, i, i << 24, i << 24, i << 24);
567 DoIO((struct IORequest *)PIO);
568 FreeColorMap(PIO->iodrp.io_ColorMap);
572 catch(...)
574 LEAVE_SECTION
575 return 0;
577 LEAVE_SECTION
578 return 1;
581 void pdfPrintEnd(void *_pctx)
583 struct printercontext *pctx = (struct printercontext*)_pctx;
584 if(pctx != NULL)
586 if(pctx->format == VPDF_PRINT_POSTSCRIPT_2 || pctx->format == VPDF_PRINT_POSTSCRIPT_3)
588 if(pctx->dev)
589 delete pctx->dev;
591 if(pctx->file)
593 Close(pctx->file);
596 else // turboprint
598 if (pctx->cairo)
600 cairo_destroy(pctx->cairo);
601 pctx->cairo = NULL;
603 if(pctx->surface)
605 cairo_surface_destroy(pctx->surface);
607 if(pctx->cairo_dev)
609 pctx->cairo_dev->setCairo(NULL);
610 delete pctx->dev;
613 if (pctx->PIO)
615 CloseDevice((struct IORequest *)pctx->PIO);
616 DeleteIORequest((struct IORequest *)pctx->PIO);
618 if (pctx->PrinterMP)
619 DeleteMsgPort(pctx->PrinterMP);
622 free(pctx);