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