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