1 /* libhpojip -- HP OfficeJet image-processing library. */
3 /* Copyright (C) 1995-2002 Hewlett-Packard Company
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
13 * NON-INFRINGEMENT. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 * In addition, as a special exception, Hewlett-Packard Company
21 * gives permission to link the code of this program with any
22 * version of the OpenSSL library which is distributed under a
23 * license identical to that listed in the included LICENSE.OpenSSL
24 * file, and distribute linked combinations including the two.
25 * You must obey the GNU General Public License in all respects
26 * for all of the code used other than OpenSSL. If you modify
27 * this file, you may extend this exception to your version of the
28 * file, but you are not obligated to do so. If you do not wish to
29 * do so, delete this exception statement from your version.
32 /* Original author: David Paschal (based on Mark Overton's "skel" template
33 * and a few bits and pieces from xjpg_{enc,dec}.c). */
35 /******************************************************************************\
37 * xjpg_fix.c - Fixes JPEG files to have a standard JFIF APP0 header and
38 * a correct row-count value in the SOF header.
40 ******************************************************************************
42 * Name of Global Jump-Table:
46 * Items in aXformInfo array passed into setXformSpec:
50 * Capabilities and Limitations:
52 * Looks at the header, and converts an OfficeJet APP1 short header to
53 * a standard JFIF APP0 header. Passes the resulting header and data
54 * through to the JPEG decoder in order to count the number of rows in
55 * the image. Discards the decompressed data and passes the original
56 * compressed data (possibly with modified header) to the output. At
57 * the end of the file, seeks back to the SOF header and rewrites the
60 * Able to handle JPEG files with JFIF APP0 or OfficeJet APP1 headers,
61 * but not color-fax APP1 headers or Denali-style compression (in
62 * these cases, you must do the full decode, any necessary color-space
63 * conversion, and encode).
65 * Default Input Traits, and Output Traits:
67 * trait default input output
68 * ------------------- ------------------- ------------------------
69 * iPixelsPerRow ignored based on header
70 * iBitsPerPixel ignored based on header
71 * iComponentsPerPixel ignored based on header
72 * lHorizDPI ignored based on header
73 * lVertDPI ignored based on header
74 * lNumRows ignored based on header
75 * iNumPages passed into output same as default input
76 * iPageNum passed into output same as default input
78 * Above, a "*" by an item indicates it must be valid (not negative).
80 \******************************************************************************/
84 #include "string.h" /* for memset and memcpy */
87 #define PRINTF(args...) fprintf(stderr,args)
89 /* TODO: Move this to a separate .h file: */
90 extern IP_XFORM_TBL jpgDecodeTbl;
91 extern WORD jpgDecode_getRowCountInfo(IP_XFORM_HANDLE hXform,
92 int *pRcCountup,int *pRcTraits,int *pSofOffset);
97 #define PRINT(msg,arg1,arg2) \
98 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
100 #define PRINT(msg,arg1,arg2)
103 #define CHECK_VALUE 0x4ba1dace
105 #define FUNC_STATUS static
107 #define BEND_GET_SHORT(s) (((s)[0]<<8)|((s)[1]))
108 #define BEND_SET_SHORT(s,x) ((s)[0]=((x)>>8)&0xFF,(s)[1]=(x)&0xFF)
111 IP_XFORM_HANDLE pSlaveXform; /* JPEG-decoder slave transformer. */
115 DWORD lenAddedHeader;
116 DWORD lenHeaderBuffer;
117 DWORD readyForSofRewrite;
118 DWORD dwValidChk; /* struct validity check value */
119 } JFIX_INST, *PJFIX_INST;
122 /* TODO: Move the tables to a separate common file. */
124 /* Since the firmware does not supply tables in its header,
125 * the tables used in the firmware are supplied below. */
127 /*____________________________________________________________________________
129 | Zigzag of Normal Quantization Tables |
130 |____________________________________________________________________________|
133 static const unsigned char orig_lum_quant[64] = {
134 16, 11, 12, 14, 12, 10, 16, 14,
135 13, 14, 18, 17, 16, 19, 24, 40,
136 26, 24, 22, 22, 24, 49, 35, 37,
137 29, 40, 58, 51, 61, 60, 57, 51,
138 56, 55, 64, 72, 92, 78, 64, 68,
139 87, 69, 55, 56, 80, 109, 81, 87,
140 95, 98, 103, 104, 103, 62, 77, 113,
141 121, 112, 100, 120, 92, 101, 103, 99
144 static const unsigned char orig_chrom_quant[64] = {
145 17, 18, 18, 24, 21, 24, 47, 26,
146 26, 47, 99, 66, 56, 66, 99, 99,
147 99, 99, 99, 99, 99, 99, 99, 99,
148 99, 99, 99, 99, 99, 99, 99, 99,
149 99, 99, 99, 99, 99, 99, 99, 99,
150 99, 99, 99, 99, 99, 99, 99, 99,
151 99, 99, 99, 99, 99, 99, 99, 99,
152 99, 99, 99, 99, 99, 99, 99, 99
155 /*____________________________________________________________________________
158 |____________________________________________________________________________|
161 static const unsigned char lum_DC_counts[16] = {
162 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
163 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
166 static const unsigned char lum_DC_values[12] = {
167 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
170 static const unsigned char chrom_DC_counts[16] = {
171 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
172 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
175 static const unsigned char chrom_DC_values[12] = {
176 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
179 static const unsigned char lum_AC_counts[16] = {
180 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
181 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d
184 static const unsigned char lum_AC_values[162] = {
185 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
186 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
187 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
188 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
189 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
190 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
191 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
192 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
193 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
194 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
195 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
196 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
197 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
198 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
199 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
200 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
201 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
202 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
203 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
204 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
208 static const unsigned char chrom_AC_counts[16] = {
209 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
210 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77
213 static const unsigned char chrom_AC_values[162] = {
214 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
215 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
216 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
217 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
218 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
219 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
220 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
221 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
222 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
223 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
224 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
225 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
226 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
227 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
228 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
229 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
230 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
231 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
232 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
233 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
237 /*____________________________________________________________________________
239 | scale_q_table | scales a q-table according to the q-factors |
240 |_______________|____________________________________________________________|
242 /* TODO: Reference this from a common .h file. */
243 void scale_q_table(int dc_q_factor,int ac_q_factor,int ident,
244 unsigned char *out) {
245 static const int Q_DEFAULT=20;
246 static const int FINAL_DC_INDEX=9;
249 const unsigned char *in=orig_lum_quant;
250 if (ident) in=orig_chrom_quant;
252 for (i=0; i<64; i++) {
253 val = ((*in++)*q + Q_DEFAULT/2) / Q_DEFAULT;
254 if (val < 1) val = 1;
255 if (val > 255) val = 255;
256 *out++ = (unsigned char)val;
257 if (i == FINAL_DC_INDEX) {
264 /*****************************************************************************\
266 * jpgFix_openXform - Creates a new instance of the transformer
268 *****************************************************************************
270 * This returns a handle for the new instance to be passed into
271 * all subsequent calls.
273 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
275 \*****************************************************************************/
277 FUNC_STATUS WORD jpgFix_openXform (
278 IP_XFORM_HANDLE *pXform) /* out: returned handle */
282 INSURE (pXform != NULL);
283 IP_MEM_ALLOC (sizeof(JFIX_INST), g);
285 memset (g, 0, sizeof(JFIX_INST));
286 if (jpgDecodeTbl.openXform(&g->pSlaveXform)!=IP_DONE) {
290 g->dwValidChk = CHECK_VALUE;
294 return IP_FATAL_ERROR;
299 /*****************************************************************************\
301 * jpgFix_setDefaultInputTraits - Specifies default input image traits
303 *****************************************************************************
305 * The header of the file-type handled by the transform probably does
306 * not include *all* the image traits we'd like to know. Those not
307 * specified in the file-header are filled in from info provided by
310 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
312 \*****************************************************************************/
314 FUNC_STATUS WORD jpgFix_setDefaultInputTraits (
315 IP_XFORM_HANDLE hXform, /* in: handle for xform */
316 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
320 HANDLE_TO_PTR (hXform, g);
322 return jpgDecodeTbl.setDefaultInputTraits(g->pSlaveXform,pTraits);
325 return IP_FATAL_ERROR;
330 /*****************************************************************************\
332 * jpgFix_setXformSpec - Provides xform-specific information
334 \*****************************************************************************/
336 FUNC_STATUS WORD jpgFix_setXformSpec (
337 IP_XFORM_HANDLE hXform, /* in: handle for xform */
338 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
342 HANDLE_TO_PTR (hXform, g);
344 /* Check your options in aXformInfo here, and save them.
345 * Use the INSURE macro like you'd use assert. INSURE jumps to
346 * fatal_error below if it fails.
352 return IP_FATAL_ERROR;
357 /*****************************************************************************\
359 * jpgFix_getHeaderBufSize- Returns size of input buf needed to hold header
361 \*****************************************************************************/
363 FUNC_STATUS WORD jpgFix_getHeaderBufSize (
364 IP_XFORM_HANDLE hXform, /* in: handle for xform */
365 DWORD *pdwInBufLen) /* out: buf size for parsing header */
370 HANDLE_TO_PTR (hXform, g);
372 r=jpgDecodeTbl.getHeaderBufSize(g->pSlaveXform,pdwInBufLen);
373 if (r!=IP_DONE) return r;
375 g->lenHeaderBuffer=*pdwInBufLen;
376 IP_MEM_ALLOC(g->lenHeaderBuffer,g->headerBuffer);
380 return IP_FATAL_ERROR;
385 /*****************************************************************************\
387 * jpgFix_getActualTraits - Parses header, and returns input & output traits
389 \*****************************************************************************/
392 //#define MYLOCATE(p) (void *)(p)=(g->headerBuffer+lenAddedHeader)
393 #define MYLOCATE(p) (p)=(void *)(g->headerBuffer+lenAddedHeader)
394 #define MYWRITE(p) lenAddedHeader+=sizeof(*(p))
395 #define MYWRITEBUF(data,datalen) \
397 INSURE((datalen)<=g->lenHeaderBuffer-lenAddedHeader); \
398 memcpy(g->headerBuffer+lenAddedHeader,(char *)(data),(datalen)); \
399 lenAddedHeader+=(datalen); \
402 FUNC_STATUS WORD jpgFix_getActualTraits (
403 IP_XFORM_HANDLE hXform, /* in: handle for xform */
404 DWORD dwInputAvail, /* in: # avail bytes in input buf */
405 PBYTE pbInputBuf, /* in: ptr to input buffer */
406 PDWORD pdwInputUsed, /* out: # bytes used from input buf */
407 PDWORD pdwInputNextPos,/* out: file-pos to read from next */
408 PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
409 PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
411 struct shortHeader_s {
412 unsigned char soi[2]; /* 0xFF, 0xD8 */
414 unsigned char app1[2]; /* 0xFF, 0xE1 */
415 unsigned char app1Length[2]; /* 0x00, 0x12 */
416 unsigned char height[2];
417 unsigned char width[2];
418 unsigned char xres[2];
419 unsigned char yres[2];
420 unsigned char ac_q_factor;
421 unsigned char numComponents; /* 1=gray, 3=color */
422 unsigned char xSampleFactors[2];
423 unsigned char ySampleFactors[2];
424 unsigned char dc_q_factor;
425 unsigned char reserved; /* 0x00 */
426 } *pInputHeader=(struct shortHeader_s *)pbInputBuf;
427 struct outputSoiApp0_s {
428 unsigned char soi[2]; /* 0xFF, 0xD8 */
430 unsigned char app0[2]; /* 0xFF, 0xE0 */
431 unsigned char app0Length[2]; /* 0x00, 0x10 */
432 unsigned char jfif[5]; /* "JFIF\0" */
433 unsigned char majorVersion; /* 0x01 */
434 unsigned char minorVersion; /* 0x00 */
435 unsigned char units; /* 0x01 = DPI */
436 unsigned char xres[2];
437 unsigned char yres[2];
438 unsigned char xthumb; /* 0x00 */
439 unsigned char ythumb; /* 0x00 */
442 unsigned char sof0[2]; /* 0xFF, 0xC0 */
443 unsigned char sof0Length[2]; /* 0x00, 0x?? */
444 unsigned char eight; /* 0x08 */
445 unsigned char height[2];
446 unsigned char width[2];
447 unsigned char numComponents; /* 1=gray, 3=color */
450 unsigned char iComponent;
451 unsigned char xySampleFactors;
452 unsigned char isNotFirstComponent;
453 } *pOutputSofComponent;
455 unsigned char dqt[2]; /* 0xFF, 0xDB */
456 unsigned char dqtLength[2]; /* 0x00, 0x43 */
457 unsigned char ident; /* 0=lum., 1=chrom. */
458 unsigned char elements[64];
461 unsigned char dht[2]; /* 0xFF, 0xC4 */
462 unsigned char dhtLength[2]; /* 0x00, 0x?? */
465 unsigned char hclass_ident;
466 unsigned char counts[16];
467 /* Variable-length huffval table follows. */
469 static const struct {
470 unsigned char hclass_ident;
471 const unsigned char *counts;
472 const unsigned char *huffval;
474 {0x00,lum_DC_counts,lum_DC_values},
475 {0x10,lum_AC_counts,lum_AC_values},
476 {0x01,chrom_DC_counts,chrom_DC_values},
477 {0x11,chrom_AC_counts,chrom_AC_values}
479 int dhtCountCounts[4];
481 unsigned char sos[2]; /* 0xFF, 0xDA */
482 unsigned char sosLength[2]; /* 0x00, 0x?? */
483 unsigned char numComponents; /* 1=gray, 3=color */
486 unsigned char iComponent;
487 unsigned char x00x11; /* (i==0 ? 0x00 : 0x11) */
488 } *pOutputSosComponent;
490 unsigned char zero1; /* 0x00 */
491 unsigned char sixtythree; /* 0x3F */
492 unsigned char zero2; /* 0x00 */
496 DWORD lenRemovedHeader=0,lenAddedHeader=0;
497 int imax,i,j,x,y,r,len;
499 HANDLE_TO_PTR (hXform, g);
501 /* Validate APP1 (OfficeJet short header) record.
502 * If we actually get a JFIF standard APP0 record, then
503 * skip parsing the header. */
504 if (dwInputAvail>=sizeof(*pInputHeader) &&
505 pInputHeader->soi[0]==0xFF && pInputHeader->soi[1]==0xD8 &&
506 pInputHeader->app1[0]==0xFF && pInputHeader->app1[1]==0xE1 &&
507 !pInputHeader->app1Length[0] && pInputHeader->app1Length[1]==0x12) {
509 /* Write standard JPEG/JFIF records... */
510 lenRemovedHeader=sizeof(*pInputHeader);
512 /* Start Of Image record. */
513 MYLOCATE(pOutputSoiApp0);
514 pOutputSoiApp0->soi[0]=0xFF;
515 pOutputSoiApp0->soi[1]=0xD8;
516 /* APP0 (JFIF header) record. */
517 pOutputSoiApp0->app0[0]=0xFF;
518 pOutputSoiApp0->app0[1]=0xE0;
519 pOutputSoiApp0->app0Length[0]=0x00;
520 pOutputSoiApp0->app0Length[1]=sizeof(*pOutputSoiApp0)-4;
521 strcpy((char *)pOutputSoiApp0->jfif,"JFIF");
522 pOutputSoiApp0->majorVersion=0x01;
523 pOutputSoiApp0->minorVersion=0x00;
524 pOutputSoiApp0->units=0x01;
525 pOutputSoiApp0->xres[0]=pInputHeader->xres[0];
526 pOutputSoiApp0->xres[1]=pInputHeader->xres[1];
527 pOutputSoiApp0->yres[0]=pInputHeader->yres[0];
528 pOutputSoiApp0->yres[1]=pInputHeader->yres[1];
529 pOutputSoiApp0->xthumb=0;
530 pOutputSoiApp0->ythumb=0;
531 MYWRITE(pOutputSoiApp0);
533 /* Start Of Frame record. */
534 MYLOCATE(pOutputSof0Part1);
535 pOutputSof0Part1->sof0[0]=0xFF;
536 pOutputSof0Part1->sof0[1]=0xC0;
537 pOutputSof0Part1->sof0Length[0]=0x00;
538 pOutputSof0Part1->sof0Length[1]=sizeof(*pOutputSof0Part1)-2+
539 pInputHeader->numComponents*sizeof(*pOutputSofComponent);
540 pOutputSof0Part1->eight=0x08;
541 pOutputSof0Part1->height[0]=pInputHeader->height[0];
542 pOutputSof0Part1->height[1]=pInputHeader->height[1];
543 pOutputSof0Part1->width[0]=pInputHeader->width[0];
544 pOutputSof0Part1->width[1]=pInputHeader->width[1];
545 pOutputSof0Part1->numComponents=pInputHeader->numComponents;
546 MYWRITE(pOutputSof0Part1);
547 x=BEND_GET_SHORT(pInputHeader->xSampleFactors);
548 y=BEND_GET_SHORT(pInputHeader->ySampleFactors);
549 for (i=0;i<pInputHeader->numComponents;i++) {
550 MYLOCATE(pOutputSofComponent);
551 pOutputSofComponent->iComponent=i;
552 pOutputSofComponent->xySampleFactors=
553 (((x>>(4*(3-i)))&0x0F)<<4) | ((y>>(4*(3-i)))&0x0F);
554 pOutputSofComponent->isNotFirstComponent=(!i?0:1);
555 MYWRITE(pOutputSofComponent);
558 /* Define Quantization Table record. */
559 imax=pInputHeader->numComponents>1?1:0;
560 for (i=0;i<=imax;i++) {
561 MYLOCATE(pOutputDqt);
562 pOutputDqt->dqt[0]=0xFF;
563 pOutputDqt->dqt[1]=0xDB;
564 pOutputDqt->dqtLength[0]=0x00;
565 pOutputDqt->dqtLength[1]=sizeof(*pOutputDqt)-2;
566 pOutputDqt->ident=i; /* Upper nibble=0 for 8-bit table. */
567 scale_q_table(pInputHeader->dc_q_factor,pInputHeader->ac_q_factor,
568 i,pOutputDqt->elements);
571 imax=pInputHeader->numComponents>1?4:2;
572 x=sizeof(*pOutputDhtPart1)-2;
573 for (i=0;i<imax;i++) {
575 x+=sizeof(*pOutputDhtPart2);
577 y=dhtInfo[i].counts[j];
578 dhtCountCounts[i]+=y;
582 MYLOCATE(pOutputDhtPart1);
583 pOutputDhtPart1->dht[0]=0xFF;
584 pOutputDhtPart1->dht[1]=0xC4;
585 BEND_SET_SHORT(pOutputDhtPart1->dhtLength,x);
586 MYWRITE(pOutputDhtPart1);
587 for (i=0;i<imax;i++) {
588 MYLOCATE(pOutputDhtPart2);
589 pOutputDhtPart2->hclass_ident=dhtInfo[i].hclass_ident;
590 memcpy(pOutputDhtPart2->counts,dhtInfo[i].counts,16);
591 MYWRITE(pOutputDhtPart2);
592 MYWRITEBUF(dhtInfo[i].huffval,dhtCountCounts[i]);
595 /* Start Of Scan record. */
596 MYLOCATE(pOutputSosPart1);
597 imax=pInputHeader->numComponents;
598 pOutputSosPart1->sos[0]=0xFF;
599 pOutputSosPart1->sos[1]=0xDA;
600 pOutputSosPart1->sosLength[0]=0;
601 pOutputSosPart1->sosLength[1]=sizeof(*pOutputSosPart1)-2+
602 imax*sizeof(*pOutputSosComponent)+sizeof(*pOutputSosPart2);
603 pOutputSosPart1->numComponents=imax;
604 MYWRITE(pOutputSosPart1);
605 for (i=0;i<imax;i++) {
606 MYLOCATE(pOutputSosComponent);
607 pOutputSosComponent->iComponent=i;
608 pOutputSosComponent->x00x11=(!i?0x00:0x11);
609 MYWRITE(pOutputSosComponent);
611 MYLOCATE(pOutputSosPart2);
612 pOutputSosPart2->zero1=0;
613 pOutputSosPart2->sixtythree=63;
614 pOutputSosPart2->zero2=0;
615 MYWRITE(pOutputSosPart2);
618 /* Save a copy of the (possibly rewritten) header (plus any residual
619 * data) so we can emit it later. */
620 len=dwInputAvail-(lenAddedHeader-lenRemovedHeader);
621 if (len>g->lenHeaderBuffer-lenAddedHeader) {
622 len=g->lenHeaderBuffer-lenAddedHeader;
624 memcpy(g->headerBuffer+lenAddedHeader,pbInputBuf+lenRemovedHeader,len);
626 /* Pass the (possibly rewritten) header to the slave transformer. */
627 r=jpgDecodeTbl.getActualTraits(g->pSlaveXform,
628 len+lenAddedHeader,g->headerBuffer,
629 pdwInputUsed,pdwInputNextPos,
630 pInTraits,pOutTraits);
631 if ((r&(IP_DONE|IP_READY_FOR_DATA))!=(IP_DONE|IP_READY_FOR_DATA)) {
632 return (r|IP_FATAL_ERROR);
635 g->lenHeader=*pdwInputUsed;
636 g->lenAddedHeader=lenAddedHeader-lenRemovedHeader;
637 *pdwInputUsed-=g->lenAddedHeader;
638 *pdwInputNextPos-=g->lenAddedHeader;
643 return IP_FATAL_ERROR;
648 /****************************************************************************\
650 * jpgFix_getActualBufSizes - Returns buf sizes needed for remainder of job
652 \****************************************************************************/
654 FUNC_STATUS WORD jpgFix_getActualBufSizes (
655 IP_XFORM_HANDLE hXform, /* in: handle for xform */
656 PDWORD pdwMinInBufLen, /* out: min input buf size */
657 PDWORD pdwMinOutBufLen) /* out: min output buf size */
662 HANDLE_TO_PTR (hXform, g);
664 r=jpgDecodeTbl.getActualBufSizes(g->pSlaveXform,
665 pdwMinInBufLen,pdwMinOutBufLen);
667 INSURE(*pdwMinOutBufLen<=g->lenHeaderBuffer);
669 *pdwMinOutBufLen=g->lenHeaderBuffer;
673 return IP_FATAL_ERROR;
678 /*****************************************************************************\
680 * jpgFix_convert - Converts one row
682 \*****************************************************************************/
684 FUNC_STATUS WORD jpgFix_convert (
685 IP_XFORM_HANDLE hXform,
686 DWORD dwInputAvail, /* in: # avail bytes in in-buf */
687 PBYTE pbInputBuf, /* in: ptr to in-buffer */
688 PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
689 PDWORD pdwInputNextPos, /* out: file-pos to read from next */
690 DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
691 PBYTE pbOutputBuf, /* in: ptr to out-buffer */
692 PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
693 PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
698 HANDLE_TO_PTR (hXform, g);
700 if (g->outNextPos<g->lenHeader) {
701 DWORD len=g->lenHeader-g->outNextPos;
702 if (len>dwOutputAvail) len=dwOutputAvail;
704 memcpy(pbOutputBuf,g->headerBuffer+g->outNextPos,len);
707 *pdwInputNextPos=g->lenHeader-g->lenAddedHeader;
709 *pdwOutputThisPos=g->outNextPos;
711 r|=IP_READY_FOR_DATA;
713 } else if (!g->readyForSofRewrite) {
714 DWORD dwOutputUsed,dwOutputThisPos;
715 r=jpgDecodeTbl.convert(g->pSlaveXform,
716 dwInputAvail,pbInputBuf,pdwInputUsed,pdwInputNextPos,
717 g->lenHeaderBuffer,g->headerBuffer,
718 &dwOutputUsed,&dwOutputThisPos);
719 *pdwInputNextPos-=g->lenAddedHeader;
721 g->readyForSofRewrite=1;
722 if (!*pdwInputUsed) goto rewriteSof;
725 INSURE(*pdwInputUsed<=dwOutputAvail);
726 memcpy(pbOutputBuf,pbInputBuf,*pdwInputUsed);
728 *pdwOutputUsed=*pdwInputUsed;
729 *pdwOutputThisPos=g->outNextPos;
730 g->outNextPos+=*pdwInputUsed;
736 *pdwInputNextPos=g->outNextPos-g->lenAddedHeader;
738 *pdwOutputThisPos=g->outNextPos;
739 if (g->readyForSofRewrite>0) {
740 int rcCountup,rcTraits,sofOffset;
741 r=jpgDecode_getRowCountInfo(g->pSlaveXform,
742 &rcCountup,&rcTraits,&sofOffset);
743 BEND_SET_SHORT(pbOutputBuf,rcCountup);
745 *pdwOutputThisPos=sofOffset;
746 g->readyForSofRewrite=-1;
753 return IP_FATAL_ERROR;
758 /*****************************************************************************\
760 * jpgFix_insertedData - client inserted into our output stream
762 \*****************************************************************************/
764 FUNC_STATUS WORD jpgFix_insertedData (
765 IP_XFORM_HANDLE hXform,
769 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
774 /*****************************************************************************\
776 * jpgFix_newPage - Tells us to flush this page, and start a new page
778 \*****************************************************************************/
780 FUNC_STATUS WORD jpgFix_newPage (
781 IP_XFORM_HANDLE hXform)
785 HANDLE_TO_PTR (hXform, g);
786 /* todo: return fatal error if convert is called again? */
787 return IP_DONE; /* can't insert page-breaks, so ignore this call */
790 return IP_FATAL_ERROR;
796 /*****************************************************************************\
798 * jpgFix_closeXform - Destroys this instance
800 \*****************************************************************************/
802 FUNC_STATUS WORD jpgFix_closeXform (IP_XFORM_HANDLE hXform)
806 HANDLE_TO_PTR (hXform, g);
808 if (g->pSlaveXform) jpgDecodeTbl.closeXform(g->pSlaveXform);
809 if (g->headerBuffer) IP_MEM_FREE(g->headerBuffer);
811 IP_MEM_FREE (g); /* free memory for the instance */
816 return IP_FATAL_ERROR;
821 /*****************************************************************************\
823 * jpgFixTbl - Jump-table for transform driver
825 \*****************************************************************************/
826 IP_XFORM_TBL jpgFixTbl = {
828 jpgFix_setDefaultInputTraits,
830 jpgFix_getHeaderBufSize,
831 jpgFix_getActualTraits,
832 jpgFix_getActualBufSizes,