Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xpcx.c
1 /* libhpojip -- HP OfficeJet image-processing library. */
2
3 /* Copyright (C) 1995-2002 Hewlett-Packard Company
4  *
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.
9  *
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.
14  *
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,
18  * MA 02111-1307, USA.
19  *
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.
30  */
31
32 /* Original author: Mark Overton and others.
33  *
34  * Ported to Linux by David Paschal.
35  */
36
37 /*****************************************************************************\
38  *
39  * xpcx.c - encoder and decoder for PCX files for Image Processor
40  *
41  *****************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    pcxEncodeTbl = the encoder,
46  *    pcxDecodeTbl = the decoder.
47  *
48  * Items in aXformInfo array passed into setXformSpec:
49  *
50  *    none
51  *
52  * Capabilities and Limitations:
53  *
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.
63  *
64  * Default Input Traits, and Output Traits:
65  *
66  *    For decoder:
67  *
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
78  *
79  *    For encoder:
80  *
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
91  *
92  *    Above, a "*" by an item indicates it must be valid (not negative).
93  *
94  * Mark Overton, Feb 1998
95  *
96 \*****************************************************************************/
97
98 /* todo: this PCX code encodes/decodes 4-bit gray as one pixel per byte.
99  *       it should be two pixels per byte.
100  */
101
102
103 #include "hpip.h"
104 #include "ipdefs.h"
105 #include "string.h"    /* for memset and memcpy */
106
107
108 #if 0
109     #include "stdio.h"
110     #include <tchar.h>
111
112     #define PRINT(msg,arg1,arg2) \
113         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
114 #else
115     #define PRINT(msg,arg1,arg2)
116 #endif
117
118 #define CHECK_VALUE 0x1ce5ca7e
119
120 /* TODO: Make this work for big and little endian. */
121 #define LITTLE_ENDIAN  (! (defined SNAKES))
122
123
124 /* PCX_INST - our instance variables */
125
126 typedef struct {
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;
137
138
139
140 /*____________________________________________________________________________
141  |              |                                                             |
142  | pcx_header_t | Each PCX file starts with this 128-byte header              |
143  |______________|_____________________________________________________________|
144 */
145 typedef struct {
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 */
161 } pcx_header_t;
162
163 #define PCX_ID           0x0A
164 #define PCX_VERSION      2
165 #define PCX_HEADER_SIZE  128
166
167
168 /*____________________________________________________________________________
169  |                   |                                                        |
170  | swap_header_bytes | if big-endian machine, swaps bytes in WORD items       |
171  |___________________|________________________________________________________|
172 */
173 static void swap_header_bytes (pcx_header_t *head_p)
174 {
175 #if ! LITTLE_ENDIAN
176     #define SWAP_IT(item)  \
177         head_p->item = (head_p->item << 8) | (head_p->item >> 8)
178
179     SWAP_IT (XMin);
180     SWAP_IT (YMin);
181     SWAP_IT (XMax);
182     SWAP_IT (YMax);
183     SWAP_IT (HorizResolution);
184     SWAP_IT (VertResolution);
185     SWAP_IT (BytesPerPlane);
186 #endif
187 }
188
189
190
191 /*____________________________________________________________________________
192  |               |                                                            |
193  | encode_buffer | encodes inbuf (separated planes) into run-length PCX data  |
194  |_______________|____________________________________________________________|
195 */
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 */
200 {
201     BYTE *out_p;
202     BYTE *beg_run_p;
203     BYTE *aft_run_p;
204     BYTE *inbuf_aft_p;
205     BYTE  byt;
206     UINT  run_len;
207
208     out_p = outbuf_p;
209     beg_run_p = inbuf_p;
210     inbuf_aft_p = inbuf_p + g->uBytesPerPlane * g->traits.iBitsPerPixel;
211
212     while (beg_run_p < inbuf_aft_p)
213     {
214         byt = *beg_run_p;
215
216         for (aft_run_p = beg_run_p+1;
217              aft_run_p<inbuf_aft_p && *aft_run_p==byt;
218              aft_run_p++) ;
219
220         run_len = aft_run_p - beg_run_p;
221         if (run_len > 63) {
222             run_len = 63;
223             aft_run_p = beg_run_p + 63;
224         }
225
226         if (run_len>1 || byt>=(BYTE)0xc0)
227             *out_p++ = (BYTE)run_len | (BYTE)0xc0;
228         *out_p++ = byt;
229
230         beg_run_p = aft_run_p;
231     }
232
233     return out_p - outbuf_p;
234 }
235
236
237
238 /*____________________________________________________________________________
239  |               |                                                            |
240  | decode_buffer | decodes PCX run-length data into separated planes          |
241  |_______________|____________________________________________________________|
242 */
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   */
247 {
248     BYTE *in_p;
249     BYTE *out_p;
250     BYTE *out_aft_p;
251     UINT  run_len;
252     BYTE  byt;
253
254     in_p = inbuf_p;
255     out_p = outbuf_p;
256     out_aft_p = outbuf_p + g->uBytesPerPlane*g->traits.iBitsPerPixel;
257
258     while (out_p < out_aft_p)
259     {
260         byt = *in_p++;
261
262         if (byt < (BYTE)0xc0)
263             *out_p++ = byt;
264         else {
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);
269             out_p += run_len;
270         }
271     }
272
273     return in_p - inbuf_p;
274 }
275
276
277
278 /*____________________________________________________________________________
279  |                                                                            |
280  |                     Encoding/Decoding Bilevel                              |
281  |____________________________________________________________________________|
282 */
283
284
285
286 /*____________________________________________________________________________
287  |             |                                                              |
288  | flip_pixels | in PCX, 0=black and 1=white, so this flips all the bits      |
289  |_____________|______________________________________________________________|
290 */
291 static void flip_pixels (
292     PCX_INST *g,            /* our instance variables      */
293     BYTE     *byte_buf_p)   /* ptr to buffer to be flipped */
294 {
295     ULONG *buf_p;
296     ULONG *buf_aft_p;
297
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++)
301         *buf_p = ~ *buf_p;
302 }
303
304
305
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   */
310 {
311     UINT n_bytes;
312
313     flip_pixels (g, inbuf_p);
314     n_bytes = encode_buffer (g, inbuf_p, outbuf_p);
315     flip_pixels (g, inbuf_p);
316     return n_bytes;
317 }
318
319
320
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   */
325 {
326     UINT used;
327
328     used = decode_buffer (g, inbuf_p, outbuf_p);
329     flip_pixels (g, outbuf_p);
330     return used;
331 }
332
333
334
335 /*____________________________________________________________________________
336  |                                                                            |
337  |                     Encoding/Decoding 16-Level                             |
338  |____________________________________________________________________________|
339 */
340
341
342 #if 0
343
344 /*____________________________________________________________________________
345  |            |                                                               |
346  | pcxtable.c | Outputs table for PCX's 16-level decoder to stdout            |
347  |____________|_______________________________________________________________|
348 */
349
350 #include <stdio.h>
351 #define little_endian 1
352
353 void main (void)
354 {
355     unsigned nib;
356     long unsigned outlong;
357
358     for (nib=0; nib<=15; nib++) {
359         outlong = 0;
360         if (nib & 0x08) outlong |= 0x10000000;
361         if (nib & 0x04) outlong |= 0x00100000;
362         if (nib & 0x02) outlong |= 0x00001000;
363         if (nib & 0x01) outlong |= 0x00000010;
364
365         if (little_endian)
366             outlong = (outlong & 0xff000000) >> 24  |
367                       (outlong & 0x00ff0000) >>  8  |
368                       (outlong & 0x0000ff00) <<  8  |
369                       (outlong & 0x000000ff) << 24;
370
371         _tprintf (_T("0x%08x, "), outlong);
372         if ((nib%4) == 3) _tputs(_T(""));
373     }
374     _tputs (_T(""));
375 }
376
377 #endif
378
379
380
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   */
385 {
386     #if LITTLE_ENDIAN
387         #define NIB_0 0x000000f0
388         #define NIB_1 0x0000f000
389         #define NIB_2 0x00f00000
390         #define NIB_3 0xf0000000
391     #else
392         #define NIB_0 0xf0000000
393         #define NIB_1 0x00f00000
394         #define NIB_2 0x0000f000
395         #define NIB_3 0x000000f0
396     #endif
397
398     ULONG *in_p;
399     ULONG *in_aft_p;
400     BYTE  *plane_p;
401     ULONG  quad;
402     ULONG  mask;
403     BYTE   byt;
404
405     /* Separate the four planes (into pPlanes) */
406
407     in_aft_p = (ULONG *) (inbuf_p + g->uBytesPerRawRow);
408     plane_p = g->pPlanes;
409     mask = 0x10101010;
410
411     while (TRUE)
412     {
413         for (in_p=(ULONG*)inbuf_p; in_p<in_aft_p; ) {
414             byt = 0;
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;
420
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;
426             *plane_p++ = byt;
427         }
428
429         if (mask == 0x80808080)
430             break;
431         mask <<= 1;
432     }
433
434     return encode_buffer (g, g->pPlanes, outbuf_p);
435 }
436
437
438
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   */
443 {
444     #if LITTLE_ENDIAN
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,
450         };
451     #else
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,
457         };
458     #endif
459
460     UINT    used;
461     BYTE  *plane_p;
462     BYTE  *plane_aft_p;
463     ULONG *out_p;
464
465     used = decode_buffer (g, inbuf_p, g->pPlanes);
466
467     /* Combine the separated planes (in pPlanes) back into pixels */
468
469     plane_p = g->pPlanes;
470
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];
476     }
477
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;
483     }
484
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;
490     }
491
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;
497     }
498
499     return used;
500 }
501
502
503
504 /*____________________________________________________________________________
505  |                                                                            |
506  |                     Encoding/Decoding 256-Level                            |
507  |____________________________________________________________________________|
508 */
509
510
511 #if 0
512
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   */
517 {
518     assert (0);
519     return 0;
520 }
521
522
523
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   */
528 {
529     assert (0);
530     return 0;
531 }
532
533 #endif   /* 256-level stuff */
534
535
536
537 /*
538 ******************************************************************************
539 ******************************************************************************
540 **
541 **
542 **                              E N C O D E R
543 **
544 **
545 ******************************************************************************
546 ******************************************************************************
547 */
548
549
550
551 /*****************************************************************************\
552  *
553  * pcxEncode_openXform - Creates a new instance of the transformer
554  *
555  *****************************************************************************
556  *
557  * This returns a handle for the new instance to be passed into
558  * all subsequent calls.
559  *
560  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
561  *
562 \*****************************************************************************/
563
564 static WORD pcxEncode_openXform (
565     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
566 {
567     PPCX_INST g;
568
569     INSURE (pXform != NULL);
570     IP_MEM_ALLOC (sizeof(PCX_INST), g);
571     *pXform = g;
572     memset (g, 0, sizeof(PCX_INST));
573     g->dwValidChk = CHECK_VALUE;
574     INSURE (sizeof(pcx_header_t) == PCX_HEADER_SIZE);
575     return IP_DONE;
576
577     fatal_error:
578     return IP_FATAL_ERROR;
579 }
580
581
582
583 /*****************************************************************************\
584  *
585  * pcxEncode_setDefaultInputTraits - Specifies default input image traits
586  *
587  *****************************************************************************
588  *
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
592  * this routine.
593  *
594  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
595  *
596 \*****************************************************************************/
597
598 static WORD pcxEncode_setDefaultInputTraits (
599     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
600     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
601 {
602     PPCX_INST g;
603
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 */
608     return IP_DONE;
609
610     fatal_error:
611     return IP_FATAL_ERROR;
612 }
613
614
615
616 /*****************************************************************************\
617  *
618  * pcxEncode_setXformSpec - Provides xform-specific information
619  *
620 \*****************************************************************************/
621
622 static WORD pcxEncode_setXformSpec (
623     IP_XFORM_HANDLE  hXform,         /* in: handle for xform */
624     DWORD_OR_PVOID   aXformInfo[])   /* in: xform information */
625 {
626     PPCX_INST g;
627
628     HANDLE_TO_PTR (hXform, g);
629     /* do nothing, because we don't have any xform-specific info */
630     return IP_DONE;
631
632     fatal_error:
633     return IP_FATAL_ERROR;
634 }
635
636
637
638 /*****************************************************************************\
639  *
640  * pcxEncode_getHeaderBufSize- Returns size of input buf needed to hold header
641  *
642 \*****************************************************************************/
643
644 static WORD pcxEncode_getHeaderBufSize (
645     IP_XFORM_HANDLE   hXform,         /* in:  handle for xform */
646     DWORD            *pdwInBufLen)    /* out: buf size for parsing header */
647 {
648     *pdwInBufLen = 0;   /* no header on raw input data */
649     return IP_DONE;
650 }
651
652
653
654 /*****************************************************************************\
655  *
656  * pcxEncode_getActualTraits - Parses header, and returns input & output traits
657  *
658  *****************************************************************************
659  *
660  * If depth is 1, a bilevel PCX will be encoded/decoded from/to a
661  * RASTER_BITMAP image.
662  *
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
665  * data.
666  *
667  * If depth is 8, a 256-level PCX will be encoded/decoded from/to gray data.
668  *
669  * If depth is 24, the PCX will be encoded/decoded from/to RGB data.
670  *
671 \*****************************************************************************/
672
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 */
681 {
682     PPCX_INST g;
683
684     HANDLE_TO_PTR (hXform, g);
685
686     /* Since there is no input header, we'll report no usage of input */
687     *pdwInputUsed    = 0;
688     *pdwInputNextPos = 0;
689
690     /* Since we don't change traits, just copy out the default traits */
691     *pInTraits  = g->traits;
692     *pOutTraits = g->traits;
693
694       /***************************/
695      /* Process the traits info */
696     /***************************/
697
698     g->uBytesPerPlane = (g->traits.iPixelsPerRow + 7) / 8;
699     g->uBytesPerRawRow = g->traits.iBitsPerPixel == 1
700                              ? g->uBytesPerPlane
701                              : g->traits.iPixelsPerRow;
702
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);
707
708     if (g->traits.iBitsPerPixel > 1)
709         IP_MEM_ALLOC (g->uBytesPerPlane*g->traits.iBitsPerPixel, g->pPlanes);
710
711     return IP_DONE | IP_READY_FOR_DATA;
712
713     fatal_error:
714     return IP_FATAL_ERROR;
715 }
716
717
718
719 /****************************************************************************\
720  *
721  * pcxEncode_getActualBufSizes - Returns buf sizes needed for remainder of job
722  *
723 \****************************************************************************/
724
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 */
729 {
730     PPCX_INST g;
731
732     HANDLE_TO_PTR (hXform, g);
733     *pdwMinInBufLen  = g->uBytesPerRawRow;
734     *pdwMinOutBufLen = g->traits.iBitsPerPixel * g->uBytesPerPlane * 2;
735     return IP_DONE;
736
737     fatal_error:
738     return IP_FATAL_ERROR;
739 }
740
741
742
743 /****************************************************************************\
744  *
745  * outputHeader - Only called by pcxEncode_convert
746  *
747 \****************************************************************************/
748
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 */
755 {
756     pcx_header_t    *pPCXHeader;
757     PIP_IMAGE_TRAITS pTr;
758     BYTE            *pal_p;
759     UINT             i;
760
761     *pdwOutputThisPos = 0;
762     *pdwOutputUsed  = PCX_HEADER_SIZE;
763     g->dwOutNextPos = PCX_HEADER_SIZE;
764     INSURE (dwOutputAvail >= PCX_HEADER_SIZE);
765
766     pTr = &g->traits;
767     pPCXHeader = (pcx_header_t *)pbOutputBuf;
768
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;
782
783     memset (pPCXHeader->Reserved2, 0, 60);
784
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 */
789     } else {
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  */
795         }
796     }
797
798     swap_header_bytes (pPCXHeader);
799     return IP_READY_FOR_DATA;
800
801     fatal_error:
802     return IP_FATAL_ERROR;
803 }
804
805
806
807 /*****************************************************************************\
808  *
809  * pcxEncode_convert - the work-horse routine
810  *
811 \*****************************************************************************/
812
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 */
823 {
824     PPCX_INST g;
825     UINT      out_used = 0;  /* init to zap stupid compiler warning */
826
827     HANDLE_TO_PTR (hXform, g);
828
829     /**** Output the Header if we haven't already ****/
830
831     if (! g->fDidHeader) {
832         g->fDidHeader = TRUE;
833         *pdwInputUsed    = 0;
834         *pdwInputNextPos = 0;
835         return outputHeader (g, dwOutputAvail, pbOutputBuf,
836                              pdwOutputUsed, pdwOutputThisPos);
837     }
838
839     /**** Check if we were told to flush ****/
840
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;
847             *pdwInputUsed    = 0;
848             *pdwInputNextPos = g->dwInNextPos;
849             return outputHeader (g, dwOutputAvail, pbOutputBuf,
850                                  pdwOutputUsed, pdwOutputThisPos);
851         }
852
853         *pdwInputUsed = *pdwOutputUsed = 0;
854         *pdwInputNextPos  = g->dwInNextPos;
855         *pdwOutputThisPos = g->dwOutNextPos;
856         return IP_DONE;
857     }
858
859     /**** Output a Row ****/
860
861     switch (g->traits.iBitsPerPixel) {
862         case 1:  out_used = encode_1 (g, pbInputBuf, pbOutputBuf);
863                  break;
864
865         case 4:  out_used = encode_4 (g, pbInputBuf, pbOutputBuf);
866                  break;
867         #if 0
868         case 8:  out_used = encode_8 (g, pbInputBuf, pbOutputBuf);
869                  break;
870         #endif
871     }
872
873     INSURE (dwInputAvail  >= g->uBytesPerRawRow);
874     INSURE (dwOutputAvail >= out_used);
875
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;
882
883     g->uRowsDone += 1;
884
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;
887
888     fatal_error:
889     return IP_FATAL_ERROR;
890 }
891
892
893
894 /*****************************************************************************\
895  *
896  * pcxEncode_insertedData - client inserted into our output stream
897  *
898 \*****************************************************************************/
899
900 static WORD pcxEncode_insertedData (
901     IP_XFORM_HANDLE hXform,
902     DWORD           dwNumBytes)
903 {
904     fatalBreakPoint ();
905     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
906 }
907
908
909
910 /*****************************************************************************\
911  *
912  * pcxEncode_newPage - Tells us to flush this page, and start a new page
913  *
914 \*****************************************************************************/
915
916 static WORD pcxEncode_newPage (
917     IP_XFORM_HANDLE hXform)
918 {
919     PPCX_INST g;
920
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 */
924
925     fatal_error:
926     return IP_FATAL_ERROR;
927
928 }
929
930
931
932 /*****************************************************************************\
933  *
934  * pcxEncode_closeXform - Destroys this instance
935  *
936 \*****************************************************************************/
937
938 static WORD pcxEncode_closeXform (IP_XFORM_HANDLE hXform)
939 {
940     PPCX_INST g;
941
942     HANDLE_TO_PTR (hXform, g);
943     if (g->pPlanes != NULL)
944         IP_MEM_FREE (g->pPlanes);
945     g->dwValidChk = 0;
946     IP_MEM_FREE (g);       /* free memory for the instance */
947     return IP_DONE;
948
949     fatal_error:
950     return IP_FATAL_ERROR;
951 }
952
953
954
955 /*****************************************************************************\
956  *
957  * pcxEncodeTbl - Jump-table for encoder
958  *
959 \*****************************************************************************/
960
961 IP_XFORM_TBL pcxEncodeTbl = {
962     pcxEncode_openXform,
963     pcxEncode_setDefaultInputTraits,
964     pcxEncode_setXformSpec,
965     pcxEncode_getHeaderBufSize,
966     pcxEncode_getActualTraits,
967     pcxEncode_getActualBufSizes,
968     pcxEncode_convert,
969     pcxEncode_newPage,
970     pcxEncode_insertedData,
971     pcxEncode_closeXform
972 };
973
974
975
976 /*
977 ******************************************************************************
978 ******************************************************************************
979 **
980 **
981 **                              D E C O D E R
982 **
983 **
984 ******************************************************************************
985 ******************************************************************************
986 */
987
988
989
990 /*****************************************************************************\
991  *
992  * pcxDecode_openXform - Creates a new instance of the transformer
993  *
994  *****************************************************************************
995  *
996  * This returns a handle for the new instance to be passed into
997  * all subsequent calls.
998  *
999  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
1000  *
1001 \*****************************************************************************/
1002
1003 static WORD pcxDecode_openXform (
1004     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
1005 {
1006     return pcxEncode_openXform(pXform);   /* allocs & zeroes a new instance */
1007 }
1008
1009
1010
1011 /*****************************************************************************\
1012  *
1013  * pcxDecode_setDefaultInputTraits - Specifies default input image traits
1014  *
1015  *****************************************************************************
1016  *
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
1020  * this routine.
1021  *
1022  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
1023  *
1024 \*****************************************************************************/
1025
1026 static WORD pcxDecode_setDefaultInputTraits (
1027     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
1028     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
1029 {
1030     PPCX_INST g;
1031
1032     HANDLE_TO_PTR (hXform, g);
1033     /* the PCX header will overwrite most items in traits below */
1034     g->traits = *pTraits;   /* a structure copy */
1035     return IP_DONE;
1036
1037     fatal_error:
1038     return IP_FATAL_ERROR;
1039 }
1040
1041
1042
1043 /*****************************************************************************\
1044  *
1045  * pcxDecode_setXformSpec - Provides xform-specific information
1046  *
1047 \*****************************************************************************/
1048
1049 static WORD pcxDecode_setXformSpec (
1050     IP_XFORM_HANDLE  hXform,         /* in: handle for xform */
1051     DWORD_OR_PVOID   aXformInfo[])   /* in: xform information */
1052 {
1053     PPCX_INST g;
1054
1055     HANDLE_TO_PTR (hXform, g);
1056     /* do nothing, because we don't have any xform-specific info */
1057     return IP_DONE;
1058
1059     fatal_error:
1060     return IP_FATAL_ERROR;
1061 }
1062
1063
1064
1065 /*****************************************************************************\
1066  *
1067  * pcxDecode_getHeaderBufSize- Returns size of input buf needed to hold header
1068  *
1069 \*****************************************************************************/
1070
1071 static WORD pcxDecode_getHeaderBufSize (
1072     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
1073     DWORD           *pdwInBufLen)    /* out: buf size for parsing header */
1074 {
1075     *pdwInBufLen = PCX_HEADER_SIZE;
1076     return IP_DONE;
1077 }
1078
1079
1080
1081 /*****************************************************************************\
1082  *
1083  * pcxDecode_getActualTraits - Parses header, and returns input & output traits
1084  *
1085 \*****************************************************************************/
1086
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 */
1095 {
1096     PPCX_INST         g;
1097     pcx_header_t     *pcxhead_p;
1098     PIP_IMAGE_TRAITS  pTr;
1099     WORD              ret_val;
1100
1101     ret_val = IP_DONE | IP_READY_FOR_DATA;
1102     HANDLE_TO_PTR (hXform, g);
1103
1104     INSURE (dwInputAvail >= PCX_HEADER_SIZE);
1105     *pdwInputUsed        = PCX_HEADER_SIZE;
1106     *pdwInputNextPos     = PCX_HEADER_SIZE;
1107     g->dwInNextPos       = PCX_HEADER_SIZE;
1108
1109     pcxhead_p = (pcx_header_t*)pbInputBuf;
1110     pTr = &g->traits;
1111
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);
1121
1122     g->uBytesPerRawRow = pTr->iBitsPerPixel == 1
1123                              ? g->uBytesPerPlane
1124                              : g->traits.iPixelsPerRow;
1125
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;
1131
1132     if (pTr->iBitsPerPixel > 1)
1133         IP_MEM_ALLOC (g->uBytesPerPlane*pTr->iBitsPerPixel, g->pPlanes);
1134
1135     if (pTr->lNumRows <= 1)
1136         pTr->lNumRows = -1; /* both YMax and YMin were 0; # rows is unknown */
1137
1138     *pInTraits = *pOutTraits = g->traits;   /* structure copy */
1139
1140     PRINT (_T("pcx_decode_parse_header: depth=%d, n_rows=%d\n"),
1141            g->traits.iBitsPerPixel, g->traits.lNumRows);
1142
1143     return ret_val;
1144
1145     fatal_error:
1146     return IP_FATAL_ERROR;
1147 }
1148
1149
1150
1151 /****************************************************************************\
1152  *
1153  * pcxDecode_getActualBufSizes - Returns buf sizes needed for remainder of job
1154  *
1155 \****************************************************************************/
1156
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 */
1161 {
1162     PPCX_INST g;
1163
1164     HANDLE_TO_PTR (hXform, g);
1165     *pdwMinInBufLen  = g->traits.iBitsPerPixel * g->uBytesPerPlane * 2;
1166     *pdwMinOutBufLen = g->uBytesPerRawRow;
1167     return IP_DONE;
1168
1169     fatal_error:
1170     return IP_FATAL_ERROR;
1171 }
1172
1173
1174
1175 /*****************************************************************************\
1176  *
1177  * pcxDecode_convert - the work-horse routine
1178  *
1179 \*****************************************************************************/
1180
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 */
1191 {
1192     PPCX_INST g;
1193     DWORD     in_used=0;
1194
1195     HANDLE_TO_PTR (hXform, g);
1196
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;
1203         return IP_DONE;
1204     }
1205
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;
1210         *pdwOutputUsed    = 0;
1211         *pdwInputNextPos  = g->dwInNextPos;
1212         *pdwOutputThisPos = g->dwOutNextPos;
1213         return 0;
1214     }
1215
1216     switch (g->traits.iBitsPerPixel) {
1217         case 1:  in_used = decode_1 (g, pbInputBuf, pbOutputBuf);
1218                  break;
1219
1220         case 4:  in_used = decode_4 (g, pbInputBuf, pbOutputBuf);
1221                  break;
1222         #if 0
1223         case 8:  in_used = decode_8 (g, pbInputBuf, pbOutputBuf);
1224                  break;
1225         #endif
1226     }
1227
1228     INSURE (dwInputAvail  >= in_used);
1229     INSURE (dwOutputAvail >= g->uBytesPerRawRow);
1230
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;
1237
1238     g->uRowsDone += 1;
1239
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;
1242
1243     fatal_error:
1244     return IP_FATAL_ERROR;
1245 }
1246
1247
1248
1249 /*****************************************************************************\
1250  *
1251  * pcxDecode_insertedData - client inserted into our output stream
1252  *
1253 \*****************************************************************************/
1254
1255 static WORD pcxDecode_insertedData (
1256     IP_XFORM_HANDLE hXform,
1257     DWORD           dwNumBytes)
1258 {
1259     fatalBreakPoint ();
1260     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
1261 }
1262
1263
1264
1265 /*****************************************************************************\
1266  *
1267  * pcxDecode_newPage - Tells us to flush this page, and start a new page
1268  *
1269 \*****************************************************************************/
1270
1271 static WORD pcxDecode_newPage (
1272     IP_XFORM_HANDLE hXform)
1273 {
1274     PPCX_INST g;
1275
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 */
1279
1280     fatal_error:
1281     return IP_FATAL_ERROR;
1282 }
1283
1284
1285
1286 /*****************************************************************************\
1287  *
1288  * pcxDecode_closeXform - Destroys this instance
1289  *
1290 \*****************************************************************************/
1291
1292 static WORD pcxDecode_closeXform (IP_XFORM_HANDLE hXform)
1293 {
1294     return pcxEncode_closeXform (hXform);
1295 }
1296
1297
1298
1299 /*****************************************************************************\
1300  *
1301  * pcxDecodeTbl - Jump-table for Decoder
1302  *
1303 \*****************************************************************************/
1304
1305 IP_XFORM_TBL pcxDecodeTbl = {
1306     pcxDecode_openXform,
1307     pcxDecode_setDefaultInputTraits,
1308     pcxDecode_setXformSpec,
1309     pcxDecode_getHeaderBufSize,
1310     pcxDecode_getActualTraits,
1311     pcxDecode_getActualBufSizes,
1312     pcxDecode_convert,
1313     pcxDecode_newPage,
1314     pcxDecode_insertedData,
1315     pcxDecode_closeXform
1316 };
1317
1318 /* End of File */