Update shell xxxAW wrapper prototypes for fixed SHLWAPI functions.
[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(DC *dc, LPSTR lpData, WORD cch)
192 {
193     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
194
195     if(physDev->job.OutOfPage) { /* Will get here after NEWFRAME Escape */
196         if( !PSDRV_StartPage(dc) )
197             return FALSE;
198     }
199     return WriteSpool16( physDev->job.hJob, lpData, cch );
200 }
201
202
203 INT PSDRV_WriteFeature(HANDLE16 hJob, char *feature, char *value,
204                          char *invocation)
205 {
206
207     char *buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psbeginfeature) +
208                                    strlen(feature) + strlen(value));
209
210
211     sprintf(buf, psbeginfeature, feature, value);
212     WriteSpool16( hJob, buf, strlen(buf) );
213
214     WriteSpool16( hJob, invocation, strlen(invocation) );
215
216     WriteSpool16( hJob, psendfeature, strlen(psendfeature) );
217     
218     HeapFree( PSDRV_Heap, 0, buf );
219     return 1;
220 }
221
222
223
224 INT PSDRV_WriteHeader( DC *dc, LPCSTR title )
225 {
226     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
227     char *buf, *orient;
228     INPUTSLOT *slot;
229     PAGESIZE *page;
230     int llx, lly, urx, ury;
231
232     TRACE("'%s'\n", title);
233
234     buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psheader) +
235                              strlen(title) + 30 );
236     if(!buf) {
237         WARN("HeapAlloc failed\n");
238         return 0;
239     }
240     
241     /* BBox co-ords are in default user co-ord system so urx < ury even in
242        landscape mode */
243     llx = physDev->PageSize.left * 72.0 / physDev->logPixelsX;
244     lly = physDev->PageSize.bottom * 72.0 / physDev->logPixelsY;
245     urx = physDev->PageSize.right * 72.0 / physDev->logPixelsX;
246     ury = physDev->PageSize.top * 72.0 / physDev->logPixelsY;
247
248     if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
249         orient = "Landscape";
250     } else {
251         orient = "Portrait";
252     }
253
254     /* FIXME should do something better with BBox */
255
256     sprintf(buf, psheader, title, llx, lly, urx, ury, orient);          
257
258     if( WriteSpool16( physDev->job.hJob, buf, strlen(buf) ) != 
259                                                      strlen(buf) ) {
260         WARN("WriteSpool error\n");
261         HeapFree( PSDRV_Heap, 0, buf );
262         return 0;
263     }
264     HeapFree( PSDRV_Heap, 0, buf );
265
266     WriteSpool16( physDev->job.hJob, psbeginprolog, strlen(psbeginprolog) );
267     WriteSpool16( physDev->job.hJob, psprolog, strlen(psprolog) );
268     WriteSpool16( physDev->job.hJob, psendprolog, strlen(psendprolog) );
269
270     WriteSpool16( physDev->job.hJob, psbeginsetup, strlen(psbeginsetup) );
271
272     for(slot = physDev->pi->ppd->InputSlots; slot; slot = slot->next) {
273         if(slot->WinBin == physDev->Devmode->dmPublic.dmDefaultSource) {
274             if(slot->InvocationString) {
275                 PSDRV_WriteFeature(physDev->job.hJob, "*InputSlot", slot->Name,
276                              slot->InvocationString);
277                 break;
278             }
279         }
280     }
281
282     for(page = physDev->pi->ppd->PageSizes; page; page = page->next) {
283         if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize) {
284             if(page->InvocationString) {
285                 PSDRV_WriteFeature(physDev->job.hJob, "*PageSize", page->Name,
286                              page->InvocationString);
287                 break;
288             }
289         }
290     }
291
292     WriteSpool16( physDev->job.hJob, psendsetup, strlen(psendsetup) );
293
294
295     return 1;
296 }
297
298
299 INT PSDRV_WriteFooter( DC *dc )
300 {
301     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
302     char *buf;
303
304     buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psfooter) + 100 );
305     if(!buf) {
306         WARN("HeapAlloc failed\n");
307         return 0;
308     }
309
310     sprintf(buf, psfooter, physDev->job.PageNo);
311
312     if( WriteSpool16( physDev->job.hJob, buf, strlen(buf) ) != 
313                                                      strlen(buf) ) {
314         WARN("WriteSpool error\n");
315         HeapFree( PSDRV_Heap, 0, buf );
316         return 0;
317     }
318     HeapFree( PSDRV_Heap, 0, buf );
319     return 1;
320 }
321
322
323
324 INT PSDRV_WriteEndPage( DC *dc )
325 {
326     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
327
328     if( WriteSpool16( physDev->job.hJob, psendpage, sizeof(psendpage)-1 ) != 
329                                                      sizeof(psendpage)-1 ) {
330         WARN("WriteSpool error\n");
331         return 0;
332     }
333     return 1;
334 }
335
336
337
338
339 INT PSDRV_WriteNewPage( DC *dc )
340 {
341     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
342     char *buf;
343     char name[100];
344     signed int xtrans, ytrans, rotation;
345
346     sprintf(name, "%d", physDev->job.PageNo);
347
348     buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psnewpage) + 200 );
349     if(!buf) {
350         WARN("HeapAlloc failed\n");
351         return 0;
352     }
353
354     if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
355         if(physDev->pi->ppd->LandscapeOrientation == -90) {
356             xtrans = physDev->PageSize.right;
357             ytrans = physDev->PageSize.top;
358             rotation = 90;
359         } else {
360             xtrans = physDev->PageSize.left;
361             ytrans = physDev->PageSize.bottom;
362             rotation = -90;
363         }
364     } else {
365         xtrans = physDev->PageSize.left;
366         ytrans = physDev->PageSize.top;
367         rotation = 0;
368     }
369
370     sprintf(buf, psnewpage, name, physDev->job.PageNo,
371             physDev->logPixelsX, physDev->logPixelsY,
372             xtrans, ytrans, rotation);
373
374     if( WriteSpool16( physDev->job.hJob, buf, strlen(buf) ) != 
375                                                      strlen(buf) ) {
376         WARN("WriteSpool error\n");
377         HeapFree( PSDRV_Heap, 0, buf );
378         return 0;
379     }
380     HeapFree( PSDRV_Heap, 0, buf );
381     return 1;
382 }
383
384
385 BOOL PSDRV_WriteMoveTo(DC *dc, INT x, INT y)
386 {
387     char buf[100];
388
389     sprintf(buf, psmoveto, x, y);
390     return PSDRV_WriteSpool(dc, buf, strlen(buf));
391 }
392
393 BOOL PSDRV_WriteLineTo(DC *dc, INT x, INT y)
394 {
395     char buf[100];
396
397     sprintf(buf, pslineto, x, y);
398     return PSDRV_WriteSpool(dc, buf, strlen(buf));
399 }
400
401
402 BOOL PSDRV_WriteStroke(DC *dc)
403 {
404     return PSDRV_WriteSpool(dc, psstroke, sizeof(psstroke)-1);
405 }
406
407
408
409 BOOL PSDRV_WriteRectangle(DC *dc, INT x, INT y, INT width, 
410                         INT height)
411 {
412     char buf[100];
413
414     sprintf(buf, psrectangle, x, y, width, height, -width);
415     return PSDRV_WriteSpool(dc, buf, strlen(buf));
416 }
417
418 BOOL PSDRV_WriteRRectangle(DC *dc, INT x, INT y, INT width,
419       INT height)
420 {
421     char buf[100];
422
423     sprintf(buf, psrrectangle, x, y, width, height, -width);
424     return PSDRV_WriteSpool(dc, buf, strlen(buf));
425 }
426
427 BOOL PSDRV_WriteArc(DC *dc, INT x, INT y, INT w, INT h, double ang1,
428                       double ang2)
429 {
430     char buf[256];
431
432     /* Make angles -ve and swap order because we're working with an upside
433        down y-axis */
434     sprintf(buf, psarc, x, y, w, h, -ang2, -ang1);
435     return PSDRV_WriteSpool(dc, buf, strlen(buf));
436 }
437
438 BOOL PSDRV_WriteSetFont(DC *dc)
439 {
440     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
441     char *buf;
442
443     buf = (char *)HeapAlloc( PSDRV_Heap, 0,
444              sizeof(pssetfont) + strlen(physDev->font.afm->FontName) + 40);
445
446     if(!buf) {
447         WARN("HeapAlloc failed\n");
448         return FALSE;
449     }
450     
451     sprintf(buf, pssetfont, physDev->font.afm->FontName, 
452                 physDev->font.size, -physDev->font.size,
453                 -physDev->font.escapement);
454
455     PSDRV_WriteSpool(dc, buf, strlen(buf));
456     HeapFree(PSDRV_Heap, 0, buf);
457     return TRUE;
458 }    
459
460 BOOL PSDRV_WriteSetColor(DC *dc, PSCOLOR *color)
461 {
462     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
463     char buf[256];
464
465     PSDRV_CopyColor(&physDev->inkColor, color);
466     switch(color->type) {
467     case PSCOLOR_RGB:
468         sprintf(buf, pssetrgbcolor, color->value.rgb.r, color->value.rgb.g,
469                 color->value.rgb.b);
470         return PSDRV_WriteSpool(dc, buf, strlen(buf));
471
472     case PSCOLOR_GRAY:  
473         sprintf(buf, pssetgray, color->value.gray.i);
474         return PSDRV_WriteSpool(dc, buf, strlen(buf));
475         
476     default:
477         ERR("Unkonwn colour type %d\n", color->type);
478         break;
479     }
480
481     return FALSE;
482 }
483
484 BOOL PSDRV_WriteSetPen(DC *dc)
485 {
486     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
487     char buf[256];
488
489     sprintf(buf, pssetlinewidth, physDev->pen.width);
490     PSDRV_WriteSpool(dc, buf, strlen(buf));
491
492     if(physDev->pen.dash) {
493         sprintf(buf, pssetdash, physDev->pen.dash, 0);
494         PSDRV_WriteSpool(dc, buf, strlen(buf));
495     }
496
497     return TRUE;
498 }
499
500 BOOL PSDRV_WriteGlyphShow(DC *dc, LPCWSTR str, INT count)
501 {
502     char    buf[128];
503     int     i;
504     
505     for (i = 0; i < count; ++i)
506     {
507         LPCSTR  name;
508         int     l;
509         
510         name = PSDRV_UVMetrics(str[i],
511                 ((PSDRV_PDEVICE *)dc->physDev)->font.afm)->N->sz;
512         l = snprintf(buf, sizeof(buf), psglyphshow, name);
513         
514         if (l < sizeof(psglyphshow) - 2 || l > sizeof(buf) - 1)
515         {
516             WARN("Unusable glyph name '%s' - ignoring\n", name);
517             continue;
518         }
519         
520         PSDRV_WriteSpool(dc, buf, l);
521     }
522     
523     return TRUE;
524 }
525
526 BOOL PSDRV_WriteFill(DC *dc)
527 {
528     return PSDRV_WriteSpool(dc, psfill, sizeof(psfill)-1);
529 }
530
531 BOOL PSDRV_WriteEOFill(DC *dc)
532 {
533     return PSDRV_WriteSpool(dc, pseofill, sizeof(pseofill)-1);
534 }
535
536 BOOL PSDRV_WriteGSave(DC *dc)
537 {
538     return PSDRV_WriteSpool(dc, psgsave, sizeof(psgsave)-1);
539 }
540
541 BOOL PSDRV_WriteGRestore(DC *dc)
542 {
543     return PSDRV_WriteSpool(dc, psgrestore, sizeof(psgrestore)-1);
544 }
545
546 BOOL PSDRV_WriteNewPath(DC *dc)
547 {
548     return PSDRV_WriteSpool(dc, psnewpath, sizeof(psnewpath)-1);
549 }
550
551 BOOL PSDRV_WriteClosePath(DC *dc)
552 {
553     return PSDRV_WriteSpool(dc, psclosepath, sizeof(psclosepath)-1);
554 }
555
556 BOOL PSDRV_WriteClip(DC *dc)
557 {
558     return PSDRV_WriteSpool(dc, psclip, sizeof(psclip)-1);
559 }
560
561 BOOL PSDRV_WriteEOClip(DC *dc)
562 {
563     return PSDRV_WriteSpool(dc, pseoclip, sizeof(pseoclip)-1);
564 }
565
566 BOOL PSDRV_WriteInitClip(DC *dc)
567 {
568     return PSDRV_WriteSpool(dc, psinitclip, sizeof(psinitclip)-1);
569 }
570
571 BOOL PSDRV_WriteHatch(DC *dc)
572 {
573     return PSDRV_WriteSpool(dc, pshatch, sizeof(pshatch)-1);
574 }
575
576 BOOL PSDRV_WriteRotate(DC *dc, float ang)
577 {
578     char buf[256];
579
580     sprintf(buf, psrotate, ang);
581     return PSDRV_WriteSpool(dc, buf, strlen(buf));
582 }
583
584 BOOL PSDRV_WriteIndexColorSpaceBegin(DC *dc, int size)
585 {
586     char buf[256];
587     sprintf(buf, "[/Indexed /DeviceRGB %d\n<\n", size);
588     return PSDRV_WriteSpool(dc, buf, strlen(buf));
589 }
590
591 BOOL PSDRV_WriteIndexColorSpaceEnd(DC *dc)
592 {
593     char buf[] = ">\n] setcolorspace\n";
594     return PSDRV_WriteSpool(dc, buf, sizeof(buf) - 1);
595
596
597 BOOL PSDRV_WriteRGB(DC *dc, COLORREF *map, int number)
598 {
599     char *buf = HeapAlloc(PSDRV_Heap, 0, number * 7 + 1), *ptr;
600     int i;
601
602     ptr = buf;
603     for(i = 0; i < number; i++) {
604         sprintf(ptr, "%02x%02x%02x%c", (int)GetRValue(map[i]), 
605                 (int)GetGValue(map[i]), (int)GetBValue(map[i]),
606                 ((i & 0x7) == 0x7) || (i == number - 1) ? '\n' : ' ');
607         ptr += 7;
608     }
609     PSDRV_WriteSpool(dc, buf, number * 7);
610     HeapFree(PSDRV_Heap, 0, buf);
611     return TRUE;
612 }
613
614
615 BOOL PSDRV_WriteImageDict(DC *dc, WORD depth, INT xDst, INT yDst,
616                           INT widthDst, INT heightDst, INT widthSrc,
617                           INT heightSrc, char *bits)
618 {
619     char start[] = "%d %d translate\n%d %d scale\n<<\n"
620       " /ImageType 1\n /Width %d\n /Height %d\n /BitsPerComponent %d\n"
621       " /ImageMatrix [%d 0 0 %d 0 %d]\n";
622
623     char decode1[] = " /Decode [0 %d]\n";
624     char decode3[] = " /Decode [0 1 0 1 0 1]\n";
625
626     char end[] = " /DataSource currentfile /ASCIIHexDecode filter\n>> image\n";
627     char endbits[] = " /DataSource <%s>\n>> image\n";
628
629     char *buf = HeapAlloc(PSDRV_Heap, 0, 1000);
630
631     sprintf(buf, start, xDst, yDst, widthDst, heightDst, widthSrc, heightSrc,
632             (depth < 8) ? depth : 8, widthSrc, -heightSrc, heightSrc);
633
634     PSDRV_WriteSpool(dc, buf, strlen(buf));
635
636     switch(depth) {
637     case 8:
638         sprintf(buf, decode1, 255);
639         break;
640
641     case 4:
642         sprintf(buf, decode1, 15);
643         break;
644
645     case 1:
646         sprintf(buf, decode1, 1);
647         break;
648
649     default:
650         strcpy(buf, decode3);
651         break;
652     }
653
654     PSDRV_WriteSpool(dc, buf, strlen(buf));
655
656     if(!bits)
657         PSDRV_WriteSpool(dc, end, sizeof(end) - 1);
658     else {
659         sprintf(buf, endbits, bits);
660         PSDRV_WriteSpool(dc, buf, strlen(buf));
661     }
662
663     HeapFree(PSDRV_Heap, 0, buf);
664     return TRUE;
665 }
666
667
668 BOOL PSDRV_WriteBytes(DC *dc, const BYTE *bytes, int number)
669 {
670     char *buf = HeapAlloc(PSDRV_Heap, 0, number * 3 + 1);
671     char *ptr;
672     int i;
673     
674     ptr = buf;
675     
676     for(i = 0; i < number; i++) {
677         sprintf(ptr, "%02x%c", bytes[i],
678                 ((i & 0xf) == 0xf) || (i == number - 1) ? '\n' : ' ');
679         ptr += 3;
680     }
681     PSDRV_WriteSpool(dc, buf, number * 3);
682
683     HeapFree(PSDRV_Heap, 0, buf);
684     return TRUE;
685 }
686
687 BOOL PSDRV_WriteDIBits16(DC *dc, const WORD *words, int number)
688 {
689     char *buf = HeapAlloc(PSDRV_Heap, 0, number * 7 + 1);
690     char *ptr;
691     int i;
692     
693     ptr = buf;
694     
695     for(i = 0; i < number; i++) {
696         int r, g, b;
697
698         /* We want 0x0 -- 0x1f to map to 0x0 -- 0xff */
699
700         r = words[i] >> 10 & 0x1f;
701         r = r << 3 | r >> 2;
702         g = words[i] >> 5 & 0x1f;
703         g = g << 3 | g >> 2;
704         b = words[i] & 0x1f;
705         b = b << 3 | b >> 2;
706         sprintf(ptr, "%02x%02x%02x%c", r, g, b,
707                 ((i & 0x7) == 0x7) || (i == number - 1) ? '\n' : ' ');
708         ptr += 7;
709     }
710     PSDRV_WriteSpool(dc, buf, number * 7);
711
712     HeapFree(PSDRV_Heap, 0, buf);
713     return TRUE;
714 }
715
716 BOOL PSDRV_WriteDIBits24(DC *dc, const BYTE *bits, int number)
717 {
718     char *buf = HeapAlloc(PSDRV_Heap, 0, number * 7 + 1);
719     char *ptr;
720     int i;
721     
722     ptr = buf;
723     
724     for(i = 0; i < number; i++) {
725         sprintf(ptr, "%02x%02x%02x%c", bits[i * 3 + 2], bits[i * 3 + 1],
726                 bits[i * 3],
727                 ((i & 0x7) == 0x7) || (i == number - 1) ? '\n' : ' ');
728         ptr += 7;
729     }
730     PSDRV_WriteSpool(dc, buf, number * 7);
731
732     HeapFree(PSDRV_Heap, 0, buf);
733     return TRUE;
734 }
735
736 BOOL PSDRV_WriteDIBits32(DC *dc, const BYTE *bits, int number)
737 {
738     char *buf = HeapAlloc(PSDRV_Heap, 0, number * 7 + 1);
739     char *ptr;
740     int i;
741     
742     ptr = buf;
743     
744     for(i = 0; i < number; i++) {
745         sprintf(ptr, "%02x%02x%02x%c", bits[i * 4 + 2], bits[i * 4 + 1],
746                 bits[i * 4],
747                 ((i & 0x7) == 0x7) || (i == number - 1) ? '\n' : ' ');
748         ptr += 7;
749     }
750     PSDRV_WriteSpool(dc, buf, number * 7);
751
752     HeapFree(PSDRV_Heap, 0, buf);
753     return TRUE;
754 }
755
756 BOOL PSDRV_WriteArrayGet(DC *dc, CHAR *pszArrayName, INT nIndex)
757 {
758     char buf[100];
759
760     sprintf(buf, psarrayget, pszArrayName, nIndex);
761     return PSDRV_WriteSpool(dc, buf, strlen(buf));
762 }
763
764 BOOL PSDRV_WriteArrayPut(DC *dc, CHAR *pszArrayName, INT nIndex, LONG lObject)
765 {
766     char buf[100];
767
768     sprintf(buf, psarrayput, pszArrayName, nIndex, lObject);
769     return PSDRV_WriteSpool(dc, buf, strlen(buf));
770 }
771
772 BOOL PSDRV_WriteArrayDef(DC *dc, CHAR *pszArrayName, INT nSize)
773 {
774     char buf[100];
775
776     sprintf(buf, psarraydef, pszArrayName, nSize);
777     return PSDRV_WriteSpool(dc, buf, strlen(buf));
778 }
779
780 BOOL PSDRV_WriteRectClip(DC *dc, INT x, INT y, INT w, INT h)
781 {
782     char buf[100];
783
784     sprintf(buf, psrectclip, x, y, w, h);
785     return PSDRV_WriteSpool(dc, buf, strlen(buf));
786 }
787
788 BOOL PSDRV_WriteRectClip2(DC *dc, CHAR *pszArrayName)
789 {
790     char buf[100];
791
792     sprintf(buf, psrectclip2, pszArrayName);
793     return PSDRV_WriteSpool(dc, buf, strlen(buf));
794 }
795
796 BOOL PSDRV_WritePatternDict(DC *dc, BITMAP *bm, BYTE *bits)
797 {
798     char start[] = "<<\n /PaintType 1\n /PatternType 1\n /TilingType 1\n "
799       "/BBox [0 0 %d %d]\n /XStep %d\n /YStep %d\n /PaintProc {\n  begin\n";
800
801     char end[] = "  end\n }\n>>\n matrix makepattern setpattern\n";
802     char *buf, *ptr;
803     INT w, h, x, y;
804     COLORREF map[2];
805
806     w = bm->bmWidth & ~0x7;
807     h = bm->bmHeight & ~0x7;
808
809     buf = HeapAlloc(PSDRV_Heap, 0, sizeof(start) + 100);
810     sprintf(buf, start, w, h, w, h);
811     PSDRV_WriteSpool(dc,  buf, strlen(buf));
812     PSDRV_WriteIndexColorSpaceBegin(dc, 1);
813     map[0] = dc->textColor;
814     map[1] = dc->backgroundColor;
815     PSDRV_WriteRGB(dc, map, 2);
816     PSDRV_WriteIndexColorSpaceEnd(dc);
817     ptr = buf;
818     for(y = h-1; y >= 0; y--) {
819         for(x = 0; x < w/8; x++) {
820             sprintf(ptr, "%02x", *(bits + x/8 + y * bm->bmWidthBytes));
821             ptr += 2;
822         }
823     }
824     PSDRV_WriteImageDict(dc, 1, 0, 0, 8, 8, 8, 8, buf);
825     PSDRV_WriteSpool(dc, end, sizeof(end) - 1);
826     HeapFree(PSDRV_Heap, 0, buf);
827     return TRUE;
828 }