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
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"
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__);}
82 //#define ENTER_SECTION
83 #define LEAVE_SECTION ReleaseSemaphore(&semaphore);
84 //#define LEAVE_SECTION
86 #define OUTPUTBUFFERSIZE 262144
94 static const PAGE_SIZES page_sizes
[]= {
95 {1,1 }, //PS_US_LETTER
98 {1,1 }, //PS_W_TRACTOR
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
113 struct IFFHandle
*iffhandle
;
114 struct StoredProperty
*sp
;
116 struct PrinterTxtPrefs tmp
;
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
);
132 ifferror
= ParseIFF(iffhandle
, IFFPARSE_STEP
);
134 if (ifferror
== IFFERR_EOC
)
140 if (sp
= FindProp(iffhandle
, ID_PREF
, ID_PTXT
))
142 ret
= ((struct PrinterTxtPrefs
*)sp
->sp_Data
)->pt_PaperSize
;
148 Close ((BPTR
)iffhandle
->iff_Stream
);
156 struct printercontext
164 cairo_surface_t
*surface
;
166 CairoOutputDev
*cairo_dev
;
167 struct MsgPort
*PrinterMP
;
168 union printerIO
*PIO
;
169 struct PrinterData
*PD
;
170 struct TPExtIODRP ExtIoDrp
;
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
;
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()))
239 CloseDevice((struct IORequest
*)pctx
->PIO
);
241 DeleteIORequest((struct IORequest
*)pctx
->PIO
);
244 DeleteMsgPort(pctx
->PrinterMP
);
245 pctx
->PrinterMP
= NULL
;
248 D(kprintf("init_turboprint() bad!\n"));
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
));
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
);
280 //pctx->dev->startDoc(pctx->doc->getXRef());
284 if(pctx
->file
!= BNULL
)
287 if(pctx
->dev
!= NULL
)
294 else if (init_turboprint(pctx
))
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
305 pctx
->cairo_dev
->startDoc(pctx
->doc
);
319 int pdfPrintPage(void *_pctx
, int *_page
, int center
, int pages_per_sheet
)
322 struct printercontext
*pctx
= (struct printercontext
*)_pctx
;
323 Page
*pdfpage
= pctx
->doc
->getCatalog()->getPage(page
);
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
);
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
);
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
));
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
);
375 D(kprintf("pdfPrintPage() turboprint mode: input w/h %d/%d\n!", width_mm
, height_mm
));
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
))
386 D(kprintf(" slide mode 2x\n"));
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"));
403 D(kprintf(" not changed ok\n"));
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
)
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
)
445 cairo_back
= cairo_create(surface_back
);
448 pctx
->doc
->displayPage(pctx
->cairo_dev
, _page
[0], dpi_y
/M_SQRT2
, dpi_x
/M_SQRT2
, 90, gTrue
, gFalse
, gTrue
);
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
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]);
467 pctx
->doc
->displayPage(pctx
->cairo_dev
, _page
[1], dpi_y
/M_SQRT2
, dpi_x
/M_SQRT2
, 90, gTrue
, gFalse
, gTrue
);
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
);
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
);
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
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
508 LONG pixel
, *ARGB_ptr
;
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
++)
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;
553 DoIO((struct IORequest
*)pctx
->PIO
);
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);
581 void pdfPrintEnd(void *_pctx
)
583 struct printercontext
*pctx
= (struct printercontext
*)_pctx
;
586 if(pctx
->format
== VPDF_PRINT_POSTSCRIPT_2
|| pctx
->format
== VPDF_PRINT_POSTSCRIPT_3
)
600 cairo_destroy(pctx
->cairo
);
605 cairo_surface_destroy(pctx
->surface
);
609 pctx
->cairo_dev
->setCairo(NULL
);
615 CloseDevice((struct IORequest
*)pctx
->PIO
);
616 DeleteIORequest((struct IORequest
*)pctx
->PIO
);
619 DeleteMsgPort(pctx
->PrinterMP
);