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