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
44static 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 */
55static 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
90bool 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
102void 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
127int PCLmGenerator::errorOutAndCleanUp() {
128    Cleanup();
129    jobOpen = job_errored;
130    return genericFailure;
131}
132
133static sint32 startXRef = 0;
134static sint32 endXRef = 0;
135
136/*
137 * DO NOT EDIT UNTIL YOU READ THE HEADER FILE DESCRIPTION.
138 */
139void 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
187bool 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
206bool 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
222void PCLmGenerator::initOutBuff(char *buff, sint32 size) {
223    currBuffPtr = outBuffPtr = buff;
224    outBuffSize = size;
225    totalBytesWrittenToCurrBuff = 0;
226    memset(buff, 0, size);
227}
228
229void 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
240void 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
251int PCLmGenerator::statOutputFileSize() {
252    addXRef(totalBytesWrittenToPCLmFile);
253    return (1);
254}
255
256void 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
359bool 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
419bool 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
438int 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
527int 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
616void 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
651int 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 */
745void 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
765void 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 */
992static 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
1026bool 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
1112bool 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
1170void 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
1264void 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
1272int 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
1349PCLmGenerator::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
1399PCLmGenerator::~PCLmGenerator() {
1400    Cleanup();
1401}
1402
1403int 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
1430int 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
1458int 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
1613int 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
1627int 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
1878int 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
1921void PCLmGenerator::FreeBuffer(void *pBuffer) {
1922    if (jobOpen == job_closed && pBuffer) {
1923        if (pBuffer == allocatedOutputBuffer) {
1924            allocatedOutputBuffer = NULL;
1925        }
1926        free(pBuffer);
1927    }
1928}
1929