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