Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xpnm.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: David Paschal (based on Mark Overton's "xskel" template). */
33
34 /******************************************************************************\
35  *
36  * xpnm.c - encoder and decoder for PNM (PBM, PGM, PPM) files
37  *
38  ******************************************************************************
39  *
40  * Name of Global Jump-Table:
41  *
42  *    pnmEncodeTbl = the encoder.
43  *    pnmDecodeTbl = the decoder.
44  *
45  * Items in aXformInfo array passed into setXformSpec:
46  *
47  *    None.
48  *
49  * Capabilities and Limitations:
50  *
51  *    Handles 1, 8, and 24 bits per pixel.
52  *
53  * Default Input Traits, and Output Traits:
54  *
55  *          trait             default input             output
56  *    -------------------  ---------------------  ------------------------
57  *    iPixelsPerRow         * passed into output   same as default input
58  *    iBitsPerPixel         * passed into output   same as default input
59  *    iComponentsPerPixel   * passed into output   same as default input
60  *    lHorizDPI               passed into output   same as default input
61  *    lVertDPI                passed into output   same as default input
62  *    lNumRows                passed into output   same as default input
63  *    iNumPages               passed into output   same as default input
64  *    iPageNum                passed into output   same as default input
65  *
66  *    Above, a "*" by an item indicates it must be valid (not negative).
67  *
68 \******************************************************************************/
69
70 #include "hpip.h"
71 #include "ipdefs.h"
72 #include "string.h"    /* for memset and memcpy */
73 #include <stdio.h>
74
75
76 #if 0
77     #include "stdio.h"
78     #include <tchar.h>
79     #define PRINT(msg,arg1,arg2) \
80         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
81 #else
82     #define PRINT(msg,arg1,arg2)
83 #endif
84
85 #define CHECK_VALUE 0x4ba1dace
86
87 #define FUNC_STATUS static
88
89 typedef struct {
90     IP_IMAGE_TRAITS traits;   /* traits of the input and output image */
91     DWORD    dwBytesPerRow;   /* # of bytes in each row */
92     DWORD    dwRowsDone;      /* number of rows converted so far */
93     DWORD    dwInNextPos;     /* file pos for subsequent input */
94     DWORD    dwOutNextPos;    /* file pos for subsequent output */
95     DWORD    dwValidChk;      /* struct validity check value */
96     BOOL     fIsEncode;       /* false=decode, true=encode */
97     BOOL     fDidHeader;      /* already sent/processed the header? */
98 } PNM_INST, *PPNM_INST;
99
100 #define MAX_DECODE_HEADER_SIZE 4096
101 #define MAX_ENCODE_HEADER_SIZE 128
102
103
104
105 /*****************************************************************************\
106  *
107  * pnm{De,En}code_openXform - Creates a new instance of the transformer
108  *
109  *****************************************************************************
110  *
111  * This returns a handle for the new instance to be passed into
112  * all subsequent calls.
113  *
114  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
115  *
116 \*****************************************************************************/
117
118 FUNC_STATUS WORD pnmDecode_openXform (
119     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
120 {
121     PPNM_INST g;
122
123     INSURE (pXform != NULL);
124     IP_MEM_ALLOC (sizeof(PNM_INST), g);
125     *pXform = g;
126     memset (g, 0, sizeof(PNM_INST));
127     g->dwValidChk = CHECK_VALUE;
128     return IP_DONE;
129
130     fatal_error:
131     return IP_FATAL_ERROR;
132 }
133
134 FUNC_STATUS WORD pnmEncode_openXform (
135     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
136 {
137     WORD wResult=pnmDecode_openXform(pXform);
138     if (wResult==IP_DONE) {
139         PPNM_INST g;
140
141         HANDLE_TO_PTR (*pXform, g);
142
143         g->dwOutNextPos=MAX_ENCODE_HEADER_SIZE;
144         g->fIsEncode=TRUE;
145     }
146     return wResult;
147
148     fatal_error:
149     return IP_FATAL_ERROR;
150 }
151
152
153 /*****************************************************************************\
154  *
155  * pnm_setDefaultInputTraits - Specifies default input image traits
156  *
157  *****************************************************************************
158  *
159  * The header of the file-type handled by the transform probably does
160  * not include *all* the image traits we'd like to know.  Those not
161  * specified in the file-header are filled in from info provided by
162  * this routine.
163  *
164  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
165  *
166 \*****************************************************************************/
167
168 FUNC_STATUS WORD pnm_setDefaultInputTraits (
169     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
170     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
171 {
172     PPNM_INST g;
173
174     HANDLE_TO_PTR (hXform, g);
175
176     g->traits = *pTraits;   /* a structure copy */
177     if (g->fIsEncode) {
178         /* insure that traits we care about are known */
179         INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
180         g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
181     }
182     return IP_DONE;
183
184     fatal_error:
185     return IP_FATAL_ERROR;
186 }
187
188
189
190 /*****************************************************************************\
191  *
192  * pnm_setXformSpec - Provides xform-specific information
193  *
194 \*****************************************************************************/
195
196 FUNC_STATUS WORD pnm_setXformSpec (
197     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
198     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
199 {
200     PPNM_INST g;
201
202     HANDLE_TO_PTR (hXform, g);
203
204     /* Check your options in aXformInfo here, and save them.
205      * Use the INSURE macro like you'd use assert.  INSURE jumps to
206      * fatal_error below if it fails.
207      */
208
209     return IP_DONE;
210
211     fatal_error:
212     return IP_FATAL_ERROR;
213 }
214
215
216
217 /*****************************************************************************\
218  *
219  * pnm_getHeaderBufSize- Returns size of input buf needed to hold header
220  *
221 \*****************************************************************************/
222
223 FUNC_STATUS WORD pnm_getHeaderBufSize (
224     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
225     DWORD           *pdwInBufLen)    /* out: buf size for parsing header */
226 {
227     PPNM_INST g;
228
229     HANDLE_TO_PTR (hXform, g);
230
231     if (!g->fIsEncode) {
232         *pdwInBufLen = MAX_DECODE_HEADER_SIZE;
233     } else {
234         /* since input is raw pixels, there is no header, so set it to zero */
235         *pdwInBufLen = 0;
236     }
237     return IP_DONE;
238
239     fatal_error:
240     return IP_FATAL_ERROR;
241 }
242
243
244
245 /*****************************************************************************\
246  *
247  * pnm_getActualTraits - Parses header, and returns input & output traits
248  *
249 \*****************************************************************************/
250
251 #define PEEK_CHAR(pc) \
252     do { \
253         if (*pdwInputUsed>=dwInputAvail) { \
254             return IP_INPUT_ERROR; \
255         } \
256         *(pc)=pbInputBuf[*pdwInputUsed]; \
257     } while (0)
258
259 #define NEXT_CHAR ((*pdwInputUsed)++)
260
261 #define GET_CHAR(pc) \
262     do { \
263         PEEK_CHAR(pc); \
264         NEXT_CHAR; \
265     } while (0)
266
267 #define SKIP_WS \
268     do { \
269         unsigned char c; \
270         PEEK_CHAR(&c); \
271         if (c=='#') { \
272             /* NEXT_CHAR; */ \
273             do { \
274                 GET_CHAR(&c); \
275             } while (c!='\n'); \
276             PEEK_CHAR(&c); \
277         } \
278         if (c>' ') break; \
279         NEXT_CHAR; \
280     } while (42)
281
282 #define GET_INT(pi) \
283     do { \
284         unsigned char c; \
285         *(pi)=0; \
286         SKIP_WS; \
287         while (42) { \
288             GET_CHAR(&c); \
289             c-='0'; \
290             if (c>9) { \
291                 break; \
292             } \
293             *(pi)=(*(pi)*10)+c; \
294         } \
295     } while (0)
296
297 FUNC_STATUS WORD pnm_getActualTraits (
298     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
299     DWORD            dwInputAvail,   /* in:  # avail bytes in input buf */
300     PBYTE            pbInputBuf,     /* in:  ptr to input buffer */
301     PDWORD           pdwInputUsed,   /* out: # bytes used from input buf */
302     PDWORD           pdwInputNextPos,/* out: file-pos to read from next */
303     PIP_IMAGE_TRAITS pInTraits,      /* out: input image traits */
304     PIP_IMAGE_TRAITS pOutTraits)     /* out: output image traits */
305 {
306     PPNM_INST g;
307
308     HANDLE_TO_PTR (hXform, g);
309
310     /* If there is no header, we'll report no usage of input */
311     *pdwInputUsed = 0;
312
313     /* Parse the header for decode operations. */
314     if (!g->fIsEncode) {
315         unsigned char c;
316         unsigned int maxval;
317
318         GET_CHAR(&c);
319         if (c!='P') {
320             return IP_INPUT_ERROR;
321         }
322         GET_CHAR(&c);
323         if (c=='4') {
324             /* PBM */
325             g->traits.iComponentsPerPixel=1;
326             g->traits.iBitsPerPixel=1;
327
328         } else if (c=='5') {
329             /* PGM */
330             g->traits.iComponentsPerPixel=1;
331             g->traits.iBitsPerPixel=0;
332
333         } else if (c=='6') {
334             /* PPM */
335             g->traits.iComponentsPerPixel=3;
336             g->traits.iBitsPerPixel=0;
337
338         } else {
339             /* "Plain" (all-ASCII) formats (1-3) not (yet) supported. */
340             return IP_INPUT_ERROR;
341         }
342
343         GET_INT(&g->traits.iPixelsPerRow);
344         GET_INT(&g->traits.lNumRows);
345         if (!g->traits.iBitsPerPixel) {
346             GET_INT(&maxval);
347             while (maxval) {
348                 g->traits.iBitsPerPixel++;
349                 maxval>>=1;
350             }
351         }
352         g->traits.iBitsPerPixel*=g->traits.iComponentsPerPixel;
353         g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
354     }
355
356     *pdwInputNextPos = *pdwInputUsed;
357     g->dwInNextPos   = *pdwInputUsed;
358
359     *pInTraits  = g->traits;   /* structure copies */
360     *pOutTraits = g->traits;
361
362     return IP_DONE | IP_READY_FOR_DATA;
363
364     fatal_error:
365     return IP_FATAL_ERROR;
366 }
367
368
369
370 /****************************************************************************\
371  *
372  * pnm_getActualBufSizes - Returns buf sizes needed for remainder of job
373  *
374 \****************************************************************************/
375
376 FUNC_STATUS WORD pnm_getActualBufSizes (
377     IP_XFORM_HANDLE hXform,          /* in:  handle for xform */
378     PDWORD          pdwMinInBufLen,  /* out: min input buf size */
379     PDWORD          pdwMinOutBufLen) /* out: min output buf size */
380 {
381     PPNM_INST g;
382
383     HANDLE_TO_PTR (hXform, g);
384
385     *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
386     return IP_DONE;
387
388     fatal_error:
389     return IP_FATAL_ERROR;
390 }
391
392
393
394 /*****************************************************************************\
395  *
396  * pnm_convert - Converts one row
397  *
398 \*****************************************************************************/
399
400 FUNC_STATUS WORD pnm_convert (
401     IP_XFORM_HANDLE hXform,
402     DWORD           dwInputAvail,     /* in:  # avail bytes in in-buf */
403     PBYTE           pbInputBuf,       /* in:  ptr to in-buffer */
404     PDWORD          pdwInputUsed,     /* out: # bytes used from in-buf */
405     PDWORD          pdwInputNextPos,  /* out: file-pos to read from next */
406     DWORD           dwOutputAvail,    /* in:  # avail bytes in out-buf */
407     PBYTE           pbOutputBuf,      /* in:  ptr to out-buffer */
408     PDWORD          pdwOutputUsed,    /* out: # bytes written in out-buf */
409     PDWORD          pdwOutputThisPos) /* out: file-pos to write the data */
410 {
411     PPNM_INST g;
412     int       nBytes;
413     PBYTE     pIn, pOut;
414
415     HANDLE_TO_PTR (hXform, g);
416
417     /**** Check if we were told to flush ****/
418
419     if (pbInputBuf == NULL) {
420         PRINT (_T("pnm_convert: Told to flush.\n"), 0, 0);
421         *pdwInputUsed = *pdwOutputUsed = 0;
422         *pdwInputNextPos  = g->dwInNextPos;
423         *pdwOutputThisPos = g->dwOutNextPos;
424         if (g->fIsEncode && !g->fDidHeader) {
425             BYTE buffer[MAX_ENCODE_HEADER_SIZE];
426             DWORD maxval=(2<<((g->traits.iBitsPerPixel/
427                 g->traits.iComponentsPerPixel)-1))-1;
428             int len;
429
430             INSURE(dwOutputAvail>=MAX_ENCODE_HEADER_SIZE);
431
432             memset(pbOutputBuf,' ',MAX_ENCODE_HEADER_SIZE);
433             pbOutputBuf[0]='P';
434             if (g->traits.iComponentsPerPixel==1) {
435                 if (maxval==1) {
436                     pbOutputBuf[1]='4';
437                 } else {
438                     pbOutputBuf[1]='5';
439                 }
440             } else if (g->traits.iComponentsPerPixel==3) {
441                 pbOutputBuf[1]='6';
442             } else {
443                 goto fatal_error;
444             }
445
446             snprintf((char *)buffer,MAX_ENCODE_HEADER_SIZE,"\n%d %d\n",
447                 g->traits.iPixelsPerRow,g->dwRowsDone);
448             if (g->traits.iComponentsPerPixel>1 || maxval>1) {
449                 buffer[MAX_ENCODE_HEADER_SIZE-1]=0;
450                 len=strlen((char *)buffer);
451                 snprintf((char *)buffer+len,MAX_ENCODE_HEADER_SIZE-len,
452                     "%d\n",maxval);
453             }
454
455             buffer[MAX_ENCODE_HEADER_SIZE-1]=0;
456             len=strlen((char *)buffer);
457             memcpy(pbOutputBuf+MAX_ENCODE_HEADER_SIZE-len,buffer,len);
458
459             *pdwOutputUsed=MAX_ENCODE_HEADER_SIZE;
460             *pdwOutputThisPos=0;
461             g->dwOutNextPos=MAX_ENCODE_HEADER_SIZE;
462             g->fDidHeader=1;
463         }
464         return IP_DONE;
465     }
466
467     /**** Output a Row ****/
468
469     nBytes = g->dwBytesPerRow;
470     INSURE (dwInputAvail  >= (DWORD)nBytes );
471     INSURE (dwOutputAvail >= (DWORD)nBytes);
472
473     pIn  = pbInputBuf;
474     pOut = pbOutputBuf;
475
476     /* At this point, pIn is your input buffer, and pOut is your output buffer.
477      * Do whatever you are going to do here.
478      */
479     memcpy(pOut,pIn,nBytes);
480
481     *pdwInputUsed     = nBytes;
482     g->dwInNextPos   += nBytes;
483     *pdwInputNextPos  = g->dwInNextPos;
484
485     *pdwOutputUsed    = nBytes;
486     *pdwOutputThisPos = g->dwOutNextPos;
487     g->dwOutNextPos  += nBytes;
488
489     g->dwRowsDone += 1;
490
491     return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
492
493     fatal_error:
494     return IP_FATAL_ERROR;
495 }
496
497
498
499 /*****************************************************************************\
500  *
501  * pnm_insertedData - client inserted into our output stream
502  *
503 \*****************************************************************************/
504
505 FUNC_STATUS WORD pnm_insertedData (
506     IP_XFORM_HANDLE hXform,
507     DWORD           dwNumBytes)
508 {
509     fatalBreakPoint ();
510     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
511 }
512
513
514
515 /*****************************************************************************\
516  *
517  * pnm_newPage - Tells us to flush this page, and start a new page
518  *
519 \*****************************************************************************/
520
521 FUNC_STATUS WORD pnm_newPage (
522     IP_XFORM_HANDLE hXform)
523 {
524     PPNM_INST g;
525
526     HANDLE_TO_PTR (hXform, g);
527     /* todo: return fatal error if convert is called again? */
528     return IP_DONE;   /* can't insert page-breaks, so ignore this call */
529
530     fatal_error:
531     return IP_FATAL_ERROR;
532
533 }
534
535
536
537 /*****************************************************************************\
538  *
539  * pnm_closeXform - Destroys this instance
540  *
541 \*****************************************************************************/
542
543 FUNC_STATUS WORD pnm_closeXform (IP_XFORM_HANDLE hXform)
544 {
545     PPNM_INST g;
546
547     HANDLE_TO_PTR (hXform, g);
548
549     g->dwValidChk = 0;
550     IP_MEM_FREE (g);       /* free memory for the instance */
551
552     return IP_DONE;
553
554     fatal_error:
555     return IP_FATAL_ERROR;
556 }
557
558
559
560 /*****************************************************************************\
561  *
562  * pnmTbl - Jump-table for transform driver
563  *
564 \*****************************************************************************/
565 IP_XFORM_TBL pnmDecodeTbl = {
566     pnmDecode_openXform,
567     pnm_setDefaultInputTraits,
568     pnm_setXformSpec,
569     pnm_getHeaderBufSize,
570     pnm_getActualTraits,
571     pnm_getActualBufSizes,
572     pnm_convert,
573     pnm_newPage,
574     pnm_insertedData,
575     pnm_closeXform
576 };
577
578 IP_XFORM_TBL pnmEncodeTbl = {
579     pnmEncode_openXform,
580     pnm_setDefaultInputTraits,
581     pnm_setXformSpec,
582     pnm_getHeaderBufSize,
583     pnm_getActualTraits,
584     pnm_getActualBufSizes,
585     pnm_convert,
586     pnm_newPage,
587     pnm_insertedData,
588     pnm_closeXform
589 };
590
591 /* End of File */