1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  * Copyright (C) 2016 Mopria Alliance, Inc.
4  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "../../media.h"
20 #include <PCLmGenerator.h>
21 
22 #include <assert.h>
23 #include <math.h>
24 #include <zlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <genPCLm.h>
29 
30 #define TAG "genPCLm"
31 
32 #define STRIP_HEIGHT 16
33 #define JPEG_QUALITY 100
34 #define TEMP_BUFF_SIZE 10000000
35 #define DEFAULT_OUTBUFF_SIZE 64*5120*3*10
36 #define STANDARD_SCALE_FOR_PDF 72.0
37 #define KID_STRING_SIZE 1000
38 #define CATALOG_OBJ_NUMBER 1
39 #define PAGES_OBJ_NUMBER   2
40 #define ADOBE_RGB_SIZE 284
41 
42 #define rgb_2_gray(r, g, b) (ubyte)(0.299*(double)r+0.587*(double)g+0.114*(double)b)
43 
44 static PCLmSUserSettingsType PCLmSSettings;
45 
46 /*
47  * Shift the strip image right in the strip buffer by leftMargin pixels.
48  *
49  * Assumptions: The strip buffer was allocated large enough to handle the shift; if not
50  * then the image data on the right will get clipped.
51  *
52  * We allocate a full strip (height and width), but then only copy numLinesThisCall from
53  * the original buffer to the newly allocated buffer.  This pads the strips for JPEG processing.
54  */
shiftStripByLeftMargin(ubyte * ptrToStrip,sint32 currSourceWidth,sint32 currStripHeight,sint32 numLinesThisCall,sint32 currMediaWidth,sint32 leftMargin,colorSpaceDisposition destColorSpace)55 static ubyte *shiftStripByLeftMargin(ubyte *ptrToStrip, sint32 currSourceWidth,
56         sint32 currStripHeight, sint32 numLinesThisCall, sint32 currMediaWidth, sint32 leftMargin,
57         colorSpaceDisposition destColorSpace) {
58     ubyte *fromPtr, *toPtr, *newStrip;
59     sint32 scanLineWidth;
60 
61     if (destColorSpace == grayScale) {
62         scanLineWidth = currMediaWidth;
63 
64         // Allocate a full strip
65         newStrip = (ubyte *) malloc(scanLineWidth * currStripHeight);
66         memset(newStrip, 0xff, scanLineWidth * currStripHeight);
67         for (int i = 0; i < numLinesThisCall; i++) {
68             toPtr = newStrip + leftMargin + (i * currMediaWidth);
69             fromPtr = ptrToStrip + (i * currSourceWidth);
70             memcpy(toPtr, fromPtr, currSourceWidth);
71         }
72     } else {
73         scanLineWidth = currMediaWidth * 3;
74         sint32 srcScanlineWidth = currSourceWidth * 3;
75         sint32 shiftAmount = leftMargin * 3;
76         newStrip = (ubyte *) malloc(scanLineWidth * currStripHeight);
77         memset(newStrip, 0xff, scanLineWidth * currStripHeight);
78         for (int i = 0; i < numLinesThisCall; i++) {
79             toPtr = newStrip + shiftAmount + (i * scanLineWidth);
80             fromPtr = ptrToStrip + (i * srcScanlineWidth);
81             memcpy(toPtr, fromPtr, srcScanlineWidth);
82         }
83     }
84 
85     return newStrip;
86 }
87 
88 #ifdef SUPPORT_WHITE_STRIPS
89 
isWhiteStrip(void * pInBuffer,int inBufferSize)90 bool PCLmGenerator::isWhiteStrip(void *pInBuffer, int inBufferSize) {
91     uint32 *ptr = (uint32 *) pInBuffer;
92     for (int i = 0; i < inBufferSize / 4; i++, ptr++) {
93         if (*ptr != 0xffffffff) {
94             return false;
95         }
96     }
97     return true;
98 }
99 
100 #endif
101 
Cleanup(void)102 void PCLmGenerator::Cleanup(void) {
103     if (allocatedOutputBuffer) {
104         free(allocatedOutputBuffer);
105         allocatedOutputBuffer = NULL;
106         currOutBuffSize = 0;
107     }
108 
109     if (leftoverScanlineBuffer) {
110         free(leftoverScanlineBuffer);
111         leftoverScanlineBuffer = NULL;
112     }
113     if (scratchBuffer) {
114         free(scratchBuffer);
115         scratchBuffer = NULL;
116     }
117     if (xRefTable) {
118         free(xRefTable);
119         xRefTable = NULL;
120     }
121     if (KidsArray) {
122         free(KidsArray);
123         KidsArray = NULL;
124     }
125 }
126 
errorOutAndCleanUp()127 int PCLmGenerator::errorOutAndCleanUp() {
128     Cleanup();
129     jobOpen = job_errored;
130     return genericFailure;
131 }
132 
133 static sint32 startXRef = 0;
134 static sint32 endXRef = 0;
135 
136 /*
137  * DO NOT EDIT UNTIL YOU READ THE HEADER FILE DESCRIPTION.
138  */
fixXRef()139 void PCLmGenerator::fixXRef() {
140     if (!startXRef || !mirrorBackside) {
141         return;
142     }
143 
144     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2) && mirrorBackside) {
145         assert(startXRef);
146         sint32 start = startXRef;
147         sint32 end = endXRef - 1;
148         sint32 aSize = endXRef - startXRef - 1;
149 
150         sint32 *tmpArray = (sint32 *) malloc(aSize * 20);
151 
152         sint32 xRefI = startXRef;
153         for (int i = 0; i < aSize + 1; i++, xRefI++) {
154             *(tmpArray + i) = xRefTable[xRefI + 1] - xRefTable[xRefI];
155         }
156 
157         // Reorder header and image sizes
158         for (int i = 0; i < aSize + 1; i += 2, xRefI++) {
159             sint32 t = *(tmpArray + i);
160             *(tmpArray + i) = *(tmpArray + i + 1);
161             *(tmpArray + i + 1) = t;
162         }
163 
164         xRefI = aSize;
165         for (int i = start + 1, j = aSize; i < end + 2; i++, start++, xRefI--, j--) {
166             xRefTable[i] = (xRefTable[i - 1] + *(tmpArray + j));
167         }
168 
169         for (int i = startXRef + 2; i < endXRef; i++) {
170             xRefTable[i] += 2;
171         }
172 
173         sint32 k = endXRef - 1;
174         int i;
175         sint32 lSize = (endXRef - startXRef) / 2;
176         for (i = startXRef; i < startXRef + lSize; i++, k--) {
177             sint32 t = xRefTable[i];
178             xRefTable[i] = xRefTable[k];
179             xRefTable[k] = t;
180         }
181         free(tmpArray);
182     }
183 
184     startXRef = 0;
185 }
186 
addXRef(sint32 xRefObj)187 bool PCLmGenerator::addXRef(sint32 xRefObj) {
188 #define XREF_ARRAY_SIZE 100
189     if (!xRefTable) {
190         xRefTable = (sint32 *) malloc(XREF_ARRAY_SIZE * sizeof(sint32));
191         assert(xRefTable);
192         xRefTable[0] = 0;
193         xRefIndex++;
194     }
195 
196     xRefTable[xRefIndex] = xRefObj;
197     xRefIndex++;
198 
199     if (!(xRefIndex % XREF_ARRAY_SIZE)) {
200         xRefTable = (sint32 *) realloc(xRefTable, (((xRefIndex + XREF_ARRAY_SIZE) *
201                 sizeof(sint32))));
202     }
203     return true;
204 }
205 
addKids(sint32 kidObj)206 bool PCLmGenerator::addKids(sint32 kidObj) {
207 #define KID_ARRAY_SIZE 20
208     if (!KidsArray) {
209         KidsArray = (sint32 *) malloc(KID_ARRAY_SIZE * sizeof(sint32));
210         assert(KidsArray);
211     }
212 
213     KidsArray[numKids] = kidObj;
214     numKids++;
215 
216     if (!(numKids % KID_ARRAY_SIZE)) {
217         KidsArray = (sint32 *) realloc(KidsArray, ((numKids + KID_ARRAY_SIZE) * sizeof(sint32)));
218     }
219     return true;
220 }
221 
initOutBuff(char * buff,sint32 size)222 void PCLmGenerator::initOutBuff(char *buff, sint32 size) {
223     currBuffPtr = outBuffPtr = buff;
224     outBuffSize = size;
225     totalBytesWrittenToCurrBuff = 0;
226     memset(buff, 0, size);
227 }
228 
writeStr2OutBuff(char * str)229 void PCLmGenerator::writeStr2OutBuff(char *str) {
230     sint32 strSize = strlen(str);
231     // Make sure we have enough room for the copy
232     char *maxSize = currBuffPtr + strSize;
233     assert(maxSize - outBuffPtr < outBuffSize);
234     memcpy(currBuffPtr, str, strSize);
235     currBuffPtr += strSize;
236     totalBytesWrittenToCurrBuff += strSize;
237     totalBytesWrittenToPCLmFile += strSize;
238 }
239 
write2Buff(ubyte * buff,int buffSize)240 void PCLmGenerator::write2Buff(ubyte *buff, int buffSize) {
241     char *maxSize = currBuffPtr + buffSize;
242     if (maxSize - outBuffPtr > outBuffSize) {
243         assert(0);
244     }
245     memcpy(currBuffPtr, buff, buffSize);
246     currBuffPtr += buffSize;
247     totalBytesWrittenToCurrBuff += buffSize;
248     totalBytesWrittenToPCLmFile += buffSize;
249 }
250 
statOutputFileSize()251 int PCLmGenerator::statOutputFileSize() {
252     addXRef(totalBytesWrittenToPCLmFile);
253     return (1);
254 }
255 
writePDFGrammarTrailer(int imageWidth,int imageHeight)256 void PCLmGenerator::writePDFGrammarTrailer(int imageWidth, int imageHeight) {
257     int i;
258     char KidsString[KID_STRING_SIZE];
259 
260     sprintf(pOutStr, "%%============= PCLm: FileBody: Object 1 - Catalog\n");
261     writeStr2OutBuff(pOutStr);
262     statOutputFileSize();
263     sprintf(pOutStr, "%d 0 obj\n", CATALOG_OBJ_NUMBER);
264     writeStr2OutBuff(pOutStr);
265     sprintf(pOutStr, "<<\n");
266     writeStr2OutBuff(pOutStr);
267     sprintf(pOutStr, "/Type /Catalog\n");
268     writeStr2OutBuff(pOutStr);
269     sprintf(pOutStr, "/Pages %d 0 R\n", PAGES_OBJ_NUMBER);
270     writeStr2OutBuff(pOutStr);
271     sprintf(pOutStr, ">>\n");
272     writeStr2OutBuff(pOutStr);
273     sprintf(pOutStr, "endobj\n");
274     writeStr2OutBuff(pOutStr);
275 
276     sprintf(pOutStr, "%%============= PCLm: FileBody: Object 2 - page tree \n");
277     writeStr2OutBuff(pOutStr);
278     statOutputFileSize();
279     sprintf(pOutStr, "%d 0 obj\n", PAGES_OBJ_NUMBER);
280     writeStr2OutBuff(pOutStr);
281     sprintf(pOutStr, "<<\n");
282     writeStr2OutBuff(pOutStr);
283     sprintf(pOutStr, "/Count %ld\n", numKids);
284     writeStr2OutBuff(pOutStr);
285 
286     // Define the Kids for this document as an indirect array
287     sprintf(KidsString, "/Kids [ ");
288     writeStr2OutBuff(KidsString);
289     for (i = 0; i < numKids; i++) {
290         sprintf(KidsString, "%ld 0 R ", KidsArray[i]);
291         writeStr2OutBuff(KidsString);
292     }
293 
294     sprintf(KidsString, "]\n");
295     writeStr2OutBuff(KidsString);
296 
297     sprintf(pOutStr, "/Type /Pages\n");
298     writeStr2OutBuff(pOutStr);
299     sprintf(pOutStr, ">>\n");
300     writeStr2OutBuff(pOutStr);
301     sprintf(pOutStr, "endobj\n");
302     writeStr2OutBuff(pOutStr);
303 
304     sprintf(pOutStr, "%%============= PCLm: cross-reference section: object 0, 6 entries\n");
305     writeStr2OutBuff(pOutStr);
306     statOutputFileSize();
307 
308     // Fix up the xref table for backside duplex
309     fixXRef();
310 
311     xRefStart = xRefIndex - 1;
312 
313     sprintf(pOutStr, "xref\n");
314     writeStr2OutBuff(pOutStr);
315     sprintf(pOutStr, "0 %d\n", 1);
316     writeStr2OutBuff(pOutStr);
317 
318     // Note the attempt to write exactly 20 bytes
319     sprintf(pOutStr, "0000000000 65535 f \n");
320     writeStr2OutBuff(pOutStr);
321     sprintf(pOutStr, "%d %ld\n", PAGES_OBJ_NUMBER + 1, xRefIndex - 4);
322     writeStr2OutBuff(pOutStr);
323     for (i = 1; i < xRefIndex - 3; i++) {
324         sprintf(pOutStr, "%010ld %05d n \n", xRefTable[i], 0);
325         writeStr2OutBuff(pOutStr);
326     }
327 
328     // sprintf(pOutStr,"<</AIMetaData 32 0 R/AIPDFPrivateData1 33 0 R/AIPDFPrivateData10 34 0\n");
329 
330     // Now add the catalog and page object
331     sprintf(pOutStr, "%d 2\n", CATALOG_OBJ_NUMBER);
332     writeStr2OutBuff(pOutStr);
333     sprintf(pOutStr, "%010ld %05d n \n", xRefTable[xRefIndex - 3], 0);
334     writeStr2OutBuff(pOutStr);
335     sprintf(pOutStr, "%010ld %05d n \n", xRefTable[xRefIndex - 2], 0);
336     writeStr2OutBuff(pOutStr);
337 
338     sprintf(pOutStr, "%%============= PCLm: File Trailer\n");
339     writeStr2OutBuff(pOutStr);
340     sprintf(pOutStr, "trailer\n");
341     writeStr2OutBuff(pOutStr);
342     sprintf(pOutStr, "<<\n");
343     writeStr2OutBuff(pOutStr);
344     // sprintf(pOutStr,"/Info %d 0\n", infoObj); writeStr2OutBuff(pOutStr);
345     sprintf(pOutStr, "/Size %ld\n", xRefIndex - 1);
346     writeStr2OutBuff(pOutStr);
347     sprintf(pOutStr, "/Root %d 0 R\n", CATALOG_OBJ_NUMBER);
348     writeStr2OutBuff(pOutStr);
349     sprintf(pOutStr, ">>\n");
350     writeStr2OutBuff(pOutStr);
351     sprintf(pOutStr, "startxref\n");
352     writeStr2OutBuff(pOutStr);
353     sprintf(pOutStr, "%ld\n", xRefTable[xRefStart]);
354     writeStr2OutBuff(pOutStr);
355     sprintf(pOutStr, "%%%%EOF\n");
356     writeStr2OutBuff(pOutStr);
357 }
358 
injectAdobeRGBCS()359 bool PCLmGenerator::injectAdobeRGBCS() {
360     if (adobeRGBCS_firstTime) {
361         // We need to inject the ICC object for AdobeRGB
362         sprintf(pOutStr, "%%============= PCLm: ICC Profile\n");
363         writeStr2OutBuff(pOutStr);
364         statOutputFileSize();
365         sprintf(pOutStr, "%ld 0 obj\n", objCounter);
366         objCounter++;
367         writeStr2OutBuff(pOutStr);
368         sprintf(pOutStr, "[/ICCBased %ld 0 R]\n", objCounter);
369         writeStr2OutBuff(pOutStr);
370 
371         sprintf(pOutStr, "endobj\n");
372         writeStr2OutBuff(pOutStr);
373         statOutputFileSize();
374         sprintf(pOutStr, "%ld 0 obj\n", objCounter);
375         objCounter++;
376         writeStr2OutBuff(pOutStr);
377         sprintf(pOutStr, "<<\n");
378         writeStr2OutBuff(pOutStr);
379         sprintf(pOutStr, "/N 3\n");
380         writeStr2OutBuff(pOutStr);
381         sprintf(pOutStr, "/Alternate /DeviceRGB\n");
382         writeStr2OutBuff(pOutStr);
383         sprintf(pOutStr, "/Length %u\n", ADOBE_RGB_SIZE + 1);
384         writeStr2OutBuff(pOutStr);
385         sprintf(pOutStr, "/Filter /FlateDecode\n");
386         writeStr2OutBuff(pOutStr);
387         sprintf(pOutStr, ">>\n");
388         writeStr2OutBuff(pOutStr);
389         sprintf(pOutStr, "stream\n");
390         writeStr2OutBuff(pOutStr);
391 
392         FILE *inFile;
393         if (!(inFile = fopen("flate_colorspace.bin", "rb"))) {
394             fprintf(stderr, "can't open %s\n", "flate_colorspace.bin");
395             return 0;
396         }
397 
398         ubyte *buffIn = (unsigned char *) malloc(ADOBE_RGB_SIZE);
399         assert(buffIn);
400 
401         sint32 bytesRead = fread(buffIn, 1, ADOBE_RGB_SIZE, inFile);
402         assert(bytesRead == ADOBE_RGB_SIZE);
403         fclose(inFile);
404         write2Buff(buffIn, bytesRead);
405         if (buffIn) {
406             free(buffIn);
407         }
408 
409         sprintf(pOutStr, "\nendstream\n");
410         writeStr2OutBuff(pOutStr);
411         sprintf(pOutStr, "endobj\n");
412         writeStr2OutBuff(pOutStr);
413     }
414 
415     adobeRGBCS_firstTime = false;
416     return true;
417 }
418 
colorConvertSource(colorSpaceDisposition srcCS,colorSpaceDisposition dstCS,ubyte * strip,sint32 stripWidth,sint32 stripHeight)419 bool PCLmGenerator::colorConvertSource(colorSpaceDisposition srcCS, colorSpaceDisposition dstCS,
420         ubyte *strip, sint32 stripWidth, sint32 stripHeight) {
421     if (srcCS == deviceRGB && dstCS == grayScale) {
422         // Do an inplace conversion from RGB -> 8 bpp gray
423         ubyte *srcPtr = strip;
424         ubyte *dstPtr = strip;
425         for (int h = 0; h < stripHeight; h++) {
426             for (int w = 0; w < stripWidth; w++, dstPtr++, srcPtr += 3) {
427                 *dstPtr = (ubyte) rgb_2_gray(*srcPtr, *(srcPtr + 1), *(srcPtr + 2));
428             }
429         }
430         dstNumComponents = 1;
431     } else {
432         assert(0);
433     }
434 
435     return true;
436 }
437 
injectRLEStrip(ubyte * RLEBuffer,int numBytes,int imageWidth,int imageHeight,colorSpaceDisposition destColorSpace,bool whiteStrip)438 int PCLmGenerator::injectRLEStrip(ubyte *RLEBuffer, int numBytes, int imageWidth, int imageHeight,
439         colorSpaceDisposition destColorSpace, bool whiteStrip) {
440     bool printedImageTransform = false;
441 
442     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2) && mirrorBackside) {
443         if (!startXRef) {
444             startXRef = xRefIndex;
445         }
446 
447         injectImageTransform();
448         printedImageTransform = true;
449     }
450 
451     if (destColorSpace == adobeRGB) {
452         injectAdobeRGBCS();
453     }
454 
455     // Inject LZ compressed image into PDF file
456     sprintf(pOutStr, "%%============= PCLm: FileBody: Strip Stream: RLE Image \n");
457     writeStr2OutBuff(pOutStr);
458     statOutputFileSize();
459 
460     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2) && mirrorBackside) {
461         sprintf(pOutStr, "%ld 0 obj\n", objCounter - 1);
462         objCounter++;
463         writeStr2OutBuff(pOutStr);
464     } else {
465         sprintf(pOutStr, "%ld 0 obj\n", objCounter);
466         objCounter++;
467         writeStr2OutBuff(pOutStr);
468     }
469 
470     sprintf(pOutStr, "<<\n");
471     writeStr2OutBuff(pOutStr);
472     sprintf(pOutStr, "/Width %d\n", imageWidth);
473     writeStr2OutBuff(pOutStr);
474     if (destColorSpace == deviceRGB) {
475         sprintf(pOutStr, "/ColorSpace /DeviceRGB\n");
476         writeStr2OutBuff(pOutStr);
477     } else if (destColorSpace == adobeRGB) {
478         sprintf(pOutStr, "/ColorSpace 5 0 R\n");
479         writeStr2OutBuff(pOutStr);
480     } else {
481         sprintf(pOutStr, "/ColorSpace /DeviceGray\n");
482         writeStr2OutBuff(pOutStr);
483     }
484     sprintf(pOutStr, "/Height %d\n", imageHeight);
485     writeStr2OutBuff(pOutStr);
486     sprintf(pOutStr, "/Filter /RunLengthDecode\n");
487     writeStr2OutBuff(pOutStr);
488     sprintf(pOutStr, "/Subtype /Image\n");
489     writeStr2OutBuff(pOutStr);
490     sprintf(pOutStr, "/Length %d\n", numBytes);
491     writeStr2OutBuff(pOutStr);
492     sprintf(pOutStr, "/Type /XObject\n");
493     writeStr2OutBuff(pOutStr);
494     sprintf(pOutStr, "/BitsPerComponent 8\n");
495     writeStr2OutBuff(pOutStr);
496 #ifdef SUPPORT_WHITE_STRIPS
497     if (whiteStrip) {
498         sprintf(pOutStr, "/Name /WhiteStrip\n");
499         writeStr2OutBuff(pOutStr);
500     } else {
501         sprintf(pOutStr, "/Name /ColorStrip\n");
502         writeStr2OutBuff(pOutStr);
503     }
504 #endif
505 
506     sprintf(pOutStr, ">>\n");
507     writeStr2OutBuff(pOutStr);
508     sprintf(pOutStr, "stream\n");
509     writeStr2OutBuff(pOutStr);
510 
511     // Write the zlib compressed strip to the PDF output file
512     write2Buff(RLEBuffer, numBytes);
513     sprintf(pOutStr, "\nendstream\n");
514     writeStr2OutBuff(pOutStr);
515     sprintf(pOutStr, "endobj\n");
516     writeStr2OutBuff(pOutStr);
517 
518     if (!printedImageTransform) {
519         injectImageTransform();
520     }
521 
522     endXRef = xRefIndex;
523 
524     return (1);
525 }
526 
injectLZStrip(ubyte * LZBuffer,int numBytes,int imageWidth,int imageHeight,colorSpaceDisposition destColorSpace,bool whiteStrip)527 int PCLmGenerator::injectLZStrip(ubyte *LZBuffer, int numBytes, int imageWidth, int imageHeight,
528         colorSpaceDisposition destColorSpace, bool whiteStrip) {
529     bool printedImageTransform = false;
530 
531     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2) && mirrorBackside) {
532         if (!startXRef) {
533             startXRef = xRefIndex;
534         }
535 
536         injectImageTransform();
537         printedImageTransform = true;
538     }
539 
540     if (destColorSpace == adobeRGB) {
541         injectAdobeRGBCS();
542     }
543 
544     // Inject LZ compressed image into PDF file
545     sprintf(pOutStr, "%%============= PCLm: FileBody: Strip Stream: zlib Image \n");
546     writeStr2OutBuff(pOutStr);
547     statOutputFileSize();
548 
549     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2) && mirrorBackside) {
550         sprintf(pOutStr, "%ld 0 obj\n", objCounter - 1);
551         objCounter++;
552         writeStr2OutBuff(pOutStr);
553     } else {
554         sprintf(pOutStr, "%ld 0 obj\n", objCounter);
555         objCounter++;
556         writeStr2OutBuff(pOutStr);
557     }
558 
559     sprintf(pOutStr, "<<\n");
560     writeStr2OutBuff(pOutStr);
561     sprintf(pOutStr, "/Width %d\n", imageWidth);
562     writeStr2OutBuff(pOutStr);
563     if (destColorSpace == deviceRGB) {
564         sprintf(pOutStr, "/ColorSpace /DeviceRGB\n");
565         writeStr2OutBuff(pOutStr);
566     } else if (destColorSpace == adobeRGB) {
567         sprintf(pOutStr, "/ColorSpace 5 0 R\n");
568         writeStr2OutBuff(pOutStr);
569     } else {
570         sprintf(pOutStr, "/ColorSpace /DeviceGray\n");
571         writeStr2OutBuff(pOutStr);
572     }
573     sprintf(pOutStr, "/Height %d\n", imageHeight);
574     writeStr2OutBuff(pOutStr);
575     sprintf(pOutStr, "/Filter /FlateDecode\n");
576     writeStr2OutBuff(pOutStr);
577     sprintf(pOutStr, "/Subtype /Image\n");
578     writeStr2OutBuff(pOutStr);
579     sprintf(pOutStr, "/Length %d\n", numBytes);
580     writeStr2OutBuff(pOutStr);
581     sprintf(pOutStr, "/Type /XObject\n");
582     writeStr2OutBuff(pOutStr);
583     sprintf(pOutStr, "/BitsPerComponent 8\n");
584     writeStr2OutBuff(pOutStr);
585 #ifdef SUPPORT_WHITE_STRIPS
586     if (whiteStrip) {
587         sprintf(pOutStr, "/Name /WhiteStrip\n");
588         writeStr2OutBuff(pOutStr);
589     } else {
590         sprintf(pOutStr, "/Name /ColorStrip\n");
591         writeStr2OutBuff(pOutStr);
592     }
593 #endif
594 
595     sprintf(pOutStr, ">>\n");
596     writeStr2OutBuff(pOutStr);
597     sprintf(pOutStr, "stream\n");
598     writeStr2OutBuff(pOutStr);
599 
600     // Write the zlib compressed strip to the PDF output file
601     write2Buff(LZBuffer, numBytes);
602     sprintf(pOutStr, "\nendstream\n");
603     writeStr2OutBuff(pOutStr);
604     sprintf(pOutStr, "endobj\n");
605     writeStr2OutBuff(pOutStr);
606 
607     if (!printedImageTransform) {
608         injectImageTransform();
609     }
610 
611     endXRef = xRefIndex;
612 
613     return (1);
614 }
615 
injectImageTransform()616 void PCLmGenerator::injectImageTransform() {
617     char str[512];
618     int strLength;
619     sprintf(str, "q /image Do Q\n");
620     strLength = strlen(str);
621 
622     // Output image transformation information
623     sprintf(pOutStr, "%%============= PCLm: Object - Image Transformation \n");
624     writeStr2OutBuff(pOutStr);
625     statOutputFileSize();
626     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2) && mirrorBackside) {
627         sprintf(pOutStr, "%ld 0 obj\n", objCounter + 1);
628         objCounter++;
629         writeStr2OutBuff(pOutStr);
630     } else {
631         sprintf(pOutStr, "%ld 0 obj\n", objCounter);
632         objCounter++;
633         writeStr2OutBuff(pOutStr);
634     }
635     sprintf(pOutStr, "<<\n");
636     writeStr2OutBuff(pOutStr);
637     sprintf(pOutStr, "/Length %d\n", strLength);
638     writeStr2OutBuff(pOutStr);
639     sprintf(pOutStr, ">>\n");
640     writeStr2OutBuff(pOutStr);
641     sprintf(pOutStr, "stream\n");
642     writeStr2OutBuff(pOutStr);
643     sprintf(pOutStr, "%s", str);
644     writeStr2OutBuff(pOutStr);
645     sprintf(pOutStr, "endstream\n");
646     writeStr2OutBuff(pOutStr);
647     sprintf(pOutStr, "endobj\n");
648     writeStr2OutBuff(pOutStr);
649 }
650 
injectJPEG(char * jpeg_Buff,int imageWidth,int imageHeight,int numCompBytes,colorSpaceDisposition destColorSpace,bool whiteStrip)651 int PCLmGenerator::injectJPEG(char *jpeg_Buff, int imageWidth, int imageHeight, int numCompBytes,
652         colorSpaceDisposition destColorSpace, bool whiteStrip) {
653     char str[512];
654 
655     bool printedImageTransform = false;
656 
657     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2) && mirrorBackside) {
658         if (!startXRef) {
659             startXRef = xRefIndex;
660         }
661 
662         injectImageTransform();
663         printedImageTransform = true;
664     }
665 
666     yPosition += imageHeight;
667 
668     if (destColorSpace == adobeRGB) {
669         injectAdobeRGBCS();
670     }
671 
672     // Inject PDF JPEG into output file
673     sprintf(pOutStr, "%%============= PCLm: FileBody: Strip Stream: jpeg Image \n");
674     writeStr2OutBuff(pOutStr);
675     statOutputFileSize();
676     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2) && mirrorBackside) {
677         sprintf(pOutStr, "%ld 0 obj\n", objCounter - 1);
678         objCounter++;
679         writeStr2OutBuff(pOutStr);
680     } else {
681         sprintf(pOutStr, "%ld 0 obj\n", objCounter);
682         objCounter++;
683         writeStr2OutBuff(pOutStr);
684     }
685     sprintf(pOutStr, "<<\n");
686     writeStr2OutBuff(pOutStr);
687     sprintf(pOutStr, "/Width %d\n", imageWidth);
688     writeStr2OutBuff(pOutStr);
689     if (destColorSpace == deviceRGB) {
690         sprintf(pOutStr, "/ColorSpace /DeviceRGB\n");
691         writeStr2OutBuff(pOutStr);
692     } else if (destColorSpace == adobeRGB) {
693         sprintf(pOutStr, "/ColorSpace 5 0 R\n");
694         writeStr2OutBuff(pOutStr);
695     } else {
696         sprintf(pOutStr, "/ColorSpace /DeviceGray\n");
697         writeStr2OutBuff(pOutStr);
698     }
699     sprintf(pOutStr, "/Height %d\n", imageHeight);
700     writeStr2OutBuff(pOutStr);
701     sprintf(pOutStr, "/Filter /DCTDecode\n");
702     writeStr2OutBuff(pOutStr);
703     sprintf(pOutStr, "/Subtype /Image\n");
704     writeStr2OutBuff(pOutStr);
705     sprintf(pOutStr, "/Length %d\n", numCompBytes);
706     writeStr2OutBuff(pOutStr);
707     sprintf(pOutStr, "/Type /XObject\n");
708     writeStr2OutBuff(pOutStr);
709     sprintf(pOutStr, "/BitsPerComponent 8\n");
710     writeStr2OutBuff(pOutStr);
711 #ifdef SUPPORT_WHITE_STRIPS
712     if (whiteStrip) {
713         sprintf(pOutStr, "/Name /WhiteStrip\n");
714         writeStr2OutBuff(pOutStr);
715     } else {
716         sprintf(pOutStr, "/Name /ColorStrip\n");
717         writeStr2OutBuff(pOutStr);
718     }
719 #endif
720     sprintf(pOutStr, ">>\n");
721     writeStr2OutBuff(pOutStr);
722     sprintf(pOutStr, "stream\n");
723     writeStr2OutBuff(pOutStr);
724 
725     write2Buff((ubyte *) jpeg_Buff, numCompBytes);
726     sprintf(pOutStr, "\nendstream\n");
727     writeStr2OutBuff(pOutStr);
728     sprintf(pOutStr, "endobj\n");
729     writeStr2OutBuff(pOutStr);
730 
731     sprintf(str, "q /image Do Q\n");
732 
733     if (!printedImageTransform) {
734         injectImageTransform();
735     }
736 
737     endXRef = xRefIndex;
738 
739     return (1);
740 }
741 
742 /*
743  * Writes str to buffer if the size of buffer is less than TEMP_BUFF_SIZE
744  */
writeStr2Buff(char * buffer,char * str)745 void writeStr2Buff(char *buffer, char *str) {
746     int buffSize;
747     char *buffPos;
748 
749     buffSize = strlen(buffer) + strlen(str);
750     if (buffSize > TEMP_BUFF_SIZE) {
751         assert(0);
752     }
753 
754     buffSize = strlen(buffer);
755     buffPos = buffer + buffSize;
756     sprintf(buffPos, "%s", str);
757 
758     buffSize = strlen(buffer);
759     if (buffSize > TEMP_BUFF_SIZE) {
760         printf("tempBuff size exceeded: buffSize=%d\n", buffSize);
761         assert(0);
762     }
763 }
764 
writePDFGrammarPage(int imageWidth,int imageHeight,int numStrips,colorSpaceDisposition destColorSpace)765 void PCLmGenerator::writePDFGrammarPage(int imageWidth, int imageHeight, int numStrips,
766         colorSpaceDisposition destColorSpace) {
767     int i, imageRef = objCounter + 2, buffSize;
768     int yAnchor;
769     char str[512];
770     char *tempBuffer;
771     int startImageIndex = 0;
772     int numLinesLeft = 0;
773 
774     if (destColorSpace == adobeRGB && 1 == pageCount) {
775         imageRef += 2; // Add 2 for AdobeRGB
776     }
777 
778     tempBuffer = (char *) malloc(TEMP_BUFF_SIZE);
779     assert(tempBuffer);
780     memset(tempBuffer, 0x0, TEMP_BUFF_SIZE);
781 
782     sprintf(pOutStr, "%%============= PCLm: FileBody: Object 3 - page object\n");
783     writeStr2OutBuff(pOutStr);
784     statOutputFileSize();
785     sprintf(pOutStr, "%ld 0 obj\n", objCounter);
786     writeStr2OutBuff(pOutStr);
787     addKids(objCounter);
788     objCounter++;
789     sprintf(pOutStr, "<<\n");
790     writeStr2OutBuff(pOutStr);
791     sprintf(pOutStr, "/Type /Page\n");
792     writeStr2OutBuff(pOutStr);
793     sprintf(pOutStr, "/Parent %d 0 R\n", PAGES_OBJ_NUMBER);
794     writeStr2OutBuff(pOutStr);
795     sprintf(pOutStr, "/Resources <<\n");
796     writeStr2OutBuff(pOutStr);
797     // sprintf(pOutStr,"/ProcSet [ /PDF /ImageC ]\n"); writeStr2OutBuff(pOutStr);
798     sprintf(pOutStr, "/XObject <<\n");
799     writeStr2OutBuff(pOutStr);
800 
801     if (topMarginInPix) {
802         for (i = 0; i < numFullInjectedStrips; i++, startImageIndex++) {
803             sprintf(str, "/Image%d %d 0 R\n", startImageIndex, imageRef);
804             sprintf(pOutStr, "%s", str);
805             writeStr2OutBuff(pOutStr);
806             imageRef += 2;
807         }
808         if (numPartialScanlinesToInject) {
809             sprintf(str, "/Image%d %d 0 R\n", startImageIndex, imageRef);
810             sprintf(pOutStr, "%s", str);
811             writeStr2OutBuff(pOutStr);
812             imageRef += 2;
813             startImageIndex++;
814         }
815     }
816 
817     for (i = startImageIndex; i < numStrips + startImageIndex; i++) {
818         sprintf(str, "/Image%d %d 0 R\n", i, imageRef);
819         // sprintf(pOutStr,"/ImageA 4 0 R /ImageB 6 0 R >>\n"); writeStr2OutBuff(pOutStr);
820         sprintf(pOutStr, "%s", str);
821         writeStr2OutBuff(pOutStr);
822         imageRef += 2;
823     }
824     sprintf(pOutStr, ">>\n");
825     writeStr2OutBuff(pOutStr);
826     sprintf(pOutStr, ">>\n");
827     writeStr2OutBuff(pOutStr);
828     if (currMediaOrientationDisposition == landscapeOrientation) {
829         pageOrigin = mediaWidth;
830         sprintf(pOutStr, "/MediaBox [ 0 0 %d %d ]\n", mediaHeight, mediaWidth);
831         writeStr2OutBuff(pOutStr);
832     } else {
833         pageOrigin = mediaHeight;
834         sprintf(pOutStr, "/MediaBox [ 0 0 %d %d ]\n", mediaWidth, mediaHeight);
835         writeStr2OutBuff(pOutStr);
836     }
837     sprintf(pOutStr, "/Contents [ %ld 0 R ]\n", objCounter);
838     writeStr2OutBuff(pOutStr);
839 #ifdef PIECEINFO_SUPPORTED
840     sprintf(pOutStr,"/PieceInfo <</HPAddition %d 0 R >> \n",9997); writeStr2OutBuff(pOutStr);
841 #endif
842     sprintf(pOutStr, ">>\n");
843     writeStr2OutBuff(pOutStr);
844     sprintf(pOutStr, "endobj\n");
845     writeStr2OutBuff(pOutStr);
846 
847     // Create the FileBody stream first, so we know the Length of the stream
848     if (reverseOrder) {
849         yAnchor = 0;
850     } else {
851         yAnchor = (int) ((pageOrigin * STANDARD_SCALE) + 0.99); // Round up
852     }
853 
854     // Setup the CTM so that we can send device-resolution coordinates
855     sprintf(pOutStr,
856             "%%Image Transformation Matrix: width, skewX, skewY, height, xAnchor, yAnchor\n");
857     writeStr2OutBuff(pOutStr);
858     sprintf(str, "%f 0 0 %f 0 0 cm\n", STANDARD_SCALE_FOR_PDF / currRenderResolutionInteger,
859             STANDARD_SCALE_FOR_PDF / currRenderResolutionInteger);
860     writeStr2Buff(tempBuffer, str);
861 
862     startImageIndex = 0;
863     if (topMarginInPix) {
864         for (i = 0; i < numFullInjectedStrips; i++) {
865             if (reverseOrder) {
866                 yAnchor += numFullScanlinesToInject;
867             } else {
868                 yAnchor -= numFullScanlinesToInject;
869             }
870 
871             sprintf(str, "/P <</MCID 0>> BDC q\n");
872             writeStr2Buff(tempBuffer, str);
873 
874             sprintf(str, "%%Image Transformation Matrix: width, skewX, skewY, height, "
875                     "xAnchor, yAnchor\n");
876             writeStr2Buff(tempBuffer, str);
877 
878             sprintf(str, "%d 0 0 %ld 0 %d cm\n", imageWidth * scaleFactor,
879                     numFullScanlinesToInject * scaleFactor, yAnchor * scaleFactor);
880             writeStr2Buff(tempBuffer, str);
881 
882             sprintf(str, "/Image%d Do Q\n", startImageIndex);
883             writeStr2Buff(tempBuffer, str);
884 
885             startImageIndex++;
886         }
887         if (numPartialScanlinesToInject) {
888             if (reverseOrder) {
889                 yAnchor += numPartialScanlinesToInject;
890             } else {
891                 yAnchor -= numPartialScanlinesToInject;
892             }
893 
894             sprintf(str, "/P <</MCID 0>> BDC q\n");
895             writeStr2Buff(tempBuffer, str);
896 
897             sprintf(str, "%%Image Transformation Matrix: width, skewX, skewY, height, xAnchor, "
898                     "yAnchor\n");
899 
900             writeStr2Buff(tempBuffer, str);
901 
902             sprintf(str, "%d 0 0 %ld 0 %d cm\n", imageWidth * scaleFactor,
903                     numPartialScanlinesToInject * scaleFactor, yAnchor * scaleFactor);
904             writeStr2Buff(tempBuffer, str);
905 
906             sprintf(str, "/Image%d Do Q\n", startImageIndex);
907             writeStr2Buff(tempBuffer, str);
908 
909             startImageIndex++;
910         }
911     }
912 
913     for (i = startImageIndex; i < numStrips + startImageIndex; i++) {
914         // last strip may have less lines than currStripHeight. Update yAnchor using left over lines
915         if (i == (numStrips + startImageIndex - 1)) {
916             numLinesLeft = currSourceHeight - ((numStrips - 1) * currStripHeight);
917 
918             if (reverseOrder) {
919                 yAnchor += numLinesLeft;
920             } else {
921                 yAnchor -= numLinesLeft;
922             }
923         } else {
924             if (reverseOrder) {
925                 yAnchor += currStripHeight;
926             } else {
927                 yAnchor -= currStripHeight;
928             }
929         }
930 
931         sprintf(str, "/P <</MCID 0>> BDC q\n");
932         writeStr2Buff(tempBuffer, str);
933 
934         sprintf(str,
935                 "%%Image Transformation Matrix: width, skewX, skewY, height, xAnchor, yAnchor\n");
936         writeStr2Buff(tempBuffer, str);
937 
938         // last strip may have less lines than currStripHeight
939         if (i == (numStrips + startImageIndex - 1)) {
940             sprintf(str, "%d 0 0 %d 0 %d cm\n", imageWidth * scaleFactor,
941                     numLinesLeft * scaleFactor, yAnchor * scaleFactor);
942             writeStr2Buff(tempBuffer, str);
943         } else if (yAnchor < 0) {
944             sint32 newH = currStripHeight + yAnchor;
945             sprintf(str, "%d 0 0 %ld 0 %d cm\n", imageWidth * scaleFactor, newH * scaleFactor,
946                     0 * scaleFactor);
947             writeStr2Buff(tempBuffer, str);
948         } else {
949             sprintf(str, "%d 0 0 %ld 0 %d cm\n", imageWidth * scaleFactor,
950                     currStripHeight * scaleFactor, yAnchor * scaleFactor);
951             writeStr2Buff(tempBuffer, str);
952         }
953 
954         sprintf(str, "/Image%d Do Q\n", i);
955         writeStr2Buff(tempBuffer, str);
956     }
957 
958     // Resulting buffer size
959     buffSize = strlen(tempBuffer);
960 
961     sprintf(pOutStr, "%%============= PCLm: FileBody: Page Content Stream object\n");
962     writeStr2OutBuff(pOutStr);
963     statOutputFileSize();
964     sprintf(pOutStr, "%ld 0 obj\n", objCounter);
965     writeStr2OutBuff(pOutStr);
966     sprintf(pOutStr, "<<\n");
967     writeStr2OutBuff(pOutStr);
968 
969     sprintf(pOutStr, "/Length %d\n", buffSize);
970     writeStr2OutBuff(pOutStr);
971     sprintf(pOutStr, ">>\n");
972     writeStr2OutBuff(pOutStr);
973     sprintf(pOutStr, "stream\n");
974     writeStr2OutBuff(pOutStr);
975 
976     // Now write the FileBody stream
977     write2Buff((ubyte *) tempBuffer, buffSize);
978 
979     sprintf(pOutStr, "endstream\n");
980     writeStr2OutBuff(pOutStr);
981     sprintf(pOutStr, "endobj\n");
982     writeStr2OutBuff(pOutStr);
983     objCounter++;
984     if (tempBuffer) {
985         free(tempBuffer);
986     }
987 }
988 
989 /*
990  * Mirrors the source image in preparation for backside duplex support
991  */
prepImageForBacksideDuplex(ubyte * imagePtr,sint32 imageHeight,sint32 imageWidth,sint32 numComponents)992 static bool prepImageForBacksideDuplex(ubyte *imagePtr, sint32 imageHeight, sint32 imageWidth,
993         sint32 numComponents) {
994     sint32 numBytes = imageHeight * imageWidth * numComponents;
995     ubyte *head, *tail, t0, t1, t2;
996 
997     if (numComponents == 3) {
998         for (head = imagePtr, tail = imagePtr + numBytes - 1; tail > head;) {
999             t0 = *head;
1000             t1 = *(head + 1);
1001             t2 = *(head + 2);
1002 
1003             *head = *(tail - 2);
1004             *(head + 1) = *(tail - 1);
1005             *(head + 2) = *(tail - 0);
1006             *tail = t2;
1007             *(tail - 1) = t1;
1008             *(tail - 2) = t0;
1009 
1010             head += 3;
1011             tail -= 3;
1012         }
1013     } else {
1014         for (head = imagePtr, tail = imagePtr + numBytes; tail > head;) {
1015             t0 = *head;
1016             *head = *tail;
1017             *tail = t0;
1018             head++;
1019             tail--;
1020         }
1021     }
1022 //origTail++;
1023     return true;
1024 }
1025 
getInputBinString(jobInputBin bin,char * returnStr)1026 bool PCLmGenerator::getInputBinString(jobInputBin bin, char *returnStr) {
1027     returnStr[0] = '\0';
1028 
1029     switch (bin) {
1030         case alternate:
1031             strcpy(returnStr, "alternate");
1032             break;
1033         case alternate_roll:
1034             strcpy(returnStr, "alternate_roll");
1035             break;
1036         case auto_select:
1037             strcpy(returnStr, "auto_select");
1038             break;
1039         case bottom:
1040             strcpy(returnStr, "bottom");
1041             break;
1042         case center:
1043             strcpy(returnStr, "center");
1044             break;
1045         case disc:
1046             strcpy(returnStr, "disc");
1047             break;
1048         case envelope:
1049             strcpy(returnStr, "envelope");
1050             break;
1051         case hagaki:
1052             strcpy(returnStr, "hagaki");
1053             break;
1054         case large_capacity:
1055             strcpy(returnStr, "large_capacity");
1056             break;
1057         case left:
1058             strcpy(returnStr, "left");
1059             break;
1060         case main_tray:
1061             strcpy(returnStr, "main_tray");
1062             break;
1063         case main_roll:
1064             strcpy(returnStr, "main_roll");
1065             break;
1066         case manual:
1067             strcpy(returnStr, "manual");
1068             break;
1069         case middle:
1070             strcpy(returnStr, "middle");
1071             break;
1072         case photo:
1073             strcpy(returnStr, "photo");
1074             break;
1075         case rear:
1076             strcpy(returnStr, "rear");
1077             break;
1078         case right:
1079             strcpy(returnStr, "right");
1080             break;
1081         case side:
1082             strcpy(returnStr, "side");
1083             break;
1084         case top:
1085             strcpy(returnStr, "top");
1086             break;
1087         case tray_1:
1088             strcpy(returnStr, "tray_1");
1089             break;
1090         case tray_2:
1091             strcpy(returnStr, "tray_2");
1092             break;
1093         case tray_3:
1094             strcpy(returnStr, "tray_3");
1095             break;
1096         case tray_4:
1097             strcpy(returnStr, "tray_4");
1098             break;
1099         case tray_5:
1100             strcpy(returnStr, "tray_5");
1101             break;
1102         case tray_N:
1103             strcpy(returnStr, "tray_N");
1104             break;
1105         default:
1106             assert(0);
1107             break;
1108     }
1109     return true;
1110 }
1111 
getOutputBin(jobOutputBin bin,char * returnStr)1112 bool PCLmGenerator::getOutputBin(jobOutputBin bin, char *returnStr) {
1113     if (returnStr) {
1114         returnStr[0] = '\0';
1115     }
1116 
1117     switch (bin) {
1118         case top_output:
1119             strcpy(returnStr, "top_output");
1120             break;
1121         case middle_output:
1122             strcpy(returnStr, "middle_output");
1123             break;
1124         case bottom_output:
1125             strcpy(returnStr, "bottom_output");
1126             break;
1127         case side_output:
1128             strcpy(returnStr, "side_output");
1129             break;
1130         case center_output:
1131             strcpy(returnStr, "center_output");
1132             break;
1133         case rear_output:
1134             strcpy(returnStr, "rear_output");
1135             break;
1136         case face_up:
1137             strcpy(returnStr, "face_up");
1138             break;
1139         case face_down:
1140             strcpy(returnStr, "face_down");
1141             break;
1142         case large_capacity_output:
1143             strcpy(returnStr, "large_capacity_output");
1144             break;
1145         case stacker_N:
1146             strcpy(returnStr, "stacker_N");
1147             break;
1148         case mailbox_N:
1149             strcpy(returnStr, "mailbox_N");
1150             break;
1151         case tray_1_output:
1152             strcpy(returnStr, "tray_1_output");
1153             break;
1154         case tray_2_output:
1155             strcpy(returnStr, "tray_2_output");
1156             break;
1157         case tray_3_output:
1158             strcpy(returnStr, "tray_3_output");
1159             break;
1160         case tray_4_output:
1161             strcpy(returnStr, "tray_4_output");
1162             break;
1163         default:
1164             assert(0);
1165             break;
1166     }
1167     return true;
1168 }
1169 
writeJobTicket()1170 void PCLmGenerator::writeJobTicket() {
1171     // Write JobTicket
1172     char inputBin[256];
1173     char outputBin[256];
1174 
1175     if (!m_pPCLmSSettings) {
1176         return;
1177     }
1178 
1179     getInputBinString(m_pPCLmSSettings->userInputBin, &inputBin[0]);
1180     getOutputBin(m_pPCLmSSettings->userOutputBin, &outputBin[0]);
1181     strcpy(inputBin, inputBin);
1182     strcpy(outputBin, outputBin);
1183 
1184     sprintf(pOutStr, "%%  genPCLm (Ver: %f)\n", PCLM_Ver);
1185     writeStr2OutBuff(pOutStr);
1186     sprintf(pOutStr, "%%============= Job Ticket =============\n");
1187     writeStr2OutBuff(pOutStr);
1188     sprintf(pOutStr, "%%  PCLmS-Job-Ticket\n");
1189     writeStr2OutBuff(pOutStr);
1190     sprintf(pOutStr, "%%      job-ticket-version: 0.1\n");
1191     writeStr2OutBuff(pOutStr);
1192     sprintf(pOutStr, "%%      epcl-version: 1.01\n");
1193     writeStr2OutBuff(pOutStr);
1194     sprintf(pOutStr, "%%    JobSection\n");
1195     writeStr2OutBuff(pOutStr);
1196     sprintf(pOutStr, "%%      job-id: xxx\n");
1197     writeStr2OutBuff(pOutStr);
1198     sprintf(pOutStr, "%%    MediaHandlingSection\n");
1199     writeStr2OutBuff(pOutStr);
1200     sprintf(pOutStr, "%%      media-size-name: %s\n", currMediaName);
1201     writeStr2OutBuff(pOutStr);
1202     sprintf(pOutStr, "%%      media-type: %s\n", m_pPCLmSSettings->userMediaType);
1203     writeStr2OutBuff(pOutStr);
1204     sprintf(pOutStr, "%%      media-source: %s\n", inputBin);
1205     writeStr2OutBuff(pOutStr);
1206     sprintf(pOutStr, "%%      sides: xxx\n");
1207     writeStr2OutBuff(pOutStr);
1208     sprintf(pOutStr, "%%      output-bin: %s\n", outputBin);
1209     writeStr2OutBuff(pOutStr);
1210     sprintf(pOutStr, "%%    RenderingSection\n");
1211     writeStr2OutBuff(pOutStr);
1212     if (currCompressionDisposition == compressDCT) {
1213         sprintf(pOutStr, "%%      pclm-compression-method: JPEG\n");
1214         writeStr2OutBuff(pOutStr);
1215     } else if (currCompressionDisposition == compressFlate) {
1216         sprintf(pOutStr, "%%      pclm-compression-method: FLATE\n");
1217         writeStr2OutBuff(pOutStr);
1218     } else {
1219         sprintf(pOutStr, "%%      pclm-compression-method: RLE\n");
1220         writeStr2OutBuff(pOutStr);
1221     }
1222     sprintf(pOutStr, "%%      strip-height: %ld\n", currStripHeight);
1223     writeStr2OutBuff(pOutStr);
1224 
1225     if (destColorSpace == deviceRGB) {
1226         sprintf(pOutStr, "%%      print-color-mode: deviceRGB\n");
1227         writeStr2OutBuff(pOutStr);
1228     } else if (destColorSpace == adobeRGB) {
1229         sprintf(pOutStr, "%%      print-color-mode: adobeRGB\n");
1230         writeStr2OutBuff(pOutStr);
1231     } else if (destColorSpace == grayScale) {
1232         sprintf(pOutStr, "%%      print-color-mode: gray\n");
1233         writeStr2OutBuff(pOutStr);
1234     }
1235 
1236     sprintf(pOutStr, "%%      print-quality: %d\n", m_pPCLmSSettings->userPageQuality);
1237     writeStr2OutBuff(pOutStr);
1238     sprintf(pOutStr, "%%      printer-resolution: %d\n", currRenderResolutionInteger);
1239     writeStr2OutBuff(pOutStr);
1240     sprintf(pOutStr, "%%      print-content-optimized: xxx\n");
1241     writeStr2OutBuff(pOutStr);
1242     sprintf(pOutStr, "%%      orientation-requested: %d\n", m_pPCLmSSettings->userOrientation);
1243     writeStr2OutBuff(pOutStr);
1244 
1245     if (PCLmSSettings.userCopies == 0) {
1246         PCLmSSettings.userCopies = 1;
1247     }
1248 
1249     sprintf(pOutStr, "%%      copies: %d\n", m_pPCLmSSettings->userCopies);
1250     writeStr2OutBuff(pOutStr);
1251     sprintf(pOutStr, "%%      pclm-raster-back-side: xxx\n");
1252     writeStr2OutBuff(pOutStr);
1253     if (currRenderResolutionInteger) {
1254         sprintf(pOutStr, "%%      margins-pre-applied: TRUE\n");
1255         writeStr2OutBuff(pOutStr);
1256     } else {
1257         sprintf(pOutStr, "%%      margins-pre-applied: FALSE\n");
1258         writeStr2OutBuff(pOutStr);
1259     }
1260     sprintf(pOutStr, "%%  PCLmS-Job-Ticket-End\n");
1261     writeStr2OutBuff(pOutStr);
1262 }
1263 
writePDFGrammarHeader()1264 void PCLmGenerator::writePDFGrammarHeader() {
1265     // sprintf(pOutStr,"%%============= PCLm: File Header \n"); writeStr2OutBuff(pOutStr);
1266     sprintf(pOutStr, "%%PDF-1.7\n");
1267     writeStr2OutBuff(pOutStr);
1268     sprintf(pOutStr, "%%PCLm 1.0\n");
1269     writeStr2OutBuff(pOutStr);
1270 }
1271 
RLEEncodeImage(ubyte * in,ubyte * out,int inLength)1272 int PCLmGenerator::RLEEncodeImage(ubyte *in, ubyte *out, int inLength) {
1273     ubyte *imgPtr = in;
1274     ubyte *endPtr = in + inLength;
1275     ubyte *origOut = out;
1276     ubyte c;
1277     sint32 cnt = 0;
1278 
1279     while (imgPtr < endPtr) {
1280         c = *imgPtr++;
1281         cnt = 1;
1282 
1283         // Figure out how many repeating bytes are in the image
1284         while (*imgPtr == c && cnt < inLength) {
1285             if (imgPtr > endPtr) {
1286                 break;
1287             }
1288             cnt++;
1289             imgPtr++;
1290         }
1291 
1292         if (cnt > 1) {
1293             /* If cnt > 1, then output repeating byte specification
1294              * The syntax is "byte-count repeateByte", where byte-count is 257-byte-count.
1295              * Since the cnt value is a byte, if the repeateCnt is > 128 then we need to put
1296              * out multiple repeat-blocks (Referred to as method 1) range is 128-256
1297              */
1298             while (cnt > 128) {
1299                 *out++ = 129; // i.e. 257-129==128
1300                 *out++ = c;
1301                 cnt -= 128;
1302             }
1303             // Now handle the repeats that are < 128
1304             if (cnt) {
1305                 *out++ = (257 - cnt); // i.e. cnt==2: 257-255=2
1306                 *out++ = c;
1307             }
1308         } else {
1309             /* If cnt==1, then this is a literal run - no repeating bytes found.
1310              * The syntax is "byte-count literal-run", where byte-count is < 128 and
1311              * literal-run is the non-repeating bytes of the input stream.
1312              * Referred to as method 2, range is 0-127
1313              */
1314             ubyte *start, *p;
1315             sint32 i;
1316             start = (imgPtr - 1);  // The first byte of the literal run
1317 
1318             // Now find the end of the literal run
1319             for (cnt = 1, p = start; *p != *imgPtr; p++, imgPtr++, cnt++) {
1320                 if (imgPtr >= endPtr) break;
1321             }
1322             if (!(imgPtr == endPtr)) {
1323                 imgPtr--;
1324                 // imgPtr incremented 1 too many
1325             }
1326             cnt--;
1327             // Blocks of literal bytes can't exceed 128 bytes, so output multiple
1328             //    literal-run blocks if > 128
1329             while (cnt > 128) {
1330                 *out++ = 127;
1331                 for (i = 0; i < 128; i++) {
1332                     *out++ = *start++;
1333                 }
1334                 cnt -= 128;
1335             }
1336             // Now output the leftover literal run
1337             *out++ = cnt - 1;
1338             for (i = 0; i < cnt; i++) {
1339                 *out++ = *start++;
1340             }
1341         }
1342     }
1343     // Now, write the end-of-compression marker (byte 128) into the output stream
1344     *out++ = 128;
1345     // Return the compressed size
1346     return ((int) (out - origOut));
1347 }
1348 
PCLmGenerator()1349 PCLmGenerator::PCLmGenerator() {
1350     strcpy(currMediaName, "LETTER");
1351     currDuplexDisposition = simplex;
1352     currCompressionDisposition = compressDCT;
1353     currMediaOrientationDisposition = portraitOrientation;
1354     currRenderResolution = res600;
1355     currStripHeight = STRIP_HEIGHT;
1356 
1357     // Default media h/w to letter specification
1358     mediaWidthInPixels = 0;
1359     mediaHeightInPixels = 0;
1360     mediaWidth = 612;
1361     mediaHeight = 792;
1362     destColorSpace = deviceRGB;
1363     sourceColorSpace = deviceRGB;
1364     scaleFactor = 1;
1365     jobOpen = job_closed;
1366     scratchBuffer = NULL;
1367     pageCount = 0;
1368 
1369     currRenderResolutionInteger = 600;
1370     STANDARD_SCALE = (float) currRenderResolutionInteger / (float) STANDARD_SCALE_FOR_PDF;
1371     yPosition = 0;
1372     numKids = 0;
1373 
1374     // XRefTable storage
1375     xRefIndex = 0;
1376     xRefStart = 0;
1377 
1378     objCounter = PAGES_OBJ_NUMBER + 1;
1379     totalBytesWrittenToPCLmFile = 0;
1380 
1381     // Initialize first index in xRefTable
1382     xRefTable = NULL;
1383     KidsArray = NULL;
1384 
1385     // Initialize the output Buffer
1386     allocatedOutputBuffer = NULL;
1387 
1388     // Initialize the leftover scanline logic
1389     leftoverScanlineBuffer = 0;
1390 
1391     adobeRGBCS_firstTime = true;
1392     mirrorBackside = true;
1393 
1394     topMarginInPix = 0;
1395     leftMarginInPix = 0;
1396     m_pPCLmSSettings = NULL;
1397 }
1398 
~PCLmGenerator()1399 PCLmGenerator::~PCLmGenerator() {
1400     Cleanup();
1401 }
1402 
StartJob(void ** pOutBuffer,int * iOutBufferSize)1403 int PCLmGenerator::StartJob(void **pOutBuffer, int *iOutBufferSize) {
1404     /* Allocate the output buffer; we don't know much at this point, so make the output buffer size
1405      * the worst case dimensions; when we get a startPage, we will resize it appropriately
1406      */
1407     outBuffSize = DEFAULT_OUTBUFF_SIZE;
1408     *iOutBufferSize = outBuffSize;
1409     *pOutBuffer = (ubyte *) malloc(outBuffSize); // This multipliy by 10 needs to be removed...
1410 
1411     if (NULL == *pOutBuffer) {
1412         return (errorOutAndCleanUp());
1413     }
1414 
1415     currOutBuffSize = outBuffSize;
1416 
1417     if (NULL == *pOutBuffer) {
1418         return (errorOutAndCleanUp());
1419     }
1420 
1421     allocatedOutputBuffer = *pOutBuffer;
1422     initOutBuff((char *) *pOutBuffer, outBuffSize);
1423     writePDFGrammarHeader();
1424     *iOutBufferSize = totalBytesWrittenToCurrBuff;
1425     jobOpen = job_open;
1426 
1427     return success;
1428 }
1429 
EndJob(void ** pOutBuffer,int * iOutBufferSize)1430 int PCLmGenerator::EndJob(void **pOutBuffer, int *iOutBufferSize) {
1431     if (NULL == allocatedOutputBuffer) {
1432         return (errorOutAndCleanUp());
1433     }
1434 
1435     *pOutBuffer = allocatedOutputBuffer;
1436 
1437     initOutBuff((char *) *pOutBuffer, outBuffSize);
1438 
1439     // Write PDF trailer
1440     writePDFGrammarTrailer(currSourceWidth, currSourceHeight);
1441 
1442     *iOutBufferSize = totalBytesWrittenToCurrBuff;
1443 
1444     jobOpen = job_closed;
1445 
1446     if (xRefTable) {
1447         free(xRefTable);
1448         xRefTable = NULL;
1449     }
1450     if (KidsArray) {
1451         free(KidsArray);
1452         KidsArray = NULL;
1453     }
1454 
1455     return success;
1456 }
1457 
StartPage(PCLmPageSetup * PCLmPageContent,void ** pOutBuffer,int * iOutBufferSize)1458 int PCLmGenerator::StartPage(PCLmPageSetup *PCLmPageContent, void **pOutBuffer,
1459         int *iOutBufferSize) {
1460     int numImageStrips;
1461     // Save the resolution information
1462     currRenderResolution = PCLmPageContent->destinationResolution;
1463 
1464     *pOutBuffer = allocatedOutputBuffer;
1465 
1466     if (currRenderResolution == res300) {
1467         currRenderResolutionInteger = 300;
1468     } else if (currRenderResolution == res600) {
1469         currRenderResolutionInteger = 600;
1470     } else if (currRenderResolution == res1200) {
1471         currRenderResolutionInteger = 1200;
1472     } else {
1473         assert(0);
1474     }
1475 
1476     // Recalculate STANDARD_SCALE to reflect the job resolution
1477     STANDARD_SCALE = (float) currRenderResolutionInteger / (float) STANDARD_SCALE_FOR_PDF;
1478 
1479     // Use the values set by the caller
1480     currSourceWidth = PCLmPageContent->SourceWidthPixels;
1481     currSourceHeight = PCLmPageContent->SourceHeightPixels;
1482 
1483     // Save off the media information
1484     mediaWidth = (int) (PCLmPageContent->mediaWidth);
1485     mediaHeight = (int) (PCLmPageContent->mediaHeight);
1486 
1487     // Use the values set by the caller
1488     mediaWidthInPixels = PCLmPageContent->mediaWidthInPixels;
1489     mediaHeightInPixels = PCLmPageContent->mediaHeightInPixels;
1490 
1491     topMarginInPix = (int) (((PCLmPageContent->mediaHeightOffset / STANDARD_SCALE_FOR_PDF) *
1492             currRenderResolutionInteger) + 0.50);
1493     leftMarginInPix = (int) (((PCLmPageContent->mediaWidthOffset / STANDARD_SCALE_FOR_PDF) *
1494             currRenderResolutionInteger) + 0.50);
1495 
1496     if (topMarginInPix % 16) {
1497         // Round to nearest 16 scanline boundary to ensure decompressability.
1498         int i = topMarginInPix % 16;
1499         if (i < (16 / 2)) {
1500             topMarginInPix -= i;
1501         } else {
1502             topMarginInPix += (16 - i);
1503         }
1504     }
1505 
1506     if (leftMarginInPix % 16) {
1507         // Round to nearest 16 scanline boundary to ensure decompressability.
1508         int i = leftMarginInPix % 16;
1509         if (i < (16 / 2)) {
1510             leftMarginInPix -= i;
1511         } else {
1512             leftMarginInPix += (16 - i);
1513         }
1514     }
1515 
1516     currCompressionDisposition = PCLmPageContent->compTypeRequested;
1517 
1518     if (strlen(PCLmPageContent->mediaSizeName)) {
1519         strcpy(currMediaName, PCLmPageContent->mediaSizeName);
1520     }
1521 
1522     currStripHeight = PCLmPageContent->stripHeight;
1523     if (!currStripHeight) {
1524         numImageStrips = 1;
1525         currStripHeight = currSourceHeight;
1526     } else {
1527         // Need to know how many strips will be inserted into PDF file
1528         float numImageStripsReal = ceil((float) currSourceHeight / (float) currStripHeight);
1529         numImageStrips = (int) numImageStripsReal;
1530     }
1531 
1532     if (PCLmPageContent->srcColorSpaceSpefication == grayScale) {
1533         srcNumComponents = 1;
1534     } else {
1535         srcNumComponents = 3;
1536     }
1537 
1538     if (PCLmPageContent->dstColorSpaceSpefication == grayScale) {
1539         dstNumComponents = 1;
1540     } else {
1541         dstNumComponents = 3;
1542     }
1543 
1544     currDuplexDisposition = PCLmPageContent->duplexDisposition;
1545 
1546     destColorSpace = PCLmPageContent->dstColorSpaceSpefication;
1547 
1548     // Calculate how large the output buffer needs to be based upon the page specifications
1549     int tmp_outBuffSize = mediaWidthInPixels * currStripHeight * dstNumComponents;
1550 
1551     if (tmp_outBuffSize > currOutBuffSize) {
1552         // Realloc the pOutBuffer to the correct size
1553         *pOutBuffer = realloc(*pOutBuffer, tmp_outBuffSize);
1554 
1555         if (*pOutBuffer == NULL) {
1556             // realloc failed and prev buffer not freed
1557             return errorOutAndCleanUp();
1558         }
1559 
1560         outBuffSize = currOutBuffSize = tmp_outBuffSize;
1561         allocatedOutputBuffer = *pOutBuffer;
1562         if (NULL == allocatedOutputBuffer) {
1563             return (errorOutAndCleanUp());
1564         }
1565     }
1566 
1567     initOutBuff((char *) *pOutBuffer, outBuffSize);
1568 
1569     // Keep track of the page count
1570     pageCount++;
1571 
1572     // If we are on a backside and doing duplex, prep for reverse strip order
1573     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2) && mirrorBackside) {
1574         reverseOrder = true;
1575     } else {
1576         reverseOrder = false;
1577     }
1578 
1579     // Calculate the number of injected strips, if any
1580     if (topMarginInPix) {
1581         if (topMarginInPix <= currStripHeight) {
1582             numFullInjectedStrips = 1;
1583             numFullScanlinesToInject = topMarginInPix;
1584             numPartialScanlinesToInject = 0;
1585         } else {
1586             numFullInjectedStrips = topMarginInPix / currStripHeight;
1587             numFullScanlinesToInject = currStripHeight;
1588             numPartialScanlinesToInject =
1589                     topMarginInPix - (numFullInjectedStrips * currStripHeight);
1590         }
1591     }
1592 
1593     writeJobTicket();
1594     writePDFGrammarPage(mediaWidthInPixels, mediaHeightInPixels, numImageStrips, destColorSpace);
1595     *iOutBufferSize = totalBytesWrittenToCurrBuff;
1596 
1597     if (!scratchBuffer) {
1598         // We need to pad the scratchBuffer size to allow for compression expansion (RLE can create
1599         // compressed segments that are slightly larger than the source.
1600         size_t len = (size_t) currStripHeight * mediaWidthInPixels * srcNumComponents * 2;
1601         scratchBuffer = (ubyte *) malloc(len);
1602         if (!scratchBuffer) {
1603             return errorOutAndCleanUp();
1604         }
1605     }
1606 
1607     mirrorBackside = PCLmPageContent->mirrorBackside;
1608     firstStrip = true;
1609 
1610     return success;
1611 }
1612 
EndPage(void ** pOutBuffer,int * iOutBufferSize)1613 int PCLmGenerator::EndPage(void **pOutBuffer, int *iOutBufferSize) {
1614     *pOutBuffer = allocatedOutputBuffer;
1615     initOutBuff((char *) *pOutBuffer, outBuffSize);
1616     *iOutBufferSize = totalBytesWrittenToCurrBuff;
1617 
1618     // Free up the scratchbuffer at endpage, to allow the next page to have a different size
1619     if (scratchBuffer) {
1620         free(scratchBuffer);
1621         scratchBuffer = NULL;
1622     }
1623 
1624     return success;
1625 }
1626 
Encapsulate(void * pInBuffer,int inBufferSize,int thisHeight,void ** pOutBuffer,int * iOutBufferSize)1627 int PCLmGenerator::Encapsulate(void *pInBuffer, int inBufferSize, int thisHeight,
1628         void **pOutBuffer, int *iOutBufferSize) {
1629     int numCompBytes;
1630     int scanlineWidth = mediaWidthInPixels * srcNumComponents;
1631     int numLinesThisCall = thisHeight;
1632     void *savedInBufferPtr = NULL;
1633     void *tmpBuffer = NULL;
1634     void *localInBuffer;
1635     ubyte *newStripPtr = NULL;
1636 
1637     if (leftoverScanlineBuffer) {
1638         ubyte *whereAreWe;
1639         sint32 scanlinesThisTime;
1640         // The leftover scanlines have already been processed (color-converted and flipped), so
1641         // just put them into the output buffer.
1642 
1643         // Allocate a temporary buffer to copy leftover and new data into
1644         tmpBuffer = malloc(scanlineWidth * currStripHeight);
1645         if (!tmpBuffer) {
1646             return (errorOutAndCleanUp());
1647         }
1648 
1649         // Copy leftover scanlines into tmpBuffer
1650         memcpy(tmpBuffer, leftoverScanlineBuffer, scanlineWidth * numLeftoverScanlines);
1651 
1652         whereAreWe = (ubyte *) tmpBuffer + (scanlineWidth * numLeftoverScanlines);
1653 
1654         scanlinesThisTime = currStripHeight - numLeftoverScanlines;
1655 
1656         // Copy enough scanlines from the real inBuffer to fill out the tmpBuffer
1657         memcpy(whereAreWe, pInBuffer, scanlinesThisTime * scanlineWidth);
1658 
1659         // Now copy the remaining scanlines from pInBuffer to the leftoverBuffer
1660         numLeftoverScanlines = thisHeight - scanlinesThisTime;
1661         assert(leftoverScanlineBuffer);
1662         whereAreWe = (ubyte *) pInBuffer + (scanlineWidth * numLeftoverScanlines);
1663         memcpy(leftoverScanlineBuffer, whereAreWe, scanlineWidth * numLeftoverScanlines);
1664         numLinesThisCall = thisHeight = currStripHeight;
1665 
1666         savedInBufferPtr = pInBuffer;
1667         localInBuffer = tmpBuffer;
1668     } else {
1669         localInBuffer = pInBuffer;
1670     }
1671 
1672     if (thisHeight > currStripHeight) {
1673         // Copy raw raster into leftoverScanlineBuffer
1674         ubyte *ptr;
1675         numLeftoverScanlines = thisHeight - currStripHeight;
1676         leftoverScanlineBuffer = malloc(scanlineWidth * numLeftoverScanlines);
1677         if (!leftoverScanlineBuffer) {
1678             return (errorOutAndCleanUp());
1679         }
1680         ptr = (ubyte *) localInBuffer + scanlineWidth * numLeftoverScanlines;
1681         memcpy(leftoverScanlineBuffer, ptr, scanlineWidth * numLeftoverScanlines);
1682         thisHeight = currStripHeight;
1683     }
1684 
1685     if (NULL == allocatedOutputBuffer) {
1686         if (tmpBuffer) {
1687             free(tmpBuffer);
1688         }
1689         return (errorOutAndCleanUp());
1690     }
1691     *pOutBuffer = allocatedOutputBuffer;
1692     initOutBuff((char *) *pOutBuffer, outBuffSize);
1693 
1694     if (currDuplexDisposition == duplex_longEdge && !(pageCount % 2)) {
1695         if (mirrorBackside) {
1696             prepImageForBacksideDuplex((ubyte *) localInBuffer, numLinesThisCall, currSourceWidth,
1697                     srcNumComponents);
1698         }
1699     }
1700 
1701     if (destColorSpace == grayScale &&
1702             (sourceColorSpace == deviceRGB || sourceColorSpace == adobeRGB)) {
1703         colorConvertSource(sourceColorSpace, grayScale, (ubyte *) localInBuffer, currSourceWidth,
1704                 numLinesThisCall);
1705         // Adjust the scanline width accordingly
1706         scanlineWidth = mediaWidthInPixels * dstNumComponents;
1707     }
1708 
1709     if (leftMarginInPix) {
1710         newStripPtr = shiftStripByLeftMargin((ubyte *) localInBuffer, currSourceWidth,
1711                 currStripHeight, numLinesThisCall, mediaWidthInPixels, leftMarginInPix,
1712                 destColorSpace);
1713     }
1714 
1715     bool whiteStrip = false;
1716 #ifdef SUPPORT_WHITE_STRIPS
1717     if (!firstStrip) {
1718         // PCLm does not print a blank page if all the strips are marked as "/Name /WhiteStrip"
1719         // so only apply /WhiteStrip to strips after the first
1720         whiteStrip = isWhiteStrip(pInBuffer, thisHeight * currSourceWidth * srcNumComponents);
1721     }
1722 #endif
1723 
1724     if (currCompressionDisposition == compressDCT) {
1725         if (firstStrip && topMarginInPix) {
1726             ubyte whitePt = 0xff;
1727 
1728             ubyte *tmpStrip = (ubyte *) malloc(scanlineWidth * topMarginInPix);
1729             memset(tmpStrip, whitePt, scanlineWidth * topMarginInPix);
1730 
1731             for (sint32 stripCntr = 0; stripCntr < numFullInjectedStrips; stripCntr++) {
1732                 write_JPEG_Buff(scratchBuffer, JPEG_QUALITY, mediaWidthInPixels,
1733                         (sint32) numFullScanlinesToInject, tmpStrip, currRenderResolutionInteger,
1734                         destColorSpace, &numCompBytes);
1735                 injectJPEG((char *) scratchBuffer, mediaWidthInPixels,
1736                         (sint32) numFullScanlinesToInject, numCompBytes, destColorSpace, true);
1737             }
1738 
1739             if (numPartialScanlinesToInject) {
1740                 // Handle the leftover strip
1741                 write_JPEG_Buff(scratchBuffer, JPEG_QUALITY, mediaWidthInPixels,
1742                         numPartialScanlinesToInject, tmpStrip, currRenderResolutionInteger,
1743                         destColorSpace, &numCompBytes);
1744                 injectJPEG((char *) scratchBuffer, mediaWidthInPixels, numPartialScanlinesToInject,
1745                         numCompBytes, destColorSpace, true);
1746             }
1747 
1748             free(tmpStrip);
1749         }
1750         firstStrip = false;
1751 
1752         // We are always going to compress the full strip height, even though the image may be less;
1753         // this allows the compressed images to be symmetric
1754         if (numLinesThisCall < currStripHeight) {
1755             sint32 numLeftoverBytes = (currStripHeight - numLinesThisCall) * currSourceWidth * 3;
1756             sint32 numImagedBytes = numLinesThisCall * currSourceWidth * 3;
1757 
1758             // End-of-page: we have to white-out the unused section of the source image
1759             memset((ubyte *) localInBuffer + numImagedBytes, 0xff, numLeftoverBytes);
1760         }
1761 
1762         if (newStripPtr) {
1763             write_JPEG_Buff(scratchBuffer, JPEG_QUALITY, mediaWidthInPixels, currStripHeight,
1764                     newStripPtr, currRenderResolutionInteger, destColorSpace, &numCompBytes);
1765 
1766             free(newStripPtr);
1767             newStripPtr = NULL;
1768         } else {
1769             write_JPEG_Buff(scratchBuffer, JPEG_QUALITY, mediaWidthInPixels, currStripHeight,
1770                     (JSAMPLE *) localInBuffer, currRenderResolutionInteger, destColorSpace,
1771                     &numCompBytes);
1772         }
1773 
1774         injectJPEG((char *) scratchBuffer, mediaWidthInPixels, currStripHeight, numCompBytes,
1775                 destColorSpace, whiteStrip);
1776     } else if (currCompressionDisposition == compressFlate) {
1777         uint32 len = numLinesThisCall * scanlineWidth;
1778         uLongf destSize = len;
1779         int result;
1780 
1781         if (firstStrip && topMarginInPix) {
1782             ubyte whitePt = 0xff;
1783 
1784             // We need to inject a blank image-strip with a height==topMarginInPix
1785             ubyte *tmpStrip = (ubyte *) malloc(scanlineWidth * topMarginInPix);
1786             uLongf tmpDestSize = destSize;
1787             memset(tmpStrip, whitePt, scanlineWidth * topMarginInPix);
1788 
1789             for (sint32 stripCntr = 0; stripCntr < numFullInjectedStrips; stripCntr++) {
1790                 result = compress(scratchBuffer, &tmpDestSize, (const Bytef *) tmpStrip,
1791                         scanlineWidth * numFullScanlinesToInject);
1792                 injectLZStrip(scratchBuffer, tmpDestSize, mediaWidthInPixels,
1793                         numFullScanlinesToInject, destColorSpace, true);
1794             }
1795             if (numPartialScanlinesToInject) {
1796                 result = compress(scratchBuffer, &tmpDestSize, (const Bytef *) tmpStrip,
1797                         scanlineWidth * numPartialScanlinesToInject);
1798                 injectLZStrip(scratchBuffer, tmpDestSize, mediaWidthInPixels,
1799                         numPartialScanlinesToInject, destColorSpace, true);
1800             }
1801             free(tmpStrip);
1802         }
1803         firstStrip = false;
1804 
1805         if (newStripPtr) {
1806             result = compress(scratchBuffer, &destSize, (const Bytef *) newStripPtr,
1807                     scanlineWidth * numLinesThisCall);
1808             free(newStripPtr);
1809             newStripPtr = NULL;
1810         } else {
1811             // Dump the source data
1812             result = compress(scratchBuffer, &destSize, (const Bytef *) localInBuffer,
1813                     scanlineWidth * numLinesThisCall);
1814         }
1815         injectLZStrip(scratchBuffer, destSize, mediaWidthInPixels, numLinesThisCall, destColorSpace,
1816                 whiteStrip);
1817     } else if (currCompressionDisposition == compressRLE) {
1818         int compSize;
1819         if (firstStrip && topMarginInPix) {
1820             ubyte whitePt = 0xff;
1821 
1822             // We need to inject a blank image-strip with a height==topMarginInPix
1823 
1824             ubyte *tmpStrip = (ubyte *) malloc(scanlineWidth * topMarginInPix);
1825             memset(tmpStrip, whitePt, scanlineWidth * topMarginInPix);
1826 
1827             for (sint32 stripCntr = 0; stripCntr < numFullInjectedStrips; stripCntr++) {
1828                 compSize = RLEEncodeImage(tmpStrip, scratchBuffer,
1829                         scanlineWidth * numFullScanlinesToInject);
1830                 injectRLEStrip(scratchBuffer, compSize, mediaWidthInPixels,
1831                         numFullScanlinesToInject, destColorSpace, true);
1832             }
1833 
1834             if (numPartialScanlinesToInject) {
1835                 compSize = RLEEncodeImage(tmpStrip, scratchBuffer,
1836                         scanlineWidth * numPartialScanlinesToInject);
1837                 injectRLEStrip(scratchBuffer, compSize, mediaWidthInPixels,
1838                         numPartialScanlinesToInject, destColorSpace, true);
1839             }
1840 
1841             free(tmpStrip);
1842         }
1843         firstStrip = false;
1844 
1845         if (newStripPtr) {
1846             compSize = RLEEncodeImage(newStripPtr, scratchBuffer,
1847                     scanlineWidth * numLinesThisCall);
1848             free(newStripPtr);
1849             newStripPtr = NULL;
1850         } else {
1851             compSize = RLEEncodeImage((ubyte *) localInBuffer, scratchBuffer,
1852                     scanlineWidth * numLinesThisCall);
1853         }
1854 
1855         injectRLEStrip(scratchBuffer, compSize, mediaWidthInPixels, numLinesThisCall,
1856                 destColorSpace, whiteStrip);
1857     } else {
1858         assert(0);
1859     }
1860 
1861     *iOutBufferSize = totalBytesWrittenToCurrBuff;
1862 
1863     if (savedInBufferPtr) {
1864         pInBuffer = savedInBufferPtr;
1865     }
1866 
1867     if (tmpBuffer) {
1868         free(tmpBuffer);
1869     }
1870 
1871     if (newStripPtr) {
1872         free(newStripPtr);
1873     }
1874 
1875     return success;
1876 }
1877 
GetPclmMediaDimensions(const char * mediaRequested,PCLmPageSetup * myPageInfo)1878 int PCLmGenerator::GetPclmMediaDimensions(const char *mediaRequested,
1879         PCLmPageSetup *myPageInfo) {
1880     int i = 0;
1881     int result = 99;
1882 
1883     int iRenderResolutionInteger = 0;
1884     if (myPageInfo->destinationResolution == res300) {
1885         iRenderResolutionInteger = 300;
1886     } else if (myPageInfo->destinationResolution == res600) {
1887         iRenderResolutionInteger = 600;
1888     } else if (myPageInfo->destinationResolution == res1200) {
1889         iRenderResolutionInteger = 1200;
1890     } else {
1891         assert(0);
1892     }
1893 
1894     for (i = 0; i < SUPPORTED_MEDIA_SIZE_COUNT; i++) {
1895         if (strcasecmp(mediaRequested, SupportedMediaSizes[i].PCL6Name) == 0) {
1896             myPageInfo->mediaWidth = floorf(
1897                     _MI_TO_POINTS(SupportedMediaSizes[i].WidthInInches));
1898             myPageInfo->mediaHeight = floorf(
1899                     _MI_TO_POINTS(SupportedMediaSizes[i].HeightInInches));
1900             myPageInfo->mediaWidthInPixels = floorf(
1901                     _MI_TO_PIXELS(SupportedMediaSizes[i].WidthInInches,
1902                             iRenderResolutionInteger));
1903             myPageInfo->mediaHeightInPixels = floorf(
1904                     _MI_TO_PIXELS(SupportedMediaSizes[i].HeightInInches,
1905                             iRenderResolutionInteger));
1906             result = i;
1907             break;  // we found a match, so break out of loop
1908         }
1909     }
1910 
1911     if (i == SUPPORTED_MEDIA_SIZE_COUNT) {
1912         // media size not found, defaulting to letter
1913         printf("PCLmGenerator get_pclm_media_size(): media size, %s, NOT FOUND, setting to letter",
1914                 mediaRequested);
1915         result = GetPclmMediaDimensions("LETTER", myPageInfo);
1916     }
1917 
1918     return result;
1919 }
1920 
FreeBuffer(void * pBuffer)1921 void PCLmGenerator::FreeBuffer(void *pBuffer) {
1922     if (jobOpen == job_closed && pBuffer) {
1923         if (pBuffer == allocatedOutputBuffer) {
1924             allocatedOutputBuffer = NULL;
1925         }
1926         free(pBuffer);
1927     }
1928 }
1929