1 /* libhpojip -- HP OfficeJet image-processing library. */
3 /* Copyright (C) 1995-2002 Hewlett-Packard Company
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
13 * NON-INFRINGEMENT. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 * In addition, as a special exception, Hewlett-Packard Company
21 * gives permission to link the code of this program with any
22 * version of the OpenSSL library which is distributed under a
23 * license identical to that listed in the included LICENSE.OpenSSL
24 * file, and distribute linked combinations including the two.
25 * You must obey the GNU General Public License in all respects
26 * for all of the code used other than OpenSSL. If you modify
27 * this file, you may extend this exception to your version of the
28 * file, but you are not obligated to do so. If you do not wish to
29 * do so, delete this exception statement from your version.
32 /* Original author: David Paschal (based on Mark Overton's "xskel" template). */
34 /******************************************************************************\
36 * xpnm.c - encoder and decoder for PNM (PBM, PGM, PPM) files
38 ******************************************************************************
40 * Name of Global Jump-Table:
42 * pnmEncodeTbl = the encoder.
43 * pnmDecodeTbl = the decoder.
45 * Items in aXformInfo array passed into setXformSpec:
49 * Capabilities and Limitations:
51 * Handles 1, 8, and 24 bits per pixel.
53 * Default Input Traits, and Output Traits:
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
66 * Above, a "*" by an item indicates it must be valid (not negative).
68 \******************************************************************************/
72 #include "string.h" /* for memset and memcpy */
79 #define PRINT(msg,arg1,arg2) \
80 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
82 #define PRINT(msg,arg1,arg2)
85 #define CHECK_VALUE 0x4ba1dace
87 #define FUNC_STATUS static
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;
100 #define MAX_DECODE_HEADER_SIZE 4096
101 #define MAX_ENCODE_HEADER_SIZE 128
105 /*****************************************************************************\
107 * pnm{De,En}code_openXform - Creates a new instance of the transformer
109 *****************************************************************************
111 * This returns a handle for the new instance to be passed into
112 * all subsequent calls.
114 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
116 \*****************************************************************************/
118 FUNC_STATUS WORD pnmDecode_openXform (
119 IP_XFORM_HANDLE *pXform) /* out: returned handle */
123 INSURE (pXform != NULL);
124 IP_MEM_ALLOC (sizeof(PNM_INST), g);
126 memset (g, 0, sizeof(PNM_INST));
127 g->dwValidChk = CHECK_VALUE;
131 return IP_FATAL_ERROR;
134 FUNC_STATUS WORD pnmEncode_openXform (
135 IP_XFORM_HANDLE *pXform) /* out: returned handle */
137 WORD wResult=pnmDecode_openXform(pXform);
138 if (wResult==IP_DONE) {
141 HANDLE_TO_PTR (*pXform, g);
143 g->dwOutNextPos=MAX_ENCODE_HEADER_SIZE;
149 return IP_FATAL_ERROR;
153 /*****************************************************************************\
155 * pnm_setDefaultInputTraits - Specifies default input image traits
157 *****************************************************************************
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
164 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
166 \*****************************************************************************/
168 FUNC_STATUS WORD pnm_setDefaultInputTraits (
169 IP_XFORM_HANDLE hXform, /* in: handle for xform */
170 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
174 HANDLE_TO_PTR (hXform, g);
176 g->traits = *pTraits; /* a structure copy */
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;
185 return IP_FATAL_ERROR;
190 /*****************************************************************************\
192 * pnm_setXformSpec - Provides xform-specific information
194 \*****************************************************************************/
196 FUNC_STATUS WORD pnm_setXformSpec (
197 IP_XFORM_HANDLE hXform, /* in: handle for xform */
198 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
202 HANDLE_TO_PTR (hXform, g);
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.
212 return IP_FATAL_ERROR;
217 /*****************************************************************************\
219 * pnm_getHeaderBufSize- Returns size of input buf needed to hold header
221 \*****************************************************************************/
223 FUNC_STATUS WORD pnm_getHeaderBufSize (
224 IP_XFORM_HANDLE hXform, /* in: handle for xform */
225 DWORD *pdwInBufLen) /* out: buf size for parsing header */
229 HANDLE_TO_PTR (hXform, g);
232 *pdwInBufLen = MAX_DECODE_HEADER_SIZE;
234 /* since input is raw pixels, there is no header, so set it to zero */
240 return IP_FATAL_ERROR;
245 /*****************************************************************************\
247 * pnm_getActualTraits - Parses header, and returns input & output traits
249 \*****************************************************************************/
251 #define PEEK_CHAR(pc) \
253 if (*pdwInputUsed>=dwInputAvail) { \
254 return IP_INPUT_ERROR; \
256 *(pc)=pbInputBuf[*pdwInputUsed]; \
259 #define NEXT_CHAR ((*pdwInputUsed)++)
261 #define GET_CHAR(pc) \
282 #define GET_INT(pi) \
293 *(pi)=(*(pi)*10)+c; \
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 */
308 HANDLE_TO_PTR (hXform, g);
310 /* If there is no header, we'll report no usage of input */
313 /* Parse the header for decode operations. */
320 return IP_INPUT_ERROR;
325 g->traits.iComponentsPerPixel=1;
326 g->traits.iBitsPerPixel=1;
330 g->traits.iComponentsPerPixel=1;
331 g->traits.iBitsPerPixel=0;
335 g->traits.iComponentsPerPixel=3;
336 g->traits.iBitsPerPixel=0;
339 /* "Plain" (all-ASCII) formats (1-3) not (yet) supported. */
340 return IP_INPUT_ERROR;
343 GET_INT(&g->traits.iPixelsPerRow);
344 GET_INT(&g->traits.lNumRows);
345 if (!g->traits.iBitsPerPixel) {
348 g->traits.iBitsPerPixel++;
352 g->traits.iBitsPerPixel*=g->traits.iComponentsPerPixel;
353 g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
356 *pdwInputNextPos = *pdwInputUsed;
357 g->dwInNextPos = *pdwInputUsed;
359 *pInTraits = g->traits; /* structure copies */
360 *pOutTraits = g->traits;
362 return IP_DONE | IP_READY_FOR_DATA;
365 return IP_FATAL_ERROR;
370 /****************************************************************************\
372 * pnm_getActualBufSizes - Returns buf sizes needed for remainder of job
374 \****************************************************************************/
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 */
383 HANDLE_TO_PTR (hXform, g);
385 *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
389 return IP_FATAL_ERROR;
394 /*****************************************************************************\
396 * pnm_convert - Converts one row
398 \*****************************************************************************/
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 */
415 HANDLE_TO_PTR (hXform, g);
417 /**** Check if we were told to flush ****/
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;
430 INSURE(dwOutputAvail>=MAX_ENCODE_HEADER_SIZE);
432 memset(pbOutputBuf,' ',MAX_ENCODE_HEADER_SIZE);
434 if (g->traits.iComponentsPerPixel==1) {
440 } else if (g->traits.iComponentsPerPixel==3) {
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,
455 buffer[MAX_ENCODE_HEADER_SIZE-1]=0;
456 len=strlen((char *)buffer);
457 memcpy(pbOutputBuf+MAX_ENCODE_HEADER_SIZE-len,buffer,len);
459 *pdwOutputUsed=MAX_ENCODE_HEADER_SIZE;
461 g->dwOutNextPos=MAX_ENCODE_HEADER_SIZE;
467 /**** Output a Row ****/
469 nBytes = g->dwBytesPerRow;
470 INSURE (dwInputAvail >= (DWORD)nBytes );
471 INSURE (dwOutputAvail >= (DWORD)nBytes);
476 /* At this point, pIn is your input buffer, and pOut is your output buffer.
477 * Do whatever you are going to do here.
479 memcpy(pOut,pIn,nBytes);
481 *pdwInputUsed = nBytes;
482 g->dwInNextPos += nBytes;
483 *pdwInputNextPos = g->dwInNextPos;
485 *pdwOutputUsed = nBytes;
486 *pdwOutputThisPos = g->dwOutNextPos;
487 g->dwOutNextPos += nBytes;
491 return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
494 return IP_FATAL_ERROR;
499 /*****************************************************************************\
501 * pnm_insertedData - client inserted into our output stream
503 \*****************************************************************************/
505 FUNC_STATUS WORD pnm_insertedData (
506 IP_XFORM_HANDLE hXform,
510 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
515 /*****************************************************************************\
517 * pnm_newPage - Tells us to flush this page, and start a new page
519 \*****************************************************************************/
521 FUNC_STATUS WORD pnm_newPage (
522 IP_XFORM_HANDLE hXform)
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 */
531 return IP_FATAL_ERROR;
537 /*****************************************************************************\
539 * pnm_closeXform - Destroys this instance
541 \*****************************************************************************/
543 FUNC_STATUS WORD pnm_closeXform (IP_XFORM_HANDLE hXform)
547 HANDLE_TO_PTR (hXform, g);
550 IP_MEM_FREE (g); /* free memory for the instance */
555 return IP_FATAL_ERROR;
560 /*****************************************************************************\
562 * pnmTbl - Jump-table for transform driver
564 \*****************************************************************************/
565 IP_XFORM_TBL pnmDecodeTbl = {
567 pnm_setDefaultInputTraits,
569 pnm_getHeaderBufSize,
571 pnm_getActualBufSizes,
578 IP_XFORM_TBL pnmEncodeTbl = {
580 pnm_setDefaultInputTraits,
582 pnm_getHeaderBufSize,
584 pnm_getActualBufSizes,