4 #if defined(__MORPHOS__)
5 #include <proto/charsets.h>
7 #define AROS_ALMOST_COMPATIBLE
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>
16 #include <aros/debug.h>
17 #define KPrintF kprintf
19 #include <clib/debug_protos.h>
21 #include <exec/semaphores.h>
22 #include <exec/lists.h>
23 #include <prefs/prefhdr.h>
24 #include <constructor.h>
25 #include <prefs/printertxt.h>
28 #include <poppler-config.h>
40 #include "GlobalParams.h"
41 #include "PDFDocEncoding.h"
42 #include "goo/GooList.h"
46 #include "splash/SplashBitmap.h"
47 #include "splash/Splash.h"
48 #include "SplashOutputDev.h"
49 #include "TextOutputDev.h"
51 #include "CairoOutputDev.h"
53 #include "PSOutputDev.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
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"
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__);}
83 //#define ENTER_SECTION
84 #define LEAVE_SECTION ReleaseSemaphore(&semaphore);
85 //#define LEAVE_SECTION
87 #define OUTPUTBUFFERSIZE 262144
95 static const PAGE_SIZES page_sizes
[]= {
96 {1,1 }, //PS_US_LETTER
99 {1,1 }, //PS_W_TRACTOR
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
114 struct IFFHandle
*iffhandle
;
115 struct StoredProperty
*sp
;
117 struct PrinterTxtPrefs tmp
;
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
);
133 ifferror
= ParseIFF(iffhandle
, IFFPARSE_STEP
);
135 if (ifferror
== IFFERR_EOC
)
141 if (sp
= FindProp(iffhandle
, ID_PREF
, ID_PTXT
))
143 ret
= ((struct PrinterTxtPrefs
*)sp
->sp_Data
)->pt_PaperSize
;
149 Close ((BPTR
)iffhandle
->iff_Stream
);
157 struct printercontext
165 cairo_surface_t
*surface
;
167 CairoOutputDev
*cairo_dev
;
168 struct MsgPort
*PrinterMP
;
169 union printerIO
*PIO
;
170 struct PrinterData
*PD
;
171 struct TPExtIODRP ExtIoDrp
;
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
;
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()))
240 CloseDevice((struct IORequest
*)pctx
->PIO
);
242 DeleteIORequest((struct IORequest
*)pctx
->PIO
);
245 DeleteMsgPort(pctx
->PrinterMP
);
246 pctx
->PrinterMP
= NULL
;
249 D(kprintf("init_turboprint() bad!\n"));
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
));
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
);
281 //pctx->dev->startDoc(pctx->doc->getXRef());
285 if(pctx
->file
!= NULL
)
288 if(pctx
->dev
!= NULL
)
295 else if (init_turboprint(pctx
))
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
306 pctx
->cairo_dev
->startDoc(pctx
->doc
);
320 int pdfPrintPage(void *_pctx
, int *_page
, int center
, int pages_per_sheet
)
323 struct printercontext
*pctx
= (struct printercontext
*)_pctx
;
324 Page
*pdfpage
= pctx
->doc
->getCatalog()->getPage(page
);
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
);
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
);
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
));
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
);
376 D(kprintf("pdfPrintPage() turboprint mode: input w/h %d/%d\n!", width_mm
, height_mm
));
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
))
387 D(kprintf(" slide mode 2x\n"));
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"));
404 D(kprintf(" not changed ok\n"));
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
)
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
)
446 cairo_back
= cairo_create(surface_back
);
449 pctx
->doc
->displayPage(pctx
->cairo_dev
, _page
[0], dpi_y
/M_SQRT2
, dpi_x
/M_SQRT2
, 90, gTrue
, gFalse
, gTrue
);
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
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]);
468 pctx
->doc
->displayPage(pctx
->cairo_dev
, _page
[1], dpi_y
/M_SQRT2
, dpi_x
/M_SQRT2
, 90, gTrue
, gFalse
, gTrue
);
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
);
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
);
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
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
509 LONG pixel
, *ARGB_ptr
;
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
++)
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;
554 DoIO((struct IORequest
*)pctx
->PIO
);
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);
582 void pdfPrintEnd(void *_pctx
)
584 struct printercontext
*pctx
= (struct printercontext
*)_pctx
;
587 if(pctx
->format
== VPDF_PRINT_POSTSCRIPT_2
|| pctx
->format
== VPDF_PRINT_POSTSCRIPT_3
)
601 cairo_destroy(pctx
->cairo
);
606 cairo_surface_destroy(pctx
->surface
);
610 pctx
->cairo_dev
->setCairo(NULL
);
616 CloseDevice((struct IORequest
*)pctx
->PIO
);
617 DeleteIORequest((struct IORequest
*)pctx
->PIO
);
620 DeleteMsgPort(pctx
->PrinterMP
);