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 * xcrop.c - Crops all four sides of the input image
41 ******************************************************************************
43 * Name of Global Jump-Table:
47 * Items in aXformInfo array passed into setXformSpec:
49 * aXformInfo[IP_CROP_LEFT ] = left: # of pixels to remove from left side
50 * aXformInfo[IP_CROP_RIGHT ] = right: # of pixels to remove from right side
51 * aXformInfo[IP_CROP_TOP ] = top: # of rows to remove from top
52 * aXformInfo[IP_CROP_MAXOUTROWS] = maxOutRows: max # of rows to output
54 * Any (or even all) of the above values may be zero. If maxOutRows is
55 * zero, then an unlimited number of rows can be output.
57 * Capabilities and Limitations:
59 * Crops all four sides of the image.
60 * The image data must be fixed-length rows of uncompressed pixels.
61 * For bilevel data, the "left" value is changed to the nearest multiple
62 * of 8, and the "right" value is changed so the resulting row-width
64 * If all crop-amounts above are 0, this xform becomes merely a pass-thru.
66 * Default Input Traits, and Output Traits:
68 * trait default input output
69 * ------------------- --------------------- ------------------------
70 * iPixelsPerRow * used input width - horiz crop
71 * iBitsPerPixel * passed into output same as default input
72 * iComponentsPerPixel passed into output same as default input
73 * lHorizDPI passed into output same as default input
74 * lVertDPI passed into output same as default input
75 * lNumRows used if known output height, if input known
76 * iNumPages passed into output same as default input
77 * iPageNum passed into output same as default input
79 * Above, a "*" by an item indicates it must be valid (not negative).
81 \******************************************************************************/
85 #include "string.h" /* for memset and memcpy */
92 #define PRINT(msg,arg1,arg2) \
93 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
95 #define PRINT(msg,arg1,arg2)
98 #define CHECK_VALUE 0x4ba1dace
102 IP_IMAGE_TRAITS traits; /* traits of the input image */
103 DWORD dwLeft, dwRight; /* # pixels to crop, left and right sides */
104 DWORD dwTop; /* # rows to crop from top */
105 DWORD dwMaxOutRows; /* max # rows to output */
106 DWORD dwInBytesPerRow; /* # bytes in each input row */
107 DWORD dwOutBytesPerRow; /* # bytes in each output row */
108 DWORD dwLeftCropBytes; /* # bytes to toss from left side of each row */
109 DWORD dwInRows; /* number of rows input so far */
110 DWORD dwOutRows; /* number of rows output so far */
111 DWORD dwInNextPos; /* file pos for subsequent input */
112 DWORD dwOutNextPos; /* file pos for subsequent output */
113 DWORD dwValidChk; /* struct validity check value */
114 } CROP_INST, *PCROP_INST;
118 /*****************************************************************************\
120 * crop_openXform - Creates a new instance of the transformer
122 *****************************************************************************
124 * This returns a handle for the new instance to be passed into
125 * all subsequent calls.
127 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
129 \*****************************************************************************/
131 static WORD crop_openXform (
132 IP_XFORM_HANDLE *pXform) /* out: returned handle */
136 INSURE (pXform != NULL);
137 IP_MEM_ALLOC (sizeof(CROP_INST), g);
139 memset (g, 0, sizeof(CROP_INST));
140 g->dwValidChk = CHECK_VALUE;
144 return IP_FATAL_ERROR;
149 /*****************************************************************************\
151 * crop_setDefaultInputTraits - Specifies default input image traits
153 *****************************************************************************
155 * The header of the file-type handled by the transform probably does
156 * not include *all* the image traits we'd like to know. Those not
157 * specified in the file-header are filled in from info provided by
160 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
162 \*****************************************************************************/
164 static WORD crop_setDefaultInputTraits (
165 IP_XFORM_HANDLE hXform, /* in: handle for xform */
166 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
170 HANDLE_TO_PTR (hXform, g);
172 /* insure that traits we care about are known */
173 INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
174 g->traits = *pTraits; /* a structure copy */
178 return IP_FATAL_ERROR;
183 /*****************************************************************************\
185 * crop_setXformSpec - Provides xform-specific information
187 \*****************************************************************************/
189 static WORD crop_setXformSpec (
190 IP_XFORM_HANDLE hXform, /* in: handle for xform */
191 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
195 HANDLE_TO_PTR (hXform, g);
197 g->dwLeft = aXformInfo[IP_CROP_LEFT].dword;
198 g->dwRight = aXformInfo[IP_CROP_RIGHT].dword;
199 g->dwTop = aXformInfo[IP_CROP_TOP].dword;
200 g->dwMaxOutRows = aXformInfo[IP_CROP_MAXOUTROWS].dword;
202 if (g->dwMaxOutRows == 0)
203 g->dwMaxOutRows = 0x7ffffffful; /* 0 -> infinite */
208 return IP_FATAL_ERROR;
213 /*****************************************************************************\
215 * crop_getHeaderBufSize- Returns size of input buf needed to hold header
217 \*****************************************************************************/
219 static WORD crop_getHeaderBufSize (
220 IP_XFORM_HANDLE hXform, /* in: handle for xform */
221 DWORD *pdwInBufLen) /* out: buf size for parsing header */
223 /* since input is raw pixels, there is no header, so set it to zero */
230 /*****************************************************************************\
232 * crop_getActualTraits - Parses header, and returns input & output traits
234 \*****************************************************************************/
236 static WORD crop_getActualTraits (
237 IP_XFORM_HANDLE hXform, /* in: handle for xform */
238 DWORD dwInputAvail, /* in: # avail bytes in input buf */
239 PBYTE pbInputBuf, /* in: ptr to input buffer */
240 PDWORD pdwInputUsed, /* out: # bytes used from input buf */
241 PDWORD pdwInputNextPos,/* out: file-pos to read from next */
242 PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
243 PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
246 int left, right, shift;
247 int inWidth, outWidth;
249 long actualOut, maxOut;
251 HANDLE_TO_PTR (hXform, g);
253 /* Since there is no header, we'll report no usage of input */
256 *pdwInputNextPos = 0;
258 /* Compute the crop info */
260 bpp = g->traits.iBitsPerPixel;
263 inWidth = g->traits.iPixelsPerRow;
264 outWidth = inWidth - left - right;
265 INSURE (outWidth >= 0);
268 /* shift to start at nearest byte boundary */
269 shift = ((left+4) & ~7) - left;
270 left += shift; /* this is now a multiple of 8 */
274 g->dwInBytesPerRow = (bpp*inWidth + 7) / 8;
275 g->dwOutBytesPerRow = (bpp*outWidth + 7) / 8;
276 g->dwLeftCropBytes = (bpp*left + 7) / 8;
278 /* Report the traits */
280 *pInTraits = g->traits; /* structure copies */
281 *pOutTraits = g->traits;
282 pOutTraits->iPixelsPerRow = outWidth;
284 /* compute the output lNumRows, if possible */
285 if (pInTraits->lNumRows > 0) {
286 maxOut = g->dwMaxOutRows;
287 actualOut = pInTraits->lNumRows - (long)g->dwTop;
288 INSURE (actualOut >= 0);
289 pOutTraits->lNumRows = actualOut<maxOut ? actualOut : maxOut;
292 return IP_DONE | IP_READY_FOR_DATA;
295 return IP_FATAL_ERROR;
300 /****************************************************************************\
302 * crop_getActualBufSizes - Returns buf sizes needed for remainder of job
304 \****************************************************************************/
306 static WORD crop_getActualBufSizes (
307 IP_XFORM_HANDLE hXform, /* in: handle for xform */
308 PDWORD pdwMinInBufLen, /* out: min input buf size */
309 PDWORD pdwMinOutBufLen) /* out: min output buf size */
313 HANDLE_TO_PTR (hXform, g);
315 *pdwMinInBufLen = g->dwInBytesPerRow;
316 *pdwMinOutBufLen = g->dwOutBytesPerRow;
320 return IP_FATAL_ERROR;
325 /*****************************************************************************\
327 * crop_convert - Converts one row
329 \*****************************************************************************/
331 static WORD crop_convert (
332 IP_XFORM_HANDLE hXform,
333 DWORD dwInputAvail, /* in: # avail bytes in in-buf */
334 PBYTE pbInputBuf, /* in: ptr to in-buffer */
335 PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
336 PDWORD pdwInputNextPos, /* out: file-pos to read from next */
337 DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
338 PBYTE pbOutputBuf, /* in: ptr to out-buffer */
339 PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
340 PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
345 HANDLE_TO_PTR (hXform, g);
347 /**** Check if we were told to flush ****/
349 if (pbInputBuf == NULL) {
350 PRINT (_T("crop_convert: Told to flush.\n"), 0, 0);
351 *pdwInputUsed = *pdwOutputUsed = 0;
352 *pdwInputNextPos = g->dwInNextPos;
353 *pdwOutputThisPos = g->dwOutNextPos;
357 /**** Check if we should discard the row (vertical cropping) ****/
359 dwOutBytes = (g->dwInRows < g->dwTop || g->dwOutRows >= g->dwMaxOutRows)
360 ? 0 : g->dwOutBytesPerRow;
362 /**** Output a Row ****/
364 INSURE (dwInputAvail >= g->dwInBytesPerRow);
365 INSURE (dwOutputAvail >= dwOutBytes);
367 if (dwOutBytes > 0) {
368 memcpy (pbOutputBuf, pbInputBuf+g->dwLeftCropBytes, dwOutBytes);
374 *pdwInputUsed = g->dwInBytesPerRow;
375 g->dwInNextPos += g->dwInBytesPerRow;
376 *pdwInputNextPos = g->dwInNextPos;
378 *pdwOutputUsed = dwOutBytes;
379 *pdwOutputThisPos = g->dwOutNextPos;
380 g->dwOutNextPos += dwOutBytes;
382 return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
385 return IP_FATAL_ERROR;
390 /*****************************************************************************\
392 * crop_insertedData - client inserted into our output stream
394 \*****************************************************************************/
396 static WORD crop_insertedData (
397 IP_XFORM_HANDLE hXform,
401 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
406 /*****************************************************************************\
408 * crop_newPage - Tells us to flush this page, and start a new page
410 \*****************************************************************************/
412 static WORD crop_newPage (
413 IP_XFORM_HANDLE hXform)
417 HANDLE_TO_PTR (hXform, g);
418 /* todo: return fatal error if convert is called again? */
419 return IP_DONE; /* can't insert page-breaks, so ignore this call */
422 return IP_FATAL_ERROR;
428 /*****************************************************************************\
430 * crop_closeXform - Destroys this instance
432 \*****************************************************************************/
434 static WORD crop_closeXform (IP_XFORM_HANDLE hXform)
438 HANDLE_TO_PTR (hXform, g);
441 IP_MEM_FREE (g); /* free memory for the instance */
446 return IP_FATAL_ERROR;
451 /*****************************************************************************\
453 * cropTbl - Jump-table for transform driver
455 \*****************************************************************************/
457 IP_XFORM_TBL cropTbl = {
459 crop_setDefaultInputTraits,
461 crop_getHeaderBufSize,
462 crop_getActualTraits,
463 crop_getActualBufSizes,