Code sync
[external/hplip.git] / ip / xcrop.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  * xcrop.c - Crops all four sides of the input image
40  *
41  ******************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    cropTbl
46  *
47  * Items in aXformInfo array passed into setXformSpec:
48  *
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
53  *
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.
56  *
57  * Capabilities and Limitations:
58  *
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
63  *    does not change.
64  *    If all crop-amounts above are 0, this xform becomes merely a pass-thru.
65  *
66  * Default Input Traits, and Output Traits:
67  *
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
78  *
79  *    Above, a "*" by an item indicates it must be valid (not negative).
80  *
81 \******************************************************************************/
82
83 #include "hpip.h"
84 #include "ipdefs.h"
85 #include "string.h"    /* for memset and memcpy */
86
87
88 #if 0
89     #include "stdio.h"
90     #include <tchar.h>
91
92     #define PRINT(msg,arg1,arg2) \
93         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
94 #else
95     #define PRINT(msg,arg1,arg2)
96 #endif
97
98 #define CHECK_VALUE 0x4ba1dace
99
100
101 typedef struct {
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;
115
116
117
118 /*****************************************************************************\
119  *
120  * crop_openXform - Creates a new instance of the transformer
121  *
122  *****************************************************************************
123  *
124  * This returns a handle for the new instance to be passed into
125  * all subsequent calls.
126  *
127  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
128  *
129 \*****************************************************************************/
130
131 static WORD crop_openXform (
132     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
133 {
134     PCROP_INST g;
135
136     INSURE (pXform != NULL);
137     IP_MEM_ALLOC (sizeof(CROP_INST), g);
138     *pXform = g;
139     memset (g, 0, sizeof(CROP_INST));
140     g->dwValidChk = CHECK_VALUE;
141     return IP_DONE;
142
143     fatal_error:
144     return IP_FATAL_ERROR;
145 }
146
147
148
149 /*****************************************************************************\
150  *
151  * crop_setDefaultInputTraits - Specifies default input image traits
152  *
153  *****************************************************************************
154  *
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
158  * this routine.
159  *
160  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
161  *
162 \*****************************************************************************/
163
164 static WORD crop_setDefaultInputTraits (
165     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
166     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
167 {
168     PCROP_INST g;
169
170     HANDLE_TO_PTR (hXform, g);
171
172     /* insure that traits we care about are known */
173     INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
174     g->traits = *pTraits;   /* a structure copy */
175     return IP_DONE;
176
177     fatal_error:
178     return IP_FATAL_ERROR;
179 }
180
181
182
183 /*****************************************************************************\
184  *
185  * crop_setXformSpec - Provides xform-specific information
186  *
187 \*****************************************************************************/
188
189 static WORD crop_setXformSpec (
190     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
191     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
192 {
193     PCROP_INST g;
194
195     HANDLE_TO_PTR (hXform, g);
196
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;
201
202     if (g->dwMaxOutRows == 0)
203         g->dwMaxOutRows = 0x7ffffffful;   /* 0 -> infinite */
204
205     return IP_DONE;
206
207     fatal_error:
208     return IP_FATAL_ERROR;
209 }
210
211
212
213 /*****************************************************************************\
214  *
215  * crop_getHeaderBufSize- Returns size of input buf needed to hold header
216  *
217 \*****************************************************************************/
218
219 static WORD crop_getHeaderBufSize (
220     IP_XFORM_HANDLE  hXform,          /* in:  handle for xform */
221     DWORD           *pdwInBufLen)     /* out: buf size for parsing header */
222 {
223     /* since input is raw pixels, there is no header, so set it to zero */
224     *pdwInBufLen = 0;
225     return IP_DONE;
226 }
227
228
229
230 /*****************************************************************************\
231  *
232  * crop_getActualTraits - Parses header, and returns input & output traits
233  *
234 \*****************************************************************************/
235
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 */
244 {
245     PCROP_INST g;
246     int        left, right, shift;
247     int        inWidth, outWidth;
248     int        bpp;
249     long       actualOut, maxOut;
250
251     HANDLE_TO_PTR (hXform, g);
252
253     /* Since there is no header, we'll report no usage of input */
254
255     *pdwInputUsed    = 0;
256     *pdwInputNextPos = 0;
257
258     /* Compute the crop info */
259
260     bpp      = g->traits.iBitsPerPixel;
261     left     = g->dwLeft;
262     right    = g->dwRight;
263     inWidth  = g->traits.iPixelsPerRow;
264     outWidth = inWidth - left - right;
265     INSURE (outWidth >= 0);
266
267     if (bpp == 1) {
268         /* shift to start at nearest byte boundary */
269         shift = ((left+4) & ~7) - left;
270         left  += shift;   /* this is now a multiple of 8 */
271         right += shift;
272     }
273
274     g->dwInBytesPerRow  = (bpp*inWidth  + 7) / 8;
275     g->dwOutBytesPerRow = (bpp*outWidth + 7) / 8;
276     g->dwLeftCropBytes  = (bpp*left     + 7) / 8;
277
278     /* Report the traits */
279
280     *pInTraits  = g->traits;   /* structure copies */
281     *pOutTraits = g->traits;
282     pOutTraits->iPixelsPerRow = outWidth;
283
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;
290     }
291
292     return IP_DONE | IP_READY_FOR_DATA;
293
294     fatal_error:
295     return IP_FATAL_ERROR;
296 }
297
298
299
300 /****************************************************************************\
301  *
302  * crop_getActualBufSizes - Returns buf sizes needed for remainder of job
303  *
304 \****************************************************************************/
305
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 */
310 {
311     PCROP_INST g;
312
313     HANDLE_TO_PTR (hXform, g);
314
315     *pdwMinInBufLen  = g->dwInBytesPerRow;
316     *pdwMinOutBufLen = g->dwOutBytesPerRow;
317     return IP_DONE;
318
319     fatal_error:
320     return IP_FATAL_ERROR;
321 }
322
323
324
325 /*****************************************************************************\
326  *
327  * crop_convert - Converts one row
328  *
329 \*****************************************************************************/
330
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 */
341 {
342     PCROP_INST g;
343     DWORD      dwOutBytes;
344
345     HANDLE_TO_PTR (hXform, g);
346
347     /**** Check if we were told to flush ****/
348
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;
354         return IP_DONE;
355     }
356
357     /**** Check if we should discard the row (vertical cropping) ****/
358
359     dwOutBytes = (g->dwInRows < g->dwTop  ||  g->dwOutRows >= g->dwMaxOutRows)
360                   ? 0 : g->dwOutBytesPerRow;
361
362     /**** Output a Row ****/
363
364     INSURE (dwInputAvail  >= g->dwInBytesPerRow);
365     INSURE (dwOutputAvail >= dwOutBytes);
366
367     if (dwOutBytes > 0) {
368         memcpy (pbOutputBuf, pbInputBuf+g->dwLeftCropBytes, dwOutBytes);
369         g->dwOutRows += 1;
370     }
371
372     g->dwInRows += 1;
373
374     *pdwInputUsed     = g->dwInBytesPerRow;
375     g->dwInNextPos   += g->dwInBytesPerRow;
376     *pdwInputNextPos  = g->dwInNextPos;
377
378     *pdwOutputUsed    = dwOutBytes;
379     *pdwOutputThisPos = g->dwOutNextPos;
380     g->dwOutNextPos  += dwOutBytes;
381
382     return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
383
384     fatal_error:
385     return IP_FATAL_ERROR;
386 }
387
388
389
390 /*****************************************************************************\
391  *
392  * crop_insertedData - client inserted into our output stream
393  *
394 \*****************************************************************************/
395
396 static WORD crop_insertedData (
397     IP_XFORM_HANDLE hXform,
398     DWORD           dwNumBytes)
399 {
400     fatalBreakPoint ();
401     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
402 }
403
404
405
406 /*****************************************************************************\
407  *
408  * crop_newPage - Tells us to flush this page, and start a new page
409  *
410 \*****************************************************************************/
411
412 static WORD crop_newPage (
413     IP_XFORM_HANDLE hXform)
414 {
415     PCROP_INST g;
416
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 */
420
421     fatal_error:
422     return IP_FATAL_ERROR;
423
424 }
425
426
427
428 /*****************************************************************************\
429  *
430  * crop_closeXform - Destroys this instance
431  *
432 \*****************************************************************************/
433
434 static WORD crop_closeXform (IP_XFORM_HANDLE hXform)
435 {
436     PCROP_INST g;
437
438     HANDLE_TO_PTR (hXform, g);
439
440     g->dwValidChk = 0;
441     IP_MEM_FREE (g);       /* free memory for the instance */
442
443     return IP_DONE;
444
445     fatal_error:
446     return IP_FATAL_ERROR;
447 }
448
449
450
451 /*****************************************************************************\
452  *
453  * cropTbl - Jump-table for transform driver
454  *
455 \*****************************************************************************/
456
457 IP_XFORM_TBL cropTbl = {
458     crop_openXform,
459     crop_setDefaultInputTraits,
460     crop_setXformSpec,
461     crop_getHeaderBufSize,
462     crop_getActualTraits,
463     crop_getActualBufSizes,
464     crop_convert,
465     crop_newPage,
466     crop_insertedData,
467     crop_closeXform
468 };
469
470 /* End of File */