Moved DejaVue fonts to contrib. They are only needed by applications
[AROS-Contrib.git] / vpdf / poppler_printer.cpp
bloba636684bef85fbc90b251867af5787b2b7c0603b
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 #define D(x) x
63 #warning TODO: make the semaphore per-document
64 extern struct SignalSemaphore semaphore;
66 extern struct Library *CairoBase;
69 // turboprint includes
70 #include <devices/printer.h>
71 #include <devices/prtbase.h>
72 #include <datatypes/datatypesclass.h>
73 #include "turboprint.h"
75 #if 1
76 #define ENTER_SECTION \
77 { ObtainSemaphore(&semaphore);}
78 #else // time delay needed to enter critical section
79 #define ENTER_SECTION \
80 { clock_t t0 = clock(); ObtainSemaphore(&semaphore); t0 = clock() - t0; kprintf("section enter:%f:%s\n", (float)t0/CLOCKS_PER_SEC, __FUNCTION__);}
81 #endif
83 //#define ENTER_SECTION
84 #define LEAVE_SECTION ReleaseSemaphore(&semaphore);
85 //#define LEAVE_SECTION
87 #define OUTPUTBUFFERSIZE 262144
89 typedef struct
91 int w;
92 int h;
93 } PAGE_SIZES;
95 static const PAGE_SIZES page_sizes[]= {
96 {1,1 }, //PS_US_LETTER
97 {1,1 }, //PS_US_LEGAL
98 {1,1}, //PS_N_TRACTOR
99 {1,1 }, //PS_W_TRACTOR
100 {1,1 }, //PS_CUSTOM
101 {841,1189}, //PS_EURO_A0
102 {594,841 }, //PS_EURO_A1
103 {420,594}, //PS_EURO_A2
104 {297,420}, //PS_EURO_A3
105 {210,297 }, //PS_EURO_A4
106 {148,210 }, //PS_EURO_A5
107 {1,1, }, //PS_EURO_A6
108 {1,1}, //PS_EURO_A7
109 {1,1 }, //PS_EURO_A8
112 int get_pagesize()
114 struct IFFHandle *iffhandle;
115 struct StoredProperty *sp;
116 int ifferror;
117 struct PrinterTxtPrefs tmp;
118 int ret = -1;
120 if (iffhandle = AllocIFF())
122 if (iffhandle->iff_Stream = (LONG)Open("env:sys/printer.prefs", MODE_OLDFILE))
124 D(kprintf("prefs file opened\n"));
125 InitIFFasDOS (iffhandle);
126 if ((ifferror = OpenIFF (iffhandle, IFFF_READ)) == 0)
128 D(kprintf("iff opened\n"));
129 PropChunk(iffhandle, ID_PREF, ID_PTXT);
131 for (;;)
133 ifferror = ParseIFF(iffhandle, IFFPARSE_STEP);
135 if (ifferror == IFFERR_EOC)
136 continue;
137 else if (ifferror)
138 break;
141 if (sp = FindProp(iffhandle, ID_PREF, ID_PTXT))
143 ret = ((struct PrinterTxtPrefs *)sp->sp_Data)->pt_PaperSize;
146 CloseIFF(iffhandle);
149 Close ((BPTR)iffhandle->iff_Stream);
151 FreeIFF(iffhandle);
153 return ret;
157 struct printercontext
159 ULONG format;
160 PDFDoc *doc;
162 PSOutputDev *dev;
163 BPTR file;
165 cairo_surface_t *surface;
166 cairo_t *cairo;
167 CairoOutputDev *cairo_dev;
168 struct MsgPort *PrinterMP;
169 union printerIO *PIO;
170 struct PrinterData *PD;
171 struct TPExtIODRP ExtIoDrp;
172 BOOL TP_Installed;
173 UWORD TPVersion;
174 int last_page;
175 int page_size;
176 char buffer[OUTPUTBUFFERSIZE];
180 static void outputstreamfunc(void *stream, const char *data, int len)
182 struct printercontext *pctx = (struct printercontext*)stream;
183 FWrite(pctx->file, (void*)data, (LONG)len, 1);
186 struct printercontext *init_turboprint(struct printercontext *pctx)
188 pctx->PrinterMP = NULL;
189 pctx->PIO = NULL;
191 D(kprintf("init_turboprint() started\n!"));
192 if((pctx->PrinterMP = (struct MsgPort*)CreateMsgPort()))
194 if((pctx->PIO = (union printerIO *)CreateIORequest(pctx->PrinterMP, sizeof(union printerIO))))
196 if(!(OpenDevice((STRPTR)"printer.device", 0, (struct IORequest *)pctx->PIO, 0)))
198 pctx->PD = (struct PrinterData *)pctx->PIO->iodrp.io_Device;
199 pctx->TP_Installed = (((ULONG *)(pctx->PD->pd_OldStk))[2] == TPMATCHWORD);
201 pctx->TPVersion = pctx->PIO->iodrp.io_Device->dd_Library.lib_Version;
202 // pctx->TPIdString = (char*)(pctx->PIO->iodrp.io_Device->dd_Library.lib_IdString);
204 if(pctx->TP_Installed && pctx->TPVersion >= 39)
206 struct PrinterData *PD = pctx->PD;
208 D(kprintf("PrinterName = '%s', Version=%u, Revision=%u\n",
209 PD->pd_SegmentData->ps_PED.ped_PrinterName, PD->pd_SegmentData->ps_Version,
210 PD->pd_SegmentData->ps_Revision));
211 D(kprintf("PrinterClass=%u, ColorClass=%u\n",
212 PD->pd_SegmentData->ps_PED.ped_PrinterClass, PD->pd_SegmentData->ps_PED.ped_ColorClass));
213 D(kprintf("MaxColumns=%u, NumCharSets=%u, NumRows=%u\n",
214 PD->pd_SegmentData->ps_PED.ped_MaxColumns, PD->pd_SegmentData->ps_PED.ped_NumCharSets, PD->pd_SegmentData->ps_PED.ped_NumRows));
215 D(kprintf("MaxXDots=%lu, MaxYDots=%lu, XDotsInch=%u, YDotsInch=%u\n",
216 PD->pd_SegmentData->ps_PED.ped_MaxXDots, PD->pd_SegmentData->ps_PED.ped_MaxYDots,
217 PD->pd_SegmentData->ps_PED.ped_XDotsInch, PD->pd_SegmentData->ps_PED.ped_YDotsInch));
218 D(kprintf("PrintLeftMargin=%d, PrintRightMargin=%d\n",
219 pctx->PD->pd_Preferences.PrintLeftMargin,pctx->PD->pd_Preferences.PrintRightMargin));
221 D(kprintf("PrintAspect: %d\n", PD->pd_Preferences.PrintAspect));
223 pctx->PIO->iodrp.io_Command = PRD_TPEXTDUMPRPORT;
224 pctx->PIO->iodrp.io_SrcX = 0; // x offset in rastport to start printing from
225 pctx->PIO->iodrp.io_SrcY = 0; // y offset in rastpoty to start printing from
227 // new: io.Modes must point to a new Structure (ExtIoDrp)
228 pctx->PIO->iodrp.io_Modes = (ULONG)&pctx->ExtIoDrp;
230 // fill in the new structure
231 pctx->ExtIoDrp.PixAspX = 1; // for the correct aspect ratio
232 pctx->ExtIoDrp.PixAspY = 1; // normally the values of the monitor-structure
234 pctx->PD->pd_Preferences.PrintFlags = (pctx->PD->pd_Preferences.PrintFlags & ~DIMENSIONS_MASK) | IGNORE_DIMENSIONS;
235 D(kprintf("init_turboprint() initiated\n!"));
237 if (-1!=(pctx->page_size = get_pagesize()))
238 return pctx;
240 CloseDevice((struct IORequest *)pctx->PIO);
242 DeleteIORequest((struct IORequest *)pctx->PIO);
243 pctx->PIO = NULL;
245 DeleteMsgPort(pctx->PrinterMP);
246 pctx->PrinterMP = NULL;
249 D(kprintf("init_turboprint() bad!\n"));
250 return NULL;
253 void *pdfPrintInit(void *_ctx, const char *path, int first, int last, struct printerjob *pj)
255 struct devicecontext *ctx = (struct devicecontext*)_ctx;
256 struct printercontext *pctx = (struct printercontext*)calloc(1, sizeof(*pctx));
258 if(pctx != NULL)
260 if(pj->mode == VPDF_PRINT_POSTSCRIPT_2 || pj->mode == VPDF_PRINT_POSTSCRIPT_3)
264 pctx->format = pj->mode;
265 pctx->doc = ctx->doc;
266 pctx->file = Open(path, MODE_NEWFILE);
267 SetVBuf(pctx->file, pctx->buffer, BUF_FULL, OUTPUTBUFFERSIZE);
269 if(pctx->file != NULL)
271 globalParams->setPSLevel((pctx->format == VPDF_PRINT_POSTSCRIPT_2)?psLevel2:psLevel3);
272 pctx->dev = new PSOutputDev(outputstreamfunc, pctx, "vpdf ps document output", pctx->doc,
273 first, last, psModePS);
275 else
277 free(pctx);
278 return NULL;
281 //pctx->dev->startDoc(pctx->doc->getXRef());
283 catch(...)
285 if(pctx->file != NULL)
286 Close(pctx->file);
288 if(pctx->dev != NULL)
289 delete pctx->dev;
291 free(pctx);
292 pctx = NULL;
295 else if (init_turboprint(pctx))
297 // Cairo device init
298 pctx->format = pj->mode;
299 pctx->doc = ctx->doc;
301 pctx->cairo_dev = new CairoOutputDev();
302 pctx->cairo_dev->setPrinting(false);
303 pctx->surface = NULL;
304 pctx->last_page = -1; // indicate that we haven't printed anything yet
305 pctx->cairo = NULL;
306 pctx->cairo_dev->startDoc(pctx->doc);
307 return pctx;
309 else
311 free(pctx);
312 return NULL;
315 return pctx;
320 int pdfPrintPage(void *_pctx, int *_page, int center, int pages_per_sheet)
322 int page = _page[0];
323 struct printercontext *pctx = (struct printercontext*)_pctx;
324 Page *pdfpage = pctx->doc->getCatalog()->getPage(page);
326 ENTER_SECTION
330 if(pctx->format == VPDF_PRINT_POSTSCRIPT_2 || pctx->format == VPDF_PRINT_POSTSCRIPT_3 )
332 pctx->doc->displayPage(pctx->dev, page, 72, 72, 0, gTrue, gFalse, gTrue);
334 else
336 struct RastPort MyRastPort;
337 struct BitMap MyBitMap;
338 char not_changed = FALSE;
339 cairo_surface_t *surface_back=NULL;
340 cairo_t *cairo_back = NULL;
342 int slide2xmode = FALSE;
343 int width_mm = round((pdfpage->getMediaWidth()/72.0) *25.4);
344 int height_mm = round((pdfpage->getMediaHeight()/72.0)*25.4);
346 int dpi_x = pctx->PD->pd_SegmentData->ps_PED.ped_XDotsInch;
347 int dpi_y = pctx->PD->pd_SegmentData->ps_PED.ped_YDotsInch;
348 int printer_w_mm = round((pctx->PD->pd_SegmentData->ps_PED.ped_MaxXDots/dpi_y)*25.4);
349 int printer_h_mm = round((pctx->PD->pd_SegmentData->ps_PED.ped_MaxYDots/dpi_y)*25.4);
350 int landscape_mode = (width_mm>height_mm);
351 float x_scale;
352 float y_scale;
354 if (landscape_mode)
356 x_scale = (height_mm/(1.0*page_sizes[pctx->page_size].w));
357 y_scale = (width_mm/(1.0*page_sizes[pctx->page_size].h));
359 else
361 x_scale = (width_mm/(1.0*page_sizes[pctx->page_size].w));
362 y_scale = (height_mm/(1.0*page_sizes[pctx->page_size].h));
364 KPrintF("X_SCALE: %f, Y_SCALE: %f\nPrinter W: %d, Printer H: %d, Page W: %d, Page H: %d\n",
365 x_scale, y_scale, page_sizes[pctx->page_size].w, page_sizes[pctx->page_size].h, width_mm, height_mm);
367 if (x_scale<1)
368 x_scale=1;
369 if (y_scale<1)
370 y_scale=1;
372 if (x_scale<y_scale)
373 x_scale = y_scale;
374 else
375 y_scale = x_scale;
376 D(kprintf("pdfPrintPage() turboprint mode: input w/h %d/%d\n!", width_mm, height_mm));
378 struct pdfBitmap bm;
380 int width = width_mm *dpi_x/25.4;
381 int height = height_mm*dpi_y/25.4;
383 if ((pages_per_sheet==2) && (height_mm<width_mm))
385 height *= 2;
386 height_mm *= 2;
387 D(kprintf(" slide mode 2x\n"));
388 slide2xmode = TRUE;
392 // check if we had to create new surface
393 if(pctx->surface != NULL)
395 if(cairo_image_surface_get_width(pctx->surface) != width || cairo_image_surface_get_height(pctx->surface) != height)
397 cairo_surface_destroy(pctx->surface);
398 pctx->surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
399 D(kprintf(" wrong sizes - new surface ok\n"));
401 else
403 not_changed = TRUE;
404 D(kprintf(" not changed ok\n"));
407 else
409 pctx->surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
410 D(kprintf("new surface ok\n"));
414 D(kprintf("pdfPrintPage() tuw\n"));
415 if(pctx->surface == NULL)
417 LEAVE_SECTION
418 return FALSE;
421 // check if we print the same page 2nd time
422 if (pctx->last_page != page)
424 pctx->cairo_dev->setCairo(NULL);
425 if (pctx->cairo) // if any context exist - delete context
426 cairo_destroy(pctx->cairo);
427 pctx->cairo = cairo_create(pctx->surface); // create new cairo context from surface
429 cairo_save(pctx->cairo); // save context on stack
431 cairo_set_source_rgb(pctx->cairo, 1., 1., 1); // change color to white
432 cairo_paint(pctx->cairo); // paint all surface
433 pctx->cairo_dev->setCairo(pctx->cairo);
434 D(kprintf("setCairo ok\n"));
435 D(kprintf("Display page: %d\n", page));
437 if (pages_per_sheet==2)
439 surface_back = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height/2);
440 if(surface_back == NULL)
442 LEAVE_SECTION
443 return FALSE;
446 cairo_back = cairo_create(surface_back);
447 if (!slide2xmode)
449 pctx->doc->displayPage(pctx->cairo_dev, _page[0], dpi_y/M_SQRT2, dpi_x/M_SQRT2, 90, gTrue, gFalse, gTrue);
451 else
453 pctx->doc->displayPage(pctx->cairo_dev, _page[0], dpi_x, dpi_y, 0, gTrue, gFalse, gTrue);
456 cairo_restore(pctx->cairo); // restore old cairo context
458 if ((_page[1]>0))
460 cairo_save(cairo_back);
461 cairo_set_source_rgb(cairo_back, 1., 1., 1); // change color to white
462 cairo_paint(cairo_back); // paint all surface
463 pctx->cairo_dev->setCairo(cairo_back);
464 kprintf("Display page: %d\n", _page[1]);
466 if (!slide2xmode)
468 pctx->doc->displayPage(pctx->cairo_dev, _page[1], dpi_y/M_SQRT2, dpi_x/M_SQRT2, 90, gTrue, gFalse, gTrue);
470 else
472 pctx->doc->displayPage(pctx->cairo_dev, _page[1], dpi_x, dpi_y, 0, gTrue, gFalse, gTrue);
475 cairo_restore(cairo_back);
476 cairo_save(pctx->cairo); // save context on stack
477 cairo_set_source_surface(pctx->cairo, surface_back, 0, height/2);
478 cairo_paint (pctx->cairo);
479 cairo_restore(pctx->cairo);
482 else
483 pctx->doc->displayPage(pctx->cairo_dev, _page[0], dpi_x, dpi_y, 0, gTrue, gFalse, gTrue);
486 D(kprintf(" displayPage ok\n"));
489 InitRastPort(&MyRastPort);
490 MyRastPort.BitMap = &MyBitMap;
491 // we need only one BitPlane, because it's chunky format
492 InitBitMap(&MyBitMap, 1, width, height);
493 MyBitMap.BytesPerRow = width * 3;
494 MyBitMap.Planes[0] = cairo_image_surface_get_data(pctx->surface);
495 #ifdef _RZK_TEST
496 cairo_surface_write_to_png(surface_back, "ram:image.png"); // only for testing
497 cairo_surface_write_to_png(pctx->surface , "ram:image_back.png"); // only for testing
498 #endif
500 if (pages_per_sheet==2)
502 cairo_destroy(cairo_back);
503 cairo_surface_destroy(surface_back);
506 if (pctx->last_page != page) // if we
508 int i, j;
509 LONG pixel, *ARGB_ptr;
510 char *tmp2;
512 ARGB_ptr = (LONG *)cairo_image_surface_get_data(pctx->surface);
513 tmp2 = (char *)ARGB_ptr;
515 // RGBA to RGB inline conversion
516 for(j = 0; j < height; j++)
518 for(i = 0; i < width; i++)
520 pixel = *ARGB_ptr++;
521 *tmp2++ = (pixel & 0xFF0000) >> 16;
522 *tmp2++ = (pixel & 0xFF00) >> 8;
523 *tmp2++ = (pixel & 0xFF);
526 D(kprintf(" conversion run ok\n"));
529 if (landscape_mode && center)
530 pctx->PD->pd_Preferences.PrintAspect=ASPECT_VERT;
532 pctx->PIO->iodrp.io_RastPort = &MyRastPort;
533 pctx->PIO->iodrp.io_SrcWidth = width; // width of rastport
534 pctx->PIO->iodrp.io_SrcHeight = height; // height of rastport
535 pctx->PIO->iodrp.io_DestCols =
536 (LONG)(((width_mm)/25.4) * 1000.); // width in printer pixels format
537 pctx->PIO->iodrp.io_DestRows =
538 (LONG)(((height_mm)/25.4) * 1000.); // height in printer pixel format
539 pctx->PIO->iodrp.io_Special = SPECIAL_MILROWS | SPECIAL_MILCOLS | (center)?SPECIAL_CENTER:0;
540 // save aspect ratio of picture,
542 if ((pctx->PIO->iodrp.io_DestCols>pctx->PD->pd_SegmentData->ps_PED.ped_MaxXDots) && (pctx->PD->pd_Preferences.PrintAspect!=ASPECT_VERT))
544 double aspect = (height_mm*1.0)/width_mm;
545 pctx->PIO->iodrp.io_DestCols = pctx->PD->pd_SegmentData->ps_PED.ped_MaxXDots;
546 pctx->PIO->iodrp.io_DestRows = aspect*pctx->PIO->iodrp.io_DestCols;
547 } // turn on inches input for above fields
549 //if(data->img.bpp == 24)
551 pctx->ExtIoDrp.Mode = TPFMT_RGB24;
552 pctx->PIO->iodrp.io_ColorMap = 0;
553 #ifndef _RZK_TEST
554 DoIO((struct IORequest *)pctx->PIO);
555 #endif
558 else
560 int i;
561 ExtIoDrp.Mode = TPFMT_Chunky8;
562 PD->pd_Preferences.PrintShade = SHADE_GREYSCALE;
563 // PD->pd_Preferences.PrintAspect = ASPECT_HORIZ;
564 PIO->iodrp.io_ColorMap = GetColorMap(256L);
565 for(i = 0 ; i < 256 ; i++)
566 SetRGB32CM(PIO->iodrp.io_ColorMap, i, i << 24, i << 24, i << 24);
568 DoIO((struct IORequest *)PIO);
569 FreeColorMap(PIO->iodrp.io_ColorMap);
573 catch(...)
575 LEAVE_SECTION
576 return 0;
578 LEAVE_SECTION
579 return 1;
582 void pdfPrintEnd(void *_pctx)
584 struct printercontext *pctx = (struct printercontext*)_pctx;
585 if(pctx != NULL)
587 if(pctx->format == VPDF_PRINT_POSTSCRIPT_2 || pctx->format == VPDF_PRINT_POSTSCRIPT_3)
589 if(pctx->dev)
590 delete pctx->dev;
592 if(pctx->file)
594 Close(pctx->file);
597 else // turboprint
599 if (pctx->cairo)
601 cairo_destroy(pctx->cairo);
602 pctx->cairo = NULL;
604 if(pctx->surface)
606 cairo_surface_destroy(pctx->surface);
608 if(pctx->cairo_dev)
610 pctx->cairo_dev->setCairo(NULL);
611 delete pctx->dev;
614 if (pctx->PIO)
616 CloseDevice((struct IORequest *)pctx->PIO);
617 DeleteIORequest((struct IORequest *)pctx->PIO);
619 if (pctx->PrinterMP)
620 DeleteMsgPort(pctx->PrinterMP);
623 free(pctx);