- Clean up the mask drawing code.
[wine] / dlls / wineps / ps.c
1 /*
2  *      PostScript output functions
3  *
4  *      Copyright 1998  Huw D M Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdarg.h>
25
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "psdrv.h"
32 #include "winspool.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
36
37 static const char psheader[] = /* title llx lly urx ury */
38 "%%!PS-Adobe-3.0\n"
39 "%%%%Creator: Wine PostScript Driver\n"
40 "%%%%Title: %s\n"
41 "%%%%BoundingBox: %d %d %d %d\n"
42 "%%%%Pages: (atend)\n"
43 "%%%%EndComments\n";
44
45 static const char psbeginprolog[] =
46 "%%BeginProlog\n";
47
48 static const char psendprolog[] =
49 "%%EndProlog\n";
50
51 static const char psprolog[] =
52 "/tmpmtrx matrix def\n"
53 "/hatch {\n"
54 "  pathbbox\n"
55 "  /b exch def /r exch def /t exch def /l exch def /gap 32 def\n"
56 "  l cvi gap idiv gap mul\n"
57 "  gap\n"
58 "  r cvi gap idiv gap mul\n"
59 "  {t moveto 0 b t sub rlineto}\n"
60 "  for\n"
61 "} bind def\n"
62 "/B {pop pop pop pop} def\n"
63 "/N {newpath} def\n"
64 "/havetype42gdir {version cvi 2015 ge} bind def\n";
65
66 static const char psbeginsetup[] =
67 "%%BeginSetup\n";
68
69 static const char psendsetup[] =
70 "%%EndSetup\n";
71
72 static const char psbeginfeature[] = /* feature, value */
73 "mark {\n"
74 "%%%%BeginFeature: %s %s\n";
75
76 static const char psendfeature[] =
77 "\n%%EndFeature\n"
78 "} stopped cleartomark\n";
79
80 static const char psnewpage[] = /* name, number, xres, yres, xtrans, ytrans, rot */
81 "%%%%Page: %s %d\n"
82 "%%%%BeginPageSetup\n"
83 "/pgsave save def\n"
84 "72 %d div 72 %d div scale\n"
85 "%d %d translate\n"
86 "1 -1 scale\n"
87 "%d rotate\n"
88 "%%%%EndPageSetup\n";
89
90 static const char psendpage[] =
91 "pgsave restore\n"
92 "showpage\n";
93
94 static const char psfooter[] = /* pages */
95 "%%%%Trailer\n"
96 "%%%%Pages: %d\n"
97 "%%%%EOF\n";
98
99 static const char psmoveto[] = /* x, y */
100 "%d %d moveto\n";
101
102 static const char pslineto[] = /* x, y */
103 "%d %d lineto\n";
104
105 static const char psstroke[] =
106 "stroke\n";
107
108 static const char psrectangle[] = /* x, y, width, height, -width */
109 "%d %d moveto\n"
110 "%d 0 rlineto\n"
111 "0 %d rlineto\n"
112 "%d 0 rlineto\n"
113 "closepath\n";
114
115 static const char psrrectangle[] = /* x, y, width, height, -width */
116 "%d %d rmoveto\n"
117 "%d 0 rlineto\n"
118 "0 %d rlineto\n"
119 "%d 0 rlineto\n"
120 "closepath\n";
121
122 static const char psglyphshow[] = /* glyph name */
123 "/%s glyphshow\n";
124
125 static const char pssetfont[] = /* fontname, xscale, yscale, ascent, escapement */
126 "/%s findfont\n"
127 "[%d 0 0 %d 0 0]\n"
128 "%d 10 div matrix rotate\n"
129 "matrix concatmatrix\n"
130 "makefont setfont\n";
131
132 static const char pssetlinewidth[] = /* width */
133 "%d setlinewidth\n";
134
135 static const char pssetdash[] = /* dash, offset */
136 "[%s] %d setdash\n";
137
138 static const char pssetgray[] = /* gray */
139 "%.2f setgray\n";
140
141 static const char pssetrgbcolor[] = /* r, g, b */
142 "%.2f %.2f %.2f setrgbcolor\n";
143
144 static const char psarc[] = /* x, y, w, h, ang1, ang2 */
145 "tmpmtrx currentmatrix pop\n"
146 "%d %d translate\n"
147 "%d %d scale\n"
148 "0 0 0.5 %.1f %.1f arc\n"
149 "tmpmtrx setmatrix\n";
150
151 static const char psgsave[] =
152 "gsave\n";
153
154 static const char psgrestore[] =
155 "grestore\n";
156
157 static const char psfill[] =
158 "fill\n";
159
160 static const char pseofill[] =
161 "eofill\n";
162
163 static const char psnewpath[] =
164 "newpath\n";
165
166 static const char psclosepath[] =
167 "closepath\n";
168
169 static const char psclip[] =
170 "clip\n";
171
172 static const char psinitclip[] =
173 "initclip\n";
174
175 static const char pseoclip[] =
176 "eoclip\n";
177
178 static const char psrectclip[] =
179 "%d %d %d %d rectclip\n";
180
181 static const char psrectclip2[] =
182 "%s rectclip\n";
183
184 static const char pshatch[] =
185 "hatch\n";
186
187 static const char psrotate[] = /* ang */
188 "%.1f rotate\n";
189
190 static const char psarrayget[] =
191 "%s %d get\n";
192
193 static const char psarrayput[] =
194 "%s %d %ld put\n";
195
196 static const char psarraydef[] =
197 "/%s %d array def\n";
198
199 static const char psenddocument[] =
200 "\n%%EndDocument\n";
201
202 DWORD PSDRV_WriteSpool(PSDRV_PDEVICE *physDev, LPCSTR lpData, DWORD cch)
203 {
204     int num, num_left = cch;
205
206     if(physDev->job.quiet) {
207         TRACE("ignoring output\n");
208         return 0;
209     }
210
211     if(physDev->job.in_passthrough) { /* Was in PASSTHROUGH mode */
212         WriteSpool16( physDev->job.hJob, (LPSTR)psenddocument, sizeof(psenddocument)-1 );
213         physDev->job.in_passthrough = physDev->job.had_passthrough_rect = FALSE;
214     }
215
216     if(physDev->job.OutOfPage) { /* Will get here after NEWFRAME Escape */
217         if( !PSDRV_StartPage(physDev) )
218             return 0;
219     }
220
221     do {
222         num = min(num_left, 0x8000);
223         if(WriteSpool16( physDev->job.hJob, (LPSTR)lpData, num ) != num)
224             return 0;
225         lpData += num;
226         num_left -= num;
227     } while(num_left);
228
229     return cch;
230 }
231
232
233 INT PSDRV_WriteFeature(HANDLE16 hJob, char *feature, char *value,
234                          char *invocation)
235 {
236
237     char *buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psbeginfeature) +
238                                    strlen(feature) + strlen(value));
239
240
241     sprintf(buf, psbeginfeature, feature, value);
242     WriteSpool16( hJob, buf, strlen(buf) );
243
244     WriteSpool16( hJob, invocation, strlen(invocation) );
245
246     WriteSpool16( hJob, (LPSTR)psendfeature, strlen(psendfeature) );
247
248     HeapFree( PSDRV_Heap, 0, buf );
249     return 1;
250 }
251
252
253
254 INT PSDRV_WriteHeader( PSDRV_PDEVICE *physDev, LPCSTR title )
255 {
256     char *buf;
257     INPUTSLOT *slot;
258     PAGESIZE *page;
259     DUPLEX *duplex;
260     int win_duplex;
261     int llx, lly, urx, ury;
262
263     TRACE("'%s'\n", debugstr_a(title));
264
265     buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psheader) +
266                              (title ? strlen(title) : 0) + 30 );
267     if(!buf) {
268         WARN("HeapAlloc failed\n");
269         return 0;
270     }
271
272     /* BBox co-ords are in default user co-ord system so urx < ury even in
273        landscape mode */
274     llx = physDev->ImageableArea.left * 72.0 / physDev->logPixelsX;
275     lly = physDev->ImageableArea.bottom * 72.0 / physDev->logPixelsY;
276     urx = physDev->ImageableArea.right * 72.0 / physDev->logPixelsX;
277     ury = physDev->ImageableArea.top * 72.0 / physDev->logPixelsY;
278     /* FIXME should do something better with BBox */
279
280     sprintf(buf, psheader, title ? title : "", llx, lly, urx, ury);
281
282     if( WriteSpool16( physDev->job.hJob, buf, strlen(buf) ) !=
283                                                      strlen(buf) ) {
284         WARN("WriteSpool error\n");
285         HeapFree( PSDRV_Heap, 0, buf );
286         return 0;
287     }
288     HeapFree( PSDRV_Heap, 0, buf );
289
290     WriteSpool16( physDev->job.hJob, (LPSTR)psbeginprolog, strlen(psbeginprolog) );
291     WriteSpool16( physDev->job.hJob, (LPSTR)psprolog, strlen(psprolog) );
292     WriteSpool16( physDev->job.hJob, (LPSTR)psendprolog, strlen(psendprolog) );
293
294     WriteSpool16( physDev->job.hJob, (LPSTR)psbeginsetup, strlen(psbeginsetup) );
295
296     if(physDev->Devmode->dmPublic.dmCopies > 1) {
297         char copies_buf[100];
298         sprintf(copies_buf, "mark {\n << /NumCopies %d >> setpagedevice\n} stopped cleartomark\n", physDev->Devmode->dmPublic.dmCopies);
299         WriteSpool16(physDev->job.hJob, copies_buf, strlen(copies_buf));
300     }
301
302     for(slot = physDev->pi->ppd->InputSlots; slot; slot = slot->next) {
303         if(slot->WinBin == physDev->Devmode->dmPublic.dmDefaultSource) {
304             if(slot->InvocationString) {
305                 PSDRV_WriteFeature(physDev->job.hJob, "*InputSlot", slot->Name,
306                              slot->InvocationString);
307                 break;
308             }
309         }
310     }
311
312     for(page = physDev->pi->ppd->PageSizes; page; page = page->next) {
313         if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize) {
314             if(page->InvocationString) {
315                 PSDRV_WriteFeature(physDev->job.hJob, "*PageSize", page->Name,
316                              page->InvocationString);
317                 break;
318             }
319         }
320     }
321
322     win_duplex = physDev->Devmode->dmPublic.dmFields & DM_DUPLEX ?
323         physDev->Devmode->dmPublic.dmDuplex : 0;
324     for(duplex = physDev->pi->ppd->Duplexes; duplex; duplex = duplex->next) {
325         if(duplex->WinDuplex == win_duplex) {
326             if(duplex->InvocationString) {
327                 PSDRV_WriteFeature(physDev->job.hJob, "*Duplex", duplex->Name,
328                              duplex->InvocationString);
329                 break;
330             }
331         }
332     }
333
334     WriteSpool16( physDev->job.hJob, (LPSTR)psendsetup, strlen(psendsetup) );
335
336
337     return 1;
338 }
339
340
341 INT PSDRV_WriteFooter( PSDRV_PDEVICE *physDev )
342 {
343     char *buf;
344
345     buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psfooter) + 100 );
346     if(!buf) {
347         WARN("HeapAlloc failed\n");
348         return 0;
349     }
350
351     sprintf(buf, psfooter, physDev->job.PageNo);
352
353     if( WriteSpool16( physDev->job.hJob, buf, strlen(buf) ) !=
354                                                      strlen(buf) ) {
355         WARN("WriteSpool error\n");
356         HeapFree( PSDRV_Heap, 0, buf );
357         return 0;
358     }
359     HeapFree( PSDRV_Heap, 0, buf );
360     return 1;
361 }
362
363
364
365 INT PSDRV_WriteEndPage( PSDRV_PDEVICE *physDev )
366 {
367     if( WriteSpool16( physDev->job.hJob, (LPSTR)psendpage, sizeof(psendpage)-1 ) !=
368                                                      sizeof(psendpage)-1 ) {
369         WARN("WriteSpool error\n");
370         return 0;
371     }
372     return 1;
373 }
374
375
376
377
378 INT PSDRV_WriteNewPage( PSDRV_PDEVICE *physDev )
379 {
380     char *buf;
381     char name[100];
382     signed int xtrans, ytrans, rotation;
383
384     sprintf(name, "%d", physDev->job.PageNo);
385
386     buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psnewpage) + 200 );
387     if(!buf) {
388         WARN("HeapAlloc failed\n");
389         return 0;
390     }
391
392     if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
393         if(physDev->pi->ppd->LandscapeOrientation == -90) {
394             xtrans = physDev->ImageableArea.right;
395             ytrans = physDev->ImageableArea.top;
396             rotation = 90;
397         } else {
398             xtrans = physDev->ImageableArea.left;
399             ytrans = physDev->ImageableArea.bottom;
400             rotation = -90;
401         }
402     } else {
403         xtrans = physDev->ImageableArea.left;
404         ytrans = physDev->ImageableArea.top;
405         rotation = 0;
406     }
407
408     sprintf(buf, psnewpage, name, physDev->job.PageNo,
409             physDev->logPixelsX, physDev->logPixelsY,
410             xtrans, ytrans, rotation);
411
412     if( WriteSpool16( physDev->job.hJob, buf, strlen(buf) ) !=
413                                                      strlen(buf) ) {
414         WARN("WriteSpool error\n");
415         HeapFree( PSDRV_Heap, 0, buf );
416         return 0;
417     }
418     HeapFree( PSDRV_Heap, 0, buf );
419     return 1;
420 }
421
422
423 BOOL PSDRV_WriteMoveTo(PSDRV_PDEVICE *physDev, INT x, INT y)
424 {
425     char buf[100];
426
427     sprintf(buf, psmoveto, x, y);
428     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
429 }
430
431 BOOL PSDRV_WriteLineTo(PSDRV_PDEVICE *physDev, INT x, INT y)
432 {
433     char buf[100];
434
435     sprintf(buf, pslineto, x, y);
436     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
437 }
438
439
440 BOOL PSDRV_WriteStroke(PSDRV_PDEVICE *physDev)
441 {
442     return PSDRV_WriteSpool(physDev, psstroke, sizeof(psstroke)-1);
443 }
444
445
446
447 BOOL PSDRV_WriteRectangle(PSDRV_PDEVICE *physDev, INT x, INT y, INT width,
448                         INT height)
449 {
450     char buf[100];
451
452     sprintf(buf, psrectangle, x, y, width, height, -width);
453     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
454 }
455
456 BOOL PSDRV_WriteRRectangle(PSDRV_PDEVICE *physDev, INT x, INT y, INT width,
457       INT height)
458 {
459     char buf[100];
460
461     sprintf(buf, psrrectangle, x, y, width, height, -width);
462     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
463 }
464
465 BOOL PSDRV_WriteArc(PSDRV_PDEVICE *physDev, INT x, INT y, INT w, INT h, double ang1,
466                       double ang2)
467 {
468     char buf[256];
469
470     /* Make angles -ve and swap order because we're working with an upside
471        down y-axis */
472     sprintf(buf, psarc, x, y, w, h, -ang2, -ang1);
473     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
474 }
475
476
477 BOOL PSDRV_WriteSetFont(PSDRV_PDEVICE *physDev, const char *name, INT size, INT escapement)
478 {
479     char *buf;
480
481     buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(pssetfont) +
482                              strlen(name) + 40);
483
484     if(!buf) {
485         WARN("HeapAlloc failed\n");
486         return FALSE;
487     }
488
489     sprintf(buf, pssetfont, name, size, -size, -escapement);
490
491     PSDRV_WriteSpool(physDev, buf, strlen(buf));
492     HeapFree(PSDRV_Heap, 0, buf);
493     return TRUE;
494 }
495
496 BOOL PSDRV_WriteSetColor(PSDRV_PDEVICE *physDev, PSCOLOR *color)
497 {
498     char buf[256];
499
500     PSDRV_CopyColor(&physDev->inkColor, color);
501     switch(color->type) {
502     case PSCOLOR_RGB:
503         sprintf(buf, pssetrgbcolor, color->value.rgb.r, color->value.rgb.g,
504                 color->value.rgb.b);
505         return PSDRV_WriteSpool(physDev, buf, strlen(buf));
506
507     case PSCOLOR_GRAY:
508         sprintf(buf, pssetgray, color->value.gray.i);
509         return PSDRV_WriteSpool(physDev, buf, strlen(buf));
510
511     default:
512         ERR("Unkonwn colour type %d\n", color->type);
513         break;
514     }
515
516     return FALSE;
517 }
518
519 BOOL PSDRV_WriteSetPen(PSDRV_PDEVICE *physDev)
520 {
521     char buf[256];
522
523     sprintf(buf, pssetlinewidth, physDev->pen.width);
524     PSDRV_WriteSpool(physDev, buf, strlen(buf));
525
526     if(physDev->pen.dash) {
527         sprintf(buf, pssetdash, physDev->pen.dash, 0);
528     }
529     else
530         sprintf(buf, pssetdash, "", 0);
531    
532    PSDRV_WriteSpool(physDev, buf, strlen(buf));
533         
534    return TRUE;
535 }
536
537 BOOL PSDRV_WriteGlyphShow(PSDRV_PDEVICE *physDev, LPCSTR g_name)
538 {
539     char    buf[128];
540     int     l;
541
542     l = snprintf(buf, sizeof(buf), psglyphshow, g_name);
543
544     if (l < sizeof(psglyphshow) - 2 || l > sizeof(buf) - 1) {
545         WARN("Unusable glyph name '%s' - ignoring\n", g_name);
546         return FALSE;
547     }
548
549     PSDRV_WriteSpool(physDev, buf, l);
550     return TRUE;
551 }
552
553 BOOL PSDRV_WriteFill(PSDRV_PDEVICE *physDev)
554 {
555     return PSDRV_WriteSpool(physDev, psfill, sizeof(psfill)-1);
556 }
557
558 BOOL PSDRV_WriteEOFill(PSDRV_PDEVICE *physDev)
559 {
560     return PSDRV_WriteSpool(physDev, pseofill, sizeof(pseofill)-1);
561 }
562
563 BOOL PSDRV_WriteGSave(PSDRV_PDEVICE *physDev)
564 {
565     return PSDRV_WriteSpool(physDev, psgsave, sizeof(psgsave)-1);
566 }
567
568 BOOL PSDRV_WriteGRestore(PSDRV_PDEVICE *physDev)
569 {
570     return PSDRV_WriteSpool(physDev, psgrestore, sizeof(psgrestore)-1);
571 }
572
573 BOOL PSDRV_WriteNewPath(PSDRV_PDEVICE *physDev)
574 {
575     return PSDRV_WriteSpool(physDev, psnewpath, sizeof(psnewpath)-1);
576 }
577
578 BOOL PSDRV_WriteClosePath(PSDRV_PDEVICE *physDev)
579 {
580     return PSDRV_WriteSpool(physDev, psclosepath, sizeof(psclosepath)-1);
581 }
582
583 BOOL PSDRV_WriteClip(PSDRV_PDEVICE *physDev)
584 {
585     return PSDRV_WriteSpool(physDev, psclip, sizeof(psclip)-1);
586 }
587
588 BOOL PSDRV_WriteEOClip(PSDRV_PDEVICE *physDev)
589 {
590     return PSDRV_WriteSpool(physDev, pseoclip, sizeof(pseoclip)-1);
591 }
592
593 BOOL PSDRV_WriteInitClip(PSDRV_PDEVICE *physDev)
594 {
595     return PSDRV_WriteSpool(physDev, psinitclip, sizeof(psinitclip)-1);
596 }
597
598 BOOL PSDRV_WriteHatch(PSDRV_PDEVICE *physDev)
599 {
600     return PSDRV_WriteSpool(physDev, pshatch, sizeof(pshatch)-1);
601 }
602
603 BOOL PSDRV_WriteRotate(PSDRV_PDEVICE *physDev, float ang)
604 {
605     char buf[256];
606
607     sprintf(buf, psrotate, ang);
608     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
609 }
610
611 BOOL PSDRV_WriteIndexColorSpaceBegin(PSDRV_PDEVICE *physDev, int size)
612 {
613     char buf[256];
614     sprintf(buf, "[/Indexed /DeviceRGB %d\n<\n", size);
615     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
616 }
617
618 BOOL PSDRV_WriteIndexColorSpaceEnd(PSDRV_PDEVICE *physDev)
619 {
620     static const char buf[] = ">\n] setcolorspace\n";
621     return PSDRV_WriteSpool(physDev, buf, sizeof(buf) - 1);
622 }
623
624 BOOL PSDRV_WriteRGB(PSDRV_PDEVICE *physDev, COLORREF *map, int number)
625 {
626     char *buf = HeapAlloc(PSDRV_Heap, 0, number * 7 + 1), *ptr;
627     int i;
628
629     ptr = buf;
630     for(i = 0; i < number; i++) {
631         sprintf(ptr, "%02x%02x%02x%c", (int)GetRValue(map[i]),
632                 (int)GetGValue(map[i]), (int)GetBValue(map[i]),
633                 ((i & 0x7) == 0x7) || (i == number - 1) ? '\n' : ' ');
634         ptr += 7;
635     }
636     PSDRV_WriteSpool(physDev, buf, number * 7);
637     HeapFree(PSDRV_Heap, 0, buf);
638     return TRUE;
639 }
640
641
642 BOOL PSDRV_WriteImageDict(PSDRV_PDEVICE *physDev, WORD depth, INT xDst, INT yDst,
643                           INT widthDst, INT heightDst, INT widthSrc,
644                           INT heightSrc, char *bits, BOOL mask)
645 {
646     static const char start[] = "%d %d translate\n%d %d scale\n<<\n"
647       " /ImageType 1\n /Width %d\n /Height %d\n /BitsPerComponent %d\n"
648       " /ImageMatrix [%d 0 0 %d 0 %d]\n";
649
650     static const char decode1[] = " /Decode [0 %d]\n";
651     static const char decode3[] = " /Decode [0 1 0 1 0 1]\n";
652
653     static const char end[] = " /DataSource currentfile /ASCII85Decode filter /RunLengthDecode filter\n>> image\n";
654     static const char endmask[] = " /DataSource currentfile /ASCII85Decode filter /RunLengthDecode filter\n>> imagemask\n";
655
656     static const char endbits[] = " /DataSource <%s>\n>> image\n";
657
658     char *buf = HeapAlloc(PSDRV_Heap, 0, 1000);
659
660     sprintf(buf, start, xDst, yDst, widthDst, heightDst, widthSrc, heightSrc,
661             (depth < 8) ? depth : 8, widthSrc, -heightSrc, heightSrc);
662
663     PSDRV_WriteSpool(physDev, buf, strlen(buf));
664
665     switch(depth) {
666     case 8:
667         sprintf(buf, decode1, 255);
668         break;
669
670     case 4:
671         sprintf(buf, decode1, 15);
672         break;
673
674     case 1:
675         sprintf(buf, decode1, 1);
676         break;
677
678     default:
679         strcpy(buf, decode3);
680         break;
681     }
682
683     PSDRV_WriteSpool(physDev, buf, strlen(buf));
684
685     if(!bits) {
686         if(!mask)
687             PSDRV_WriteSpool(physDev, end, sizeof(end) - 1);
688         else
689             PSDRV_WriteSpool(physDev, endmask, sizeof(endmask) - 1);
690     } else {
691         sprintf(buf, endbits, bits);
692         PSDRV_WriteSpool(physDev, buf, strlen(buf));
693     }
694
695     HeapFree(PSDRV_Heap, 0, buf);
696     return TRUE;
697 }
698
699
700 BOOL PSDRV_WriteBytes(PSDRV_PDEVICE *physDev, const BYTE *bytes, DWORD number)
701 {
702     char *buf = HeapAlloc(PSDRV_Heap, 0, number * 3 + 1);
703     char *ptr;
704     int i;
705
706     ptr = buf;
707
708     for(i = 0; i < number; i++) {
709         sprintf(ptr, "%02x", bytes[i]);
710         ptr += 2;
711         if(((i & 0xf) == 0xf) || (i == number - 1)) {
712             strcpy(ptr, "\n");
713             ptr++;
714         }
715     }
716     PSDRV_WriteSpool(physDev, buf, ptr - buf);
717     HeapFree(PSDRV_Heap, 0, buf);
718     return TRUE;
719 }
720
721 BOOL PSDRV_WriteData(PSDRV_PDEVICE *physDev, const BYTE *data, DWORD number)
722 {
723     int num, num_left = number;
724
725     do {
726         num = min(num_left, 60);
727         PSDRV_WriteSpool(physDev, data, num);
728         PSDRV_WriteSpool(physDev, "\n", 1);
729         data += num;
730         num_left -= num;
731     } while(num_left);
732
733     return TRUE;
734 }
735
736 BOOL PSDRV_WriteArrayGet(PSDRV_PDEVICE *physDev, CHAR *pszArrayName, INT nIndex)
737 {
738     char buf[100];
739
740     sprintf(buf, psarrayget, pszArrayName, nIndex);
741     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
742 }
743
744 BOOL PSDRV_WriteArrayPut(PSDRV_PDEVICE *physDev, CHAR *pszArrayName, INT nIndex, LONG lObject)
745 {
746     char buf[100];
747
748     sprintf(buf, psarrayput, pszArrayName, nIndex, lObject);
749     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
750 }
751
752 BOOL PSDRV_WriteArrayDef(PSDRV_PDEVICE *physDev, CHAR *pszArrayName, INT nSize)
753 {
754     char buf[100];
755
756     sprintf(buf, psarraydef, pszArrayName, nSize);
757     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
758 }
759
760 BOOL PSDRV_WriteRectClip(PSDRV_PDEVICE *physDev, INT x, INT y, INT w, INT h)
761 {
762     char buf[100];
763
764     sprintf(buf, psrectclip, x, y, w, h);
765     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
766 }
767
768 BOOL PSDRV_WriteRectClip2(PSDRV_PDEVICE *physDev, CHAR *pszArrayName)
769 {
770     char buf[100];
771
772     sprintf(buf, psrectclip2, pszArrayName);
773     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
774 }
775
776 BOOL PSDRV_WritePatternDict(PSDRV_PDEVICE *physDev, BITMAP *bm, BYTE *bits)
777 {
778     static const char start[] = "<<\n /PaintType 1\n /PatternType 1\n /TilingType 1\n "
779       "/BBox [0 0 %d %d]\n /XStep %d\n /YStep %d\n /PaintProc {\n  begin\n";
780
781     static const char end[] = "  end\n }\n>>\n matrix makepattern setpattern\n";
782     char *buf, *ptr;
783     INT w, h, x, y;
784     COLORREF map[2];
785
786     w = bm->bmWidth & ~0x7;
787     h = bm->bmHeight & ~0x7;
788
789     buf = HeapAlloc(PSDRV_Heap, 0, sizeof(start) + 100);
790     sprintf(buf, start, w, h, w, h);
791     PSDRV_WriteSpool(physDev,  buf, strlen(buf));
792     PSDRV_WriteIndexColorSpaceBegin(physDev, 1);
793     map[0] = GetTextColor( physDev->hdc );
794     map[1] = GetBkColor( physDev->hdc );
795     PSDRV_WriteRGB(physDev, map, 2);
796     PSDRV_WriteIndexColorSpaceEnd(physDev);
797     ptr = buf;
798     for(y = h-1; y >= 0; y--) {
799         for(x = 0; x < w/8; x++) {
800             sprintf(ptr, "%02x", *(bits + x/8 + y * bm->bmWidthBytes));
801             ptr += 2;
802         }
803     }
804     PSDRV_WriteImageDict(physDev, 1, 0, 0, 8, 8, 8, 8, buf, FALSE);
805     PSDRV_WriteSpool(physDev, end, sizeof(end) - 1);
806     HeapFree(PSDRV_Heap, 0, buf);
807     return TRUE;
808 }
809
810 BOOL PSDRV_WriteDIBPatternDict(PSDRV_PDEVICE *physDev, BITMAPINFO *bmi, UINT usage)
811 {
812     static const char start[] = "<<\n /PaintType 1\n /PatternType 1\n /TilingType 1\n "
813       "/BBox [0 0 %d %d]\n /XStep %d\n /YStep %d\n /PaintProc {\n  begin\n";
814
815     static const char end[] = "  end\n }\n>>\n matrix makepattern setpattern\n";
816     char *buf, *ptr;
817     BYTE *bits;
818     INT w, h, x, y, colours;
819     COLORREF map[2];
820
821     if(bmi->bmiHeader.biBitCount != 1) {
822         FIXME("dib depth %d not supported\n", bmi->bmiHeader.biBitCount);
823         return FALSE;
824     }
825
826     bits = (char*)bmi + bmi->bmiHeader.biSize;
827     colours = bmi->bmiHeader.biClrUsed;
828     if(!colours && bmi->bmiHeader.biBitCount <= 8)
829         colours = 1 << bmi->bmiHeader.biBitCount;
830     bits += colours * ((usage == DIB_RGB_COLORS) ?
831                        sizeof(RGBQUAD) : sizeof(WORD));
832
833     w = bmi->bmiHeader.biWidth & ~0x7;
834     h = bmi->bmiHeader.biHeight & ~0x7;
835
836     buf = HeapAlloc(PSDRV_Heap, 0, sizeof(start) + 100);
837     sprintf(buf, start, w, h, w, h);
838     PSDRV_WriteSpool(physDev,  buf, strlen(buf));
839     PSDRV_WriteIndexColorSpaceBegin(physDev, 1);
840     map[0] = GetTextColor( physDev->hdc );
841     map[1] = GetBkColor( physDev->hdc );
842     PSDRV_WriteRGB(physDev, map, 2);
843     PSDRV_WriteIndexColorSpaceEnd(physDev);
844     ptr = buf;
845     for(y = h-1; y >= 0; y--) {
846         for(x = 0; x < w/8; x++) {
847             sprintf(ptr, "%02x", *(bits + x/8 + y *
848                                    (bmi->bmiHeader.biWidth + 31) / 32 * 4));
849             ptr += 2;
850         }
851     }
852     PSDRV_WriteImageDict(physDev, 1, 0, 0, 8, 8, 8, 8, buf, FALSE);
853     PSDRV_WriteSpool(physDev, end, sizeof(end) - 1);
854     HeapFree(PSDRV_Heap, 0, buf);
855     return TRUE;
856 }