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