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: Mark Overton and others.
34 * Ported to Linux by David Paschal.
37 /*****************************************************************************\
39 * xpcx.c - encoder and decoder for PCX files for Image Processor
41 *****************************************************************************
43 * Name of Global Jump-Table:
45 * pcxEncodeTbl = the encoder,
46 * pcxDecodeTbl = the decoder.
48 * Items in aXformInfo array passed into setXformSpec:
52 * Capabilities and Limitations:
54 * Handles 1 or 4 bits per pixel.
55 * Decoder discards the palette in the PCX file (todo: keep it).
56 * Encoder assumes input is internal raw format, which means that
57 * 1 and 4 bits/pixel are assumed to be grayscales, where
58 * 1 bit/pixel is [0=white, 1=black], 4 bits/pixel is [0=black, 15=white].
59 * Encoder outputs a palette for the preceding gray-ranges.
60 * If # rows is not known in input traits (negative), the encoder will
61 * re-write the header when # rows is known at the end of the page. So
62 * the output file will have a valid row-count when conversion is done.
64 * Default Input Traits, and Output Traits:
68 * trait default input output
69 * ------------------- --------------------- ------------------------
70 * iPixelsPerRow ignored based on header
71 * iBitsPerPixel ignored based on header (1 or 4)
72 * iComponentsPerPixel ignored 1
73 * lHorizDPI ignored based on header
74 * lVertDPI ignored based on header
75 * lNumRows ignored based on header
76 * iNumPages passed into output same as default input
77 * iPageNum passed into output same as default input
81 * trait default input output
82 * ------------------- --------------------- ------------------------
83 * iPixelsPerRow * passed into output same as default input
84 * iBitsPerPixel * must be 1 or 4 same as default input
85 * iComponentsPerPixel passed into output same as default input
86 * lHorizDPI passed into output same as default input
87 * lVertDPI passed into output same as default input
88 * lNumRows passed into output same as default input
89 * iNumPages passed into output same as default input
90 * iPageNum passed into output same as default input
92 * Above, a "*" by an item indicates it must be valid (not negative).
94 * Mark Overton, Feb 1998
96 \*****************************************************************************/
98 /* todo: this PCX code encodes/decodes 4-bit gray as one pixel per byte.
99 * it should be two pixels per byte.
105 #include "string.h" /* for memset and memcpy */
112 #define PRINT(msg,arg1,arg2) \
113 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
115 #define PRINT(msg,arg1,arg2)
118 #define CHECK_VALUE 0x1ce5ca7e
120 /* TODO: Make this work for big and little endian. */
121 #define LITTLE_ENDIAN (! (defined SNAKES))
124 /* PCX_INST - our instance variables */
127 IP_IMAGE_TRAITS traits; /* traits of the image */
128 DWORD dwInNextPos; /* file pos for subsequent input */
129 DWORD dwOutNextPos; /* file pos for subsequent output */
130 BOOL fDidHeader; /* already processed the header? */
131 BYTE *pPlanes; /* buffer containing separated planes */
132 UINT uBytesPerRawRow; /* number of bytes per unencoded row */
133 UINT uBytesPerPlane; /* number of bytes per plane per row */
134 UINT uRowsDone; /* number of rows converted so far */
135 DWORD dwValidChk; /* struct validity check value */
136 } PCX_INST, *PPCX_INST;
140 /*____________________________________________________________________________
142 | pcx_header_t | Each PCX file starts with this 128-byte header |
143 |______________|_____________________________________________________________|
146 BYTE PcxId; /* must be 0Ah, which means PC Paintbrush */
147 BYTE Version; /* 2=v2.8 w/ palette; 3=v2.8 w/o pal; 5=v3 w/ pal */
148 BYTE EncodingMethod; /* encoding method == 1 */
149 BYTE BitsPerPixel; /* = 1 for fax mode transfers */
150 WORD XMin; /* X position of the upper left corner */
151 WORD YMin; /* Y position of the upper left corner */
152 WORD XMax; /* X position of the bottom right corner */
153 WORD YMax; /* Y position of the bottom right corner */
154 WORD HorizResolution; /* horizontal resolution */
155 WORD VertResolution; /* vertical resolution */
156 BYTE PaletteInfo[48]; /* Palette information */
157 BYTE Reserved1; /* reserved, must be zero */
158 BYTE ColorPlanes; /* number of color planes == 1 */
159 WORD BytesPerPlane; /* bytes per plane per row */
160 BYTE Reserved2[60]; /* reserved, should be zero */
164 #define PCX_VERSION 2
165 #define PCX_HEADER_SIZE 128
168 /*____________________________________________________________________________
170 | swap_header_bytes | if big-endian machine, swaps bytes in WORD items |
171 |___________________|________________________________________________________|
173 static void swap_header_bytes (pcx_header_t *head_p)
176 #define SWAP_IT(item) \
177 head_p->item = (head_p->item << 8) | (head_p->item >> 8)
183 SWAP_IT (HorizResolution);
184 SWAP_IT (VertResolution);
185 SWAP_IT (BytesPerPlane);
191 /*____________________________________________________________________________
193 | encode_buffer | encodes inbuf (separated planes) into run-length PCX data |
194 |_______________|____________________________________________________________|
196 static UINT encode_buffer ( /* ret-val is # bytes written to outbuf */
197 PCX_INST *g, /* in: our instance variables */
198 BYTE *inbuf_p, /* in: ptr to inbuf having separated planes */
199 BYTE *outbuf_p) /* in: ptr to outbuf to get PCX run-lens */
210 inbuf_aft_p = inbuf_p + g->uBytesPerPlane * g->traits.iBitsPerPixel;
212 while (beg_run_p < inbuf_aft_p)
216 for (aft_run_p = beg_run_p+1;
217 aft_run_p<inbuf_aft_p && *aft_run_p==byt;
220 run_len = aft_run_p - beg_run_p;
223 aft_run_p = beg_run_p + 63;
226 if (run_len>1 || byt>=(BYTE)0xc0)
227 *out_p++ = (BYTE)run_len | (BYTE)0xc0;
230 beg_run_p = aft_run_p;
233 return out_p - outbuf_p;
238 /*____________________________________________________________________________
240 | decode_buffer | decodes PCX run-length data into separated planes |
241 |_______________|____________________________________________________________|
243 static UINT decode_buffer ( /* ret-val is # bytes read from inbuf */
244 PCX_INST *g, /* in: our instance variables */
245 BYTE *inbuf_p, /* in: ptr to input buffer */
246 BYTE *outbuf_p) /* in: ptr to output buffer */
256 out_aft_p = outbuf_p + g->uBytesPerPlane*g->traits.iBitsPerPixel;
258 while (out_p < out_aft_p)
262 if (byt < (BYTE)0xc0)
265 run_len = byt & (BYTE)0x3f;
266 if (run_len > (UINT) (out_aft_p - out_p))
267 run_len = out_aft_p-out_p; /* run went past end of outbuf */
268 memset (out_p, *in_p++, run_len);
273 return in_p - inbuf_p;
278 /*____________________________________________________________________________
280 | Encoding/Decoding Bilevel |
281 |____________________________________________________________________________|
286 /*____________________________________________________________________________
288 | flip_pixels | in PCX, 0=black and 1=white, so this flips all the bits |
289 |_____________|______________________________________________________________|
291 static void flip_pixels (
292 PCX_INST *g, /* our instance variables */
293 BYTE *byte_buf_p) /* ptr to buffer to be flipped */
298 buf_p = (ULONG*)byte_buf_p;
299 buf_aft_p = buf_p + ((g->uBytesPerRawRow+3) >> 2);
300 for ( ; buf_p<buf_aft_p; buf_p++)
306 static UINT encode_1 (
307 PCX_INST *g, /* in: our instance variables */
308 BYTE *inbuf_p, /* in: ptr to input buffer */
309 BYTE *outbuf_p) /* in: ptr to output buffer */
313 flip_pixels (g, inbuf_p);
314 n_bytes = encode_buffer (g, inbuf_p, outbuf_p);
315 flip_pixels (g, inbuf_p);
321 static UINT decode_1 (
322 PCX_INST *g, /* in: our instance variables */
323 BYTE *inbuf_p, /* in: ptr to input buffer */
324 BYTE *outbuf_p) /* in: ptr to output buffer */
328 used = decode_buffer (g, inbuf_p, outbuf_p);
329 flip_pixels (g, outbuf_p);
335 /*____________________________________________________________________________
337 | Encoding/Decoding 16-Level |
338 |____________________________________________________________________________|
344 /*____________________________________________________________________________
346 | pcxtable.c | Outputs table for PCX's 16-level decoder to stdout |
347 |____________|_______________________________________________________________|
351 #define little_endian 1
356 long unsigned outlong;
358 for (nib=0; nib<=15; nib++) {
360 if (nib & 0x08) outlong |= 0x10000000;
361 if (nib & 0x04) outlong |= 0x00100000;
362 if (nib & 0x02) outlong |= 0x00001000;
363 if (nib & 0x01) outlong |= 0x00000010;
366 outlong = (outlong & 0xff000000) >> 24 |
367 (outlong & 0x00ff0000) >> 8 |
368 (outlong & 0x0000ff00) << 8 |
369 (outlong & 0x000000ff) << 24;
371 _tprintf (_T("0x%08x, "), outlong);
372 if ((nib%4) == 3) _tputs(_T(""));
381 static UINT encode_4 (
382 PCX_INST *g, /* in: our instance variables */
383 BYTE *inbuf_p, /* in: ptr to input buffer */
384 BYTE *outbuf_p) /* in: ptr to output buffer */
387 #define NIB_0 0x000000f0
388 #define NIB_1 0x0000f000
389 #define NIB_2 0x00f00000
390 #define NIB_3 0xf0000000
392 #define NIB_0 0xf0000000
393 #define NIB_1 0x00f00000
394 #define NIB_2 0x0000f000
395 #define NIB_3 0x000000f0
405 /* Separate the four planes (into pPlanes) */
407 in_aft_p = (ULONG *) (inbuf_p + g->uBytesPerRawRow);
408 plane_p = g->pPlanes;
413 for (in_p=(ULONG*)inbuf_p; in_p<in_aft_p; ) {
415 quad = *in_p++ & mask;
416 if (quad & NIB_0) byt = 0x80;
417 if (quad & NIB_1) byt |= 0x40;
418 if (quad & NIB_2) byt |= 0x20;
419 if (quad & NIB_3) byt |= 0x10;
421 quad = *in_p++ & mask;
422 if (quad & NIB_0) byt |= 0x08;
423 if (quad & NIB_1) byt |= 0x04;
424 if (quad & NIB_2) byt |= 0x02;
425 if (quad & NIB_3) byt |= 0x01;
429 if (mask == 0x80808080)
434 return encode_buffer (g, g->pPlanes, outbuf_p);
439 static UINT decode_4 (
440 PCX_INST *g, /* in: our instance variables */
441 BYTE *inbuf_p, /* in: ptr to input buffer */
442 BYTE *outbuf_p) /* in: ptr to output buffer */
445 static const ULONG unscramble[16] = {
446 0x00000000, 0x10000000, 0x00100000, 0x10100000,
447 0x00001000, 0x10001000, 0x00101000, 0x10101000,
448 0x00000010, 0x10000010, 0x00100010, 0x10100010,
449 0x00001010, 0x10001010, 0x00101010, 0x10101010,
452 static const ULONG unscramble[16] = {
453 0x00000000, 0x00000010, 0x00001000, 0x00001010,
454 0x00100000, 0x00100010, 0x00101000, 0x00101010,
455 0x10000000, 0x10000010, 0x10001000, 0x10001010,
456 0x10100000, 0x10100010, 0x10101000, 0x10101010,
465 used = decode_buffer (g, inbuf_p, g->pPlanes);
467 /* Combine the separated planes (in pPlanes) back into pixels */
469 plane_p = g->pPlanes;
471 out_p = (ULONG*)outbuf_p;
472 plane_aft_p = plane_p + g->uBytesPerPlane;
473 for (; plane_p<plane_aft_p; plane_p++) {
474 *out_p++ = unscramble[*plane_p >> 4];
475 *out_p++ = unscramble[*plane_p & 15];
478 out_p = (ULONG*)outbuf_p;
479 plane_aft_p = plane_p + g->uBytesPerPlane;
480 for (; plane_p<plane_aft_p; plane_p++) {
481 *out_p++ |= unscramble[*plane_p >> 4] << 1;
482 *out_p++ |= unscramble[*plane_p & 15] << 1;
485 out_p = (ULONG*)outbuf_p;
486 plane_aft_p = plane_p + g->uBytesPerPlane;
487 for (; plane_p<plane_aft_p; plane_p++) {
488 *out_p++ |= unscramble[*plane_p >> 4] << 2;
489 *out_p++ |= unscramble[*plane_p & 15] << 2;
492 out_p = (ULONG*)outbuf_p;
493 plane_aft_p = plane_p + g->uBytesPerPlane;
494 for (; plane_p<plane_aft_p; plane_p++) {
495 *out_p++ |= unscramble[*plane_p >> 4] << 3;
496 *out_p++ |= unscramble[*plane_p & 15] << 3;
504 /*____________________________________________________________________________
506 | Encoding/Decoding 256-Level |
507 |____________________________________________________________________________|
513 static UINT encode_8 (
514 PCX_INST *g, /* in: our instance variables */
515 BYTE *inbuf_p, /* in: ptr to input buffer */
516 BYTE *outbuf_p) /* in: ptr to output buffer */
524 static UINT decode_8 (
525 PCX_INST *g, /* in: our instance variables */
526 BYTE *inbuf_p, /* in: ptr to input buffer */
527 BYTE *outbuf_p) /* in: ptr to output buffer */
533 #endif /* 256-level stuff */
538 ******************************************************************************
539 ******************************************************************************
545 ******************************************************************************
546 ******************************************************************************
551 /*****************************************************************************\
553 * pcxEncode_openXform - Creates a new instance of the transformer
555 *****************************************************************************
557 * This returns a handle for the new instance to be passed into
558 * all subsequent calls.
560 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
562 \*****************************************************************************/
564 static WORD pcxEncode_openXform (
565 IP_XFORM_HANDLE *pXform) /* out: returned handle */
569 INSURE (pXform != NULL);
570 IP_MEM_ALLOC (sizeof(PCX_INST), g);
572 memset (g, 0, sizeof(PCX_INST));
573 g->dwValidChk = CHECK_VALUE;
574 INSURE (sizeof(pcx_header_t) == PCX_HEADER_SIZE);
578 return IP_FATAL_ERROR;
583 /*****************************************************************************\
585 * pcxEncode_setDefaultInputTraits - Specifies default input image traits
587 *****************************************************************************
589 * The header of the file-type handled by the transform probably does
590 * not include *all* the image traits we'd like to know. Those not
591 * specified in the file-header are filled in from info provided by
594 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
596 \*****************************************************************************/
598 static WORD pcxEncode_setDefaultInputTraits (
599 IP_XFORM_HANDLE hXform, /* in: handle for xform */
600 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
604 HANDLE_TO_PTR (hXform, g);
605 INSURE (pTraits->iBitsPerPixel==1 || pTraits->iBitsPerPixel==4);
606 INSURE (pTraits->iPixelsPerRow > 0);
607 g->traits = *pTraits; /* a structure copy */
611 return IP_FATAL_ERROR;
616 /*****************************************************************************\
618 * pcxEncode_setXformSpec - Provides xform-specific information
620 \*****************************************************************************/
622 static WORD pcxEncode_setXformSpec (
623 IP_XFORM_HANDLE hXform, /* in: handle for xform */
624 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
628 HANDLE_TO_PTR (hXform, g);
629 /* do nothing, because we don't have any xform-specific info */
633 return IP_FATAL_ERROR;
638 /*****************************************************************************\
640 * pcxEncode_getHeaderBufSize- Returns size of input buf needed to hold header
642 \*****************************************************************************/
644 static WORD pcxEncode_getHeaderBufSize (
645 IP_XFORM_HANDLE hXform, /* in: handle for xform */
646 DWORD *pdwInBufLen) /* out: buf size for parsing header */
648 *pdwInBufLen = 0; /* no header on raw input data */
654 /*****************************************************************************\
656 * pcxEncode_getActualTraits - Parses header, and returns input & output traits
658 *****************************************************************************
660 * If depth is 1, a bilevel PCX will be encoded/decoded from/to a
661 * RASTER_BITMAP image.
663 * If depth is 4, a 16-level PCX will be encoded/decoded from/to gray data.
664 * The 4-bit gray value is in the upper nibble of each byte in the raw gray
667 * If depth is 8, a 256-level PCX will be encoded/decoded from/to gray data.
669 * If depth is 24, the PCX will be encoded/decoded from/to RGB data.
671 \*****************************************************************************/
673 static WORD pcxEncode_getActualTraits (
674 IP_XFORM_HANDLE hXform, /* in: handle for xform */
675 DWORD dwInputAvail, /* in: # avail bytes in input buf */
676 PBYTE pbInputBuf, /* in: ptr to input buffer */
677 PDWORD pdwInputUsed, /* out: # bytes used from input buf */
678 PDWORD pdwInputNextPos,/* out: file-pos to read from next */
679 PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
680 PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
684 HANDLE_TO_PTR (hXform, g);
686 /* Since there is no input header, we'll report no usage of input */
688 *pdwInputNextPos = 0;
690 /* Since we don't change traits, just copy out the default traits */
691 *pInTraits = g->traits;
692 *pOutTraits = g->traits;
694 /***************************/
695 /* Process the traits info */
696 /***************************/
698 g->uBytesPerPlane = (g->traits.iPixelsPerRow + 7) / 8;
699 g->uBytesPerRawRow = g->traits.iBitsPerPixel == 1
701 : g->traits.iPixelsPerRow;
703 PRINT (_T("pcx_encode_output_header: pixels/row=%d, n_rows=%d\n"),
704 g->traits.iPixelsPerRow, g->traits.lNumRows);
705 PRINT (_T("pcx_encode_output_header: depth=%d, uBytesPerRawRow=%d\n"),
706 g->traits.iBitsPerPixel, g->uBytesPerRawRow);
708 if (g->traits.iBitsPerPixel > 1)
709 IP_MEM_ALLOC (g->uBytesPerPlane*g->traits.iBitsPerPixel, g->pPlanes);
711 return IP_DONE | IP_READY_FOR_DATA;
714 return IP_FATAL_ERROR;
719 /****************************************************************************\
721 * pcxEncode_getActualBufSizes - Returns buf sizes needed for remainder of job
723 \****************************************************************************/
725 static WORD pcxEncode_getActualBufSizes (
726 IP_XFORM_HANDLE hXform, /* in: handle for xform */
727 PDWORD pdwMinInBufLen, /* out: min input buf size */
728 PDWORD pdwMinOutBufLen) /* out: min output buf size */
732 HANDLE_TO_PTR (hXform, g);
733 *pdwMinInBufLen = g->uBytesPerRawRow;
734 *pdwMinOutBufLen = g->traits.iBitsPerPixel * g->uBytesPerPlane * 2;
738 return IP_FATAL_ERROR;
743 /****************************************************************************\
745 * outputHeader - Only called by pcxEncode_convert
747 \****************************************************************************/
749 static WORD outputHeader (
750 PPCX_INST g, /* in: ptr to instance structure */
751 DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
752 PBYTE pbOutputBuf, /* in: ptr to out-buffer */
753 PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
754 PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
756 pcx_header_t *pPCXHeader;
757 PIP_IMAGE_TRAITS pTr;
761 *pdwOutputThisPos = 0;
762 *pdwOutputUsed = PCX_HEADER_SIZE;
763 g->dwOutNextPos = PCX_HEADER_SIZE;
764 INSURE (dwOutputAvail >= PCX_HEADER_SIZE);
767 pPCXHeader = (pcx_header_t *)pbOutputBuf;
769 pPCXHeader->PcxId = PCX_ID;
770 pPCXHeader->Version = PCX_VERSION;
771 pPCXHeader->EncodingMethod = 1;
772 pPCXHeader->BitsPerPixel = 1;
773 pPCXHeader->XMin = 0;
774 pPCXHeader->YMin = 0;
775 pPCXHeader->XMax = pTr->iPixelsPerRow - 1;
776 pPCXHeader->YMax = pTr->lNumRows<=0 ? 0 : pTr->lNumRows-1;
777 pPCXHeader->HorizResolution = (USHORT)(pTr->lHorizDPI>>16); /* todo: use width */
778 pPCXHeader->VertResolution = (USHORT)(pTr->lVertDPI >>16); /* and height? */
779 pPCXHeader->Reserved1 = 0;
780 pPCXHeader->ColorPlanes = pTr->iBitsPerPixel;
781 pPCXHeader->BytesPerPlane = g->uBytesPerPlane;
783 memset (pPCXHeader->Reserved2, 0, 60);
785 pal_p = pPCXHeader->PaletteInfo;
786 if (pTr->iBitsPerPixel == 1) {
787 memset (pal_p, 0, 48);
788 pal_p[3] = pal_p[4] = pal_p[5] = 255; /* 0=black, 1=white */
790 /* set the palette to a black-to-white gray ramp */
791 for (i=0; i<=15; i++) {
792 *pal_p++ = i << 4; /* red */
793 *pal_p++ = i << 4; /* green */
794 *pal_p++ = i << 4; /* blue */
798 swap_header_bytes (pPCXHeader);
799 return IP_READY_FOR_DATA;
802 return IP_FATAL_ERROR;
807 /*****************************************************************************\
809 * pcxEncode_convert - the work-horse routine
811 \*****************************************************************************/
813 static WORD pcxEncode_convert (
814 IP_XFORM_HANDLE hXform,
815 DWORD dwInputAvail, /* in: # avail bytes in in-buf */
816 PBYTE pbInputBuf, /* in: ptr to in-buffer */
817 PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
818 PDWORD pdwInputNextPos, /* out: file-pos to read from next */
819 DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
820 PBYTE pbOutputBuf, /* in: ptr to out-buffer */
821 PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
822 PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
825 UINT out_used = 0; /* init to zap stupid compiler warning */
827 HANDLE_TO_PTR (hXform, g);
829 /**** Output the Header if we haven't already ****/
831 if (! g->fDidHeader) {
832 g->fDidHeader = TRUE;
834 *pdwInputNextPos = 0;
835 return outputHeader (g, dwOutputAvail, pbOutputBuf,
836 pdwOutputUsed, pdwOutputThisPos);
839 /**** Check if we were told to flush ****/
841 if (pbInputBuf == NULL) {
842 PRINT (_T("pcx_encode_convert_row: Told to flush.\n"), 0, 0);
843 if (g->traits.lNumRows < 0) {
844 /* # rows wasn't known at first, so output header again
845 * now that we know the number of rows */
846 g->traits.lNumRows = g->uRowsDone;
848 *pdwInputNextPos = g->dwInNextPos;
849 return outputHeader (g, dwOutputAvail, pbOutputBuf,
850 pdwOutputUsed, pdwOutputThisPos);
853 *pdwInputUsed = *pdwOutputUsed = 0;
854 *pdwInputNextPos = g->dwInNextPos;
855 *pdwOutputThisPos = g->dwOutNextPos;
859 /**** Output a Row ****/
861 switch (g->traits.iBitsPerPixel) {
862 case 1: out_used = encode_1 (g, pbInputBuf, pbOutputBuf);
865 case 4: out_used = encode_4 (g, pbInputBuf, pbOutputBuf);
868 case 8: out_used = encode_8 (g, pbInputBuf, pbOutputBuf);
873 INSURE (dwInputAvail >= g->uBytesPerRawRow);
874 INSURE (dwOutputAvail >= out_used);
876 g->dwInNextPos += g->uBytesPerRawRow;
877 *pdwInputNextPos = g->dwInNextPos;
878 *pdwInputUsed = g->uBytesPerRawRow;
879 *pdwOutputUsed = out_used;
880 *pdwOutputThisPos = g->dwOutNextPos;
881 g->dwOutNextPos += out_used;
885 PRINT (_T("pcx_encode_convert_row: Returning, out used = %d\n"), out_used, 0);
886 return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
889 return IP_FATAL_ERROR;
894 /*****************************************************************************\
896 * pcxEncode_insertedData - client inserted into our output stream
898 \*****************************************************************************/
900 static WORD pcxEncode_insertedData (
901 IP_XFORM_HANDLE hXform,
905 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
910 /*****************************************************************************\
912 * pcxEncode_newPage - Tells us to flush this page, and start a new page
914 \*****************************************************************************/
916 static WORD pcxEncode_newPage (
917 IP_XFORM_HANDLE hXform)
921 HANDLE_TO_PTR (hXform, g);
922 /* todo: return fatal error if convert is called again? */
923 return IP_DONE; /* can't insert page-breaks, so ignore this call */
926 return IP_FATAL_ERROR;
932 /*****************************************************************************\
934 * pcxEncode_closeXform - Destroys this instance
936 \*****************************************************************************/
938 static WORD pcxEncode_closeXform (IP_XFORM_HANDLE hXform)
942 HANDLE_TO_PTR (hXform, g);
943 if (g->pPlanes != NULL)
944 IP_MEM_FREE (g->pPlanes);
946 IP_MEM_FREE (g); /* free memory for the instance */
950 return IP_FATAL_ERROR;
955 /*****************************************************************************\
957 * pcxEncodeTbl - Jump-table for encoder
959 \*****************************************************************************/
961 IP_XFORM_TBL pcxEncodeTbl = {
963 pcxEncode_setDefaultInputTraits,
964 pcxEncode_setXformSpec,
965 pcxEncode_getHeaderBufSize,
966 pcxEncode_getActualTraits,
967 pcxEncode_getActualBufSizes,
970 pcxEncode_insertedData,
977 ******************************************************************************
978 ******************************************************************************
984 ******************************************************************************
985 ******************************************************************************
990 /*****************************************************************************\
992 * pcxDecode_openXform - Creates a new instance of the transformer
994 *****************************************************************************
996 * This returns a handle for the new instance to be passed into
997 * all subsequent calls.
999 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
1001 \*****************************************************************************/
1003 static WORD pcxDecode_openXform (
1004 IP_XFORM_HANDLE *pXform) /* out: returned handle */
1006 return pcxEncode_openXform(pXform); /* allocs & zeroes a new instance */
1011 /*****************************************************************************\
1013 * pcxDecode_setDefaultInputTraits - Specifies default input image traits
1015 *****************************************************************************
1017 * The header of the file-type handled by the transform probably does
1018 * not include *all* the image traits we'd like to know. Those not
1019 * specified in the file-header are filled in from info provided by
1022 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
1024 \*****************************************************************************/
1026 static WORD pcxDecode_setDefaultInputTraits (
1027 IP_XFORM_HANDLE hXform, /* in: handle for xform */
1028 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
1032 HANDLE_TO_PTR (hXform, g);
1033 /* the PCX header will overwrite most items in traits below */
1034 g->traits = *pTraits; /* a structure copy */
1038 return IP_FATAL_ERROR;
1043 /*****************************************************************************\
1045 * pcxDecode_setXformSpec - Provides xform-specific information
1047 \*****************************************************************************/
1049 static WORD pcxDecode_setXformSpec (
1050 IP_XFORM_HANDLE hXform, /* in: handle for xform */
1051 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
1055 HANDLE_TO_PTR (hXform, g);
1056 /* do nothing, because we don't have any xform-specific info */
1060 return IP_FATAL_ERROR;
1065 /*****************************************************************************\
1067 * pcxDecode_getHeaderBufSize- Returns size of input buf needed to hold header
1069 \*****************************************************************************/
1071 static WORD pcxDecode_getHeaderBufSize (
1072 IP_XFORM_HANDLE hXform, /* in: handle for xform */
1073 DWORD *pdwInBufLen) /* out: buf size for parsing header */
1075 *pdwInBufLen = PCX_HEADER_SIZE;
1081 /*****************************************************************************\
1083 * pcxDecode_getActualTraits - Parses header, and returns input & output traits
1085 \*****************************************************************************/
1087 static WORD pcxDecode_getActualTraits (
1088 IP_XFORM_HANDLE hXform, /* in: handle for xform */
1089 DWORD dwInputAvail, /* in: # avail bytes in input buf */
1090 PBYTE pbInputBuf, /* in: ptr to input buffer */
1091 PDWORD pdwInputUsed, /* out: # bytes used from input buf */
1092 PDWORD pdwInputNextPos,/* out: file-pos to read from next */
1093 PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
1094 PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
1097 pcx_header_t *pcxhead_p;
1098 PIP_IMAGE_TRAITS pTr;
1101 ret_val = IP_DONE | IP_READY_FOR_DATA;
1102 HANDLE_TO_PTR (hXform, g);
1104 INSURE (dwInputAvail >= PCX_HEADER_SIZE);
1105 *pdwInputUsed = PCX_HEADER_SIZE;
1106 *pdwInputNextPos = PCX_HEADER_SIZE;
1107 g->dwInNextPos = PCX_HEADER_SIZE;
1109 pcxhead_p = (pcx_header_t*)pbInputBuf;
1112 swap_header_bytes (pcxhead_p);
1113 pTr->lNumRows = pcxhead_p->YMax - pcxhead_p->YMin + 1;
1114 pTr->iPixelsPerRow = pcxhead_p->XMax - pcxhead_p->XMin + 1;
1115 pTr->iBitsPerPixel = pcxhead_p->ColorPlanes;
1116 pTr->lHorizDPI = (ULONG)pcxhead_p->HorizResolution << 16;
1117 pTr->lVertDPI = (ULONG)pcxhead_p->VertResolution << 16;
1118 pTr->iComponentsPerPixel = 1;
1119 g->uBytesPerPlane = pcxhead_p->BytesPerPlane;
1120 swap_header_bytes (pcxhead_p);
1122 g->uBytesPerRawRow = pTr->iBitsPerPixel == 1
1124 : g->traits.iPixelsPerRow;
1126 if (! (pcxhead_p->PcxId == PCX_ID
1127 && pTr->iPixelsPerRow > 1
1128 && g->uBytesPerPlane == ((UINT)pTr->iPixelsPerRow+7)/8
1129 && (pTr->iBitsPerPixel==1 || pTr->iBitsPerPixel==4)))
1130 ret_val |= IP_INPUT_ERROR;
1132 if (pTr->iBitsPerPixel > 1)
1133 IP_MEM_ALLOC (g->uBytesPerPlane*pTr->iBitsPerPixel, g->pPlanes);
1135 if (pTr->lNumRows <= 1)
1136 pTr->lNumRows = -1; /* both YMax and YMin were 0; # rows is unknown */
1138 *pInTraits = *pOutTraits = g->traits; /* structure copy */
1140 PRINT (_T("pcx_decode_parse_header: depth=%d, n_rows=%d\n"),
1141 g->traits.iBitsPerPixel, g->traits.lNumRows);
1146 return IP_FATAL_ERROR;
1151 /****************************************************************************\
1153 * pcxDecode_getActualBufSizes - Returns buf sizes needed for remainder of job
1155 \****************************************************************************/
1157 static WORD pcxDecode_getActualBufSizes (
1158 IP_XFORM_HANDLE hXform, /* in: handle for xform */
1159 PDWORD pdwMinInBufLen, /* out: min input buf size */
1160 PDWORD pdwMinOutBufLen) /* out: min output buf size */
1164 HANDLE_TO_PTR (hXform, g);
1165 *pdwMinInBufLen = g->traits.iBitsPerPixel * g->uBytesPerPlane * 2;
1166 *pdwMinOutBufLen = g->uBytesPerRawRow;
1170 return IP_FATAL_ERROR;
1175 /*****************************************************************************\
1177 * pcxDecode_convert - the work-horse routine
1179 \*****************************************************************************/
1181 static WORD pcxDecode_convert (
1182 IP_XFORM_HANDLE hXform,
1183 DWORD dwInputAvail, /* in: # avail bytes in in-buf */
1184 PBYTE pbInputBuf, /* in: ptr to in-buffer */
1185 PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
1186 PDWORD pdwInputNextPos, /* out: file-pos to read from next */
1187 DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
1188 PBYTE pbOutputBuf, /* in: ptr to out-buffer */
1189 PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
1190 PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
1195 HANDLE_TO_PTR (hXform, g);
1197 if (pbInputBuf == NULL) {
1198 /* we are being told to flush */
1199 PRINT (_T("pcx_decode_convert_row: Told to flush; doing nothing.\n"), 0, 0);
1200 *pdwInputUsed = *pdwOutputUsed = 0;
1201 *pdwInputNextPos = g->dwInNextPos;
1202 *pdwOutputThisPos = g->dwOutNextPos;
1206 if (g->traits.lNumRows>=0 && g->uRowsDone==(UINT)g->traits.lNumRows) {
1207 /* discard extra data after final row */
1208 *pdwInputUsed = dwInputAvail;
1209 g->dwInNextPos += dwInputAvail;
1211 *pdwInputNextPos = g->dwInNextPos;
1212 *pdwOutputThisPos = g->dwOutNextPos;
1216 switch (g->traits.iBitsPerPixel) {
1217 case 1: in_used = decode_1 (g, pbInputBuf, pbOutputBuf);
1220 case 4: in_used = decode_4 (g, pbInputBuf, pbOutputBuf);
1223 case 8: in_used = decode_8 (g, pbInputBuf, pbOutputBuf);
1228 INSURE (dwInputAvail >= in_used);
1229 INSURE (dwOutputAvail >= g->uBytesPerRawRow);
1231 g->dwInNextPos += in_used;
1232 *pdwInputNextPos = g->dwInNextPos;
1233 *pdwInputUsed = in_used;
1234 *pdwOutputUsed = g->uBytesPerRawRow;
1235 *pdwOutputThisPos = g->dwOutNextPos;
1236 g->dwOutNextPos += g->uBytesPerRawRow;
1240 PRINT (_T("pcx_decode_convert_row: Returning, in used = %d\n"), in_used, 0);
1241 return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
1244 return IP_FATAL_ERROR;
1249 /*****************************************************************************\
1251 * pcxDecode_insertedData - client inserted into our output stream
1253 \*****************************************************************************/
1255 static WORD pcxDecode_insertedData (
1256 IP_XFORM_HANDLE hXform,
1260 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
1265 /*****************************************************************************\
1267 * pcxDecode_newPage - Tells us to flush this page, and start a new page
1269 \*****************************************************************************/
1271 static WORD pcxDecode_newPage (
1272 IP_XFORM_HANDLE hXform)
1276 HANDLE_TO_PTR (hXform, g);
1277 /* todo: return fatal error if convert is called again? */
1278 return IP_DONE; /* can't insert page-breaks, so ignore this call */
1281 return IP_FATAL_ERROR;
1286 /*****************************************************************************\
1288 * pcxDecode_closeXform - Destroys this instance
1290 \*****************************************************************************/
1292 static WORD pcxDecode_closeXform (IP_XFORM_HANDLE hXform)
1294 return pcxEncode_closeXform (hXform);
1299 /*****************************************************************************\
1301 * pcxDecodeTbl - Jump-table for Decoder
1303 \*****************************************************************************/
1305 IP_XFORM_TBL pcxDecodeTbl = {
1306 pcxDecode_openXform,
1307 pcxDecode_setDefaultInputTraits,
1308 pcxDecode_setXformSpec,
1309 pcxDecode_getHeaderBufSize,
1310 pcxDecode_getActualTraits,
1311 pcxDecode_getActualBufSizes,
1314 pcxDecode_insertedData,
1315 pcxDecode_closeXform