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 * xpad.c - Pads all four sides of the input image with extra pixels
41 ******************************************************************************
43 * Name of Global Jump-Table:
47 * Items in aXformInfo array passed into setXformSpec:
49 * aXformInfo[IP_PAD_LEFT ] = left: # of pixels to add to left side (or negative)
50 * aXformInfo[IP_PAD_RIGHT ] = right: # of pixels to add to right side
51 * aXformInfo[IP_PAD_TOP ] = top: # of rows to add to top (or negative)
52 * aXformInfo[IP_PAD_BOTTOM] = bottom: # of rows to add to bottom
53 * aXformInfo[IP_PAD_VALUE ] = pad value (0-255)
54 * aXformInfo[IP_PAD_MIN_HEIGHT] = minimum # of input rows, pad if needed
56 * The pad value above (at index 4) is the value of the added pad-pixels.
57 * For color data, all three bytes will be set to this value.
58 * For bi-level data, only the lsb is used.
60 * If 'left' is negative, then the output width will be forced to be a
61 * multiple of abs(left) pixels.
62 * If 'top' is negative, the same thing is done with the height.
64 * Capabilities and Limitations:
66 * Pads all four sides of the image.
67 * The image data must be fixed-length rows of uncompressed pixels.
68 * For bilevel data, the "left" value is changed to the nearest multiple
69 * of 8, and the "right" value is changed so the resulting row-width
71 * If all pad-amounts above are 0, this xform becomes merely a pass-thru.
73 * Default Input Traits, and Output Traits:
75 * trait default input output
76 * ------------------- --------------------- ------------------------
77 * iPixelsPerRow * used input width + horiz pad
78 * iBitsPerPixel * passed into output same as default input
79 * iComponentsPerPixel passed into output same as default input
80 * lHorizDPI passed into output same as default input
81 * lVertDPI passed into output same as default input
82 * lNumRows used if known output height, if input known
83 * iNumPages passed into output same as default input
84 * iPageNum passed into output same as default input
86 * Above, a "*" by an item indicates it must be valid (not negative).
88 \******************************************************************************/
92 #include "string.h" /* for memset and memcpy */
99 #define PRINT(msg,arg1,arg2) \
100 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
102 #define PRINT(msg,arg1,arg2)
105 #define CHECK_VALUE 0x4ba1dace
109 IP_IMAGE_TRAITS traits; /* traits of the input image */
110 DWORD dwLeft, dwRight; /* # pixels to pad, left and right sides */
111 DWORD dwTop; /* # rows to pad to top */
112 DWORD dwBottom; /* # rows to pad to bottom */
113 DWORD dwMinInRows; /* minimum # input rows, pad if necessary */
114 DWORD dwInBytesPerRow; /* # bytes in each input row */
115 DWORD dwOutBytesPerRow; /* # bytes in each output row */
116 DWORD dwLeftPadBytes; /* # bytes to add to left side of each row */
117 DWORD dwRightPadBytes; /* # bytes to add to right side of each row */
118 BYTE bPadVal; /* value of pad pixels */
119 DWORD dwInRows; /* number of rows input so far */
120 DWORD dwOutRows; /* number of rows output so far */
121 DWORD dwInNextPos; /* file pos for subsequent input */
122 DWORD dwOutNextPos; /* file pos for subsequent output */
123 DWORD dwValidChk; /* struct validity check value */
124 } PAD_INST, *PPAD_INST;
128 /*****************************************************************************\
130 * pad_openXform - Creates a new instance of the transformer
132 *****************************************************************************
134 * This returns a handle for the new instance to be passed into
135 * all subsequent calls.
137 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
139 \*****************************************************************************/
141 static WORD pad_openXform (
142 IP_XFORM_HANDLE *pXform) /* out: returned handle */
146 INSURE (pXform != NULL);
147 IP_MEM_ALLOC (sizeof(PAD_INST), g);
149 memset (g, 0, sizeof(PAD_INST));
150 g->dwValidChk = CHECK_VALUE;
154 return IP_FATAL_ERROR;
159 /*****************************************************************************\
161 * pad_setDefaultInputTraits - Specifies default input image traits
163 *****************************************************************************
165 * The header of the file-type handled by the transform probably does
166 * not include *all* the image traits we'd like to know. Those not
167 * specified in the file-header are filled in from info provided by
170 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
172 \*****************************************************************************/
174 static WORD pad_setDefaultInputTraits (
175 IP_XFORM_HANDLE hXform, /* in: handle for xform */
176 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
180 HANDLE_TO_PTR (hXform, g);
182 /* insure that traits we care about are known */
183 INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
184 g->traits = *pTraits; /* a structure copy */
188 return IP_FATAL_ERROR;
193 /*****************************************************************************\
195 * pad_setXformSpec - Provides xform-specific information
197 \*****************************************************************************/
199 static WORD pad_setXformSpec (
200 IP_XFORM_HANDLE hXform, /* in: handle for xform */
201 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
205 HANDLE_TO_PTR (hXform, g);
207 g->dwLeft = aXformInfo[IP_PAD_LEFT].dword;
208 g->dwRight = aXformInfo[IP_PAD_RIGHT].dword;
209 g->dwTop = aXformInfo[IP_PAD_TOP].dword;
210 g->dwBottom = aXformInfo[IP_PAD_BOTTOM].dword;
211 g->bPadVal = (BYTE)aXformInfo[IP_PAD_VALUE].dword;
212 g->dwMinInRows = aXformInfo[IP_PAD_MIN_HEIGHT].dword;
217 return IP_FATAL_ERROR;
222 /*****************************************************************************\
224 * pad_getHeaderBufSize- Returns size of input buf needed to hold header
226 \*****************************************************************************/
228 static WORD pad_getHeaderBufSize (
229 IP_XFORM_HANDLE hXform, /* in: handle for xform */
230 DWORD *pdwInBufLen) /* out: buf size for parsing header */
232 /* since input is raw pixels, there is no header, so set it to zero */
239 /*****************************************************************************\
241 * pad_getActualTraits - Parses header, and returns input & output traits
243 \*****************************************************************************/
245 static WORD pad_getActualTraits (
246 IP_XFORM_HANDLE hXform, /* in: handle for xform */
247 DWORD dwInputAvail, /* in: # avail bytes in input buf */
248 PBYTE pbInputBuf, /* in: ptr to input buffer */
249 PDWORD pdwInputUsed, /* out: # bytes used from input buf */
250 PDWORD pdwInputNextPos,/* out: file-pos to read from next */
251 PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
252 PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
255 int left, right, shift, more;
256 int inWidth, outWidth;
259 HANDLE_TO_PTR (hXform, g);
261 /* Since there is no header, we'll report no usage of input */
264 *pdwInputNextPos = 0;
266 /* Compute the pad info */
268 bpp = g->traits.iBitsPerPixel;
271 inWidth = g->traits.iPixelsPerRow;
275 // pad horizontally so that width is a multiple of left
276 outWidth = ((inWidth+left-1) / left) * left;
277 more = outWidth - inWidth;
284 outWidth = inWidth + left + right;
287 /* shift to start at nearest byte boundary */
288 shift = ((left+4) & ~7) - left;
289 left += shift; /* this is now a multiple of 8 */
292 g->bPadVal = g->bPadVal & 1 ? 0xffu : 0;
295 g->dwInBytesPerRow = (bpp*inWidth + 7) / 8;
296 g->dwOutBytesPerRow = (bpp*outWidth + 7) / 8;
297 g->dwLeftPadBytes = (bpp*left + 7) / 8;
298 g->dwRightPadBytes = g->dwOutBytesPerRow - g->dwInBytesPerRow - g->dwLeftPadBytes;
300 /* Report the traits */
302 *pInTraits = g->traits; /* structure copies */
303 *pOutTraits = g->traits;
304 pOutTraits->iPixelsPerRow = outWidth;
306 if (pInTraits->lNumRows > 0) {
307 if ((int)g->dwTop < 0) {
308 int top, bot, inHeight, outHeight;
309 top = - (int)g->dwTop;
310 // pad vertically so that #rows is a multiple of top
311 inHeight = pInTraits->lNumRows;
312 outHeight = ((inHeight+top-1) / top) * top;
313 more = outHeight - inHeight;
320 pOutTraits->lNumRows = pInTraits->lNumRows + g->dwTop + g->dwBottom;
323 INSURE ((int)g->dwLeft >= 0);
324 INSURE ((int)g->dwTop >= 0);
326 return IP_DONE | (g->dwTop>0 ? 0 : IP_READY_FOR_DATA);
329 return IP_FATAL_ERROR;
334 /****************************************************************************\
336 * pad_getActualBufSizes - Returns buf sizes needed for remainder of job
338 \****************************************************************************/
340 static WORD pad_getActualBufSizes (
341 IP_XFORM_HANDLE hXform, /* in: handle for xform */
342 PDWORD pdwMinInBufLen, /* out: min input buf size */
343 PDWORD pdwMinOutBufLen) /* out: min output buf size */
347 HANDLE_TO_PTR (hXform, g);
349 *pdwMinInBufLen = g->dwInBytesPerRow;
350 *pdwMinOutBufLen = g->dwOutBytesPerRow;
354 return IP_FATAL_ERROR;
359 /*****************************************************************************\
361 * pad_convert - Converts one row
363 \*****************************************************************************/
365 static WORD pad_convert (
366 IP_XFORM_HANDLE hXform,
367 DWORD dwInputAvail, /* in: # avail bytes in in-buf */
368 PBYTE pbInputBuf, /* in: ptr to in-buffer */
369 PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
370 PDWORD pdwInputNextPos, /* out: file-pos to read from next */
371 DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
372 PBYTE pbOutputBuf, /* in: ptr to out-buffer */
373 PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
374 PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
379 HANDLE_TO_PTR (hXform, g);
382 /**** Decide what to do ****/
384 if (pbInputBuf == NULL) {
385 PRINT (_T("pad_convert: Told to flush.\n"), 0, 0);
387 if (g->dwInRows < g->dwMinInRows) {
388 /* We need to output another pad row on the bottom */
391 } else if (g->dwBottom > 0) {
392 /* We need to output another pad row on the bottom */
397 *pdwInputUsed = *pdwOutputUsed = 0;
398 *pdwInputNextPos = g->dwInNextPos;
399 *pdwOutputThisPos = g->dwOutNextPos;
402 } else if (g->dwOutRows < g->dwTop) {
403 /* We need to output another pad row on the top */
407 /**** Output a Row ****/
409 INSURE (bWhiteRow || (dwInputAvail >= g->dwInBytesPerRow));
410 INSURE (dwOutputAvail >= g->dwOutBytesPerRow);
413 memset (pbOutputBuf, g->bPadVal, g->dwOutBytesPerRow);
415 BYTE *p = pbOutputBuf;
416 memset (p, g->bPadVal, g->dwLeftPadBytes);
417 p += g->dwLeftPadBytes;
418 memcpy (p, pbInputBuf, g->dwInBytesPerRow);
419 p += g->dwInBytesPerRow;
420 memset (p, g->bPadVal, g->dwRightPadBytes);
423 *pdwInputUsed = g->dwInBytesPerRow;
424 g->dwInNextPos += g->dwInBytesPerRow;
428 *pdwInputNextPos = g->dwInNextPos;
429 *pdwOutputUsed = g->dwOutBytesPerRow;
430 *pdwOutputThisPos = g->dwOutNextPos;
431 g->dwOutNextPos += g->dwOutBytesPerRow;
433 return (bWhiteRow ? 0 : IP_CONSUMED_ROW) |
435 (g->dwOutRows < g->dwTop ? 0 : IP_READY_FOR_DATA);
438 return IP_FATAL_ERROR;
443 /*****************************************************************************\
445 * pad_insertedData - client inserted into our output stream
447 \*****************************************************************************/
449 static WORD pad_insertedData (
450 IP_XFORM_HANDLE hXform,
454 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
459 /*****************************************************************************\
461 * pad_newPage - Tells us to flush this page, and start a new page
463 \*****************************************************************************/
465 static WORD pad_newPage (
466 IP_XFORM_HANDLE hXform)
470 HANDLE_TO_PTR (hXform, g);
471 /* todo: return fatal error if convert is called again? */
472 return IP_DONE; /* can't insert page-breaks, so ignore this call */
475 return IP_FATAL_ERROR;
481 /*****************************************************************************\
483 * pad_closeXform - Destroys this instance
485 \*****************************************************************************/
487 static WORD pad_closeXform (IP_XFORM_HANDLE hXform)
491 HANDLE_TO_PTR (hXform, g);
494 IP_MEM_FREE (g); /* free memory for the instance */
499 return IP_FATAL_ERROR;
504 /*****************************************************************************\
506 * padTbl - Jump-table for transform driver
508 \*****************************************************************************/
510 IP_XFORM_TBL padTbl = {
512 pad_setDefaultInputTraits,
514 pad_getHeaderBufSize,
516 pad_getActualBufSizes,