Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xpad.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  * xpad.c - Pads all four sides of the input image with extra pixels
40  *
41  ******************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    padTbl
46  *
47  * Items in aXformInfo array passed into setXformSpec:
48  *
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
55  *
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.
59  *
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.
63  *
64  * Capabilities and Limitations:
65  *
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
70  *    does not change.
71  *    If all pad-amounts above are 0, this xform becomes merely a pass-thru.
72  *
73  * Default Input Traits, and Output Traits:
74  *
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
85  *
86  *    Above, a "*" by an item indicates it must be valid (not negative).
87  *
88 \******************************************************************************/
89
90 #include "hpip.h"
91 #include "ipdefs.h"
92 #include "string.h"    /* for memset and memcpy */
93
94
95 #if 0
96     #include "stdio.h"
97     #include <tchar.h>
98
99     #define PRINT(msg,arg1,arg2) \
100         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
101 #else
102     #define PRINT(msg,arg1,arg2)
103 #endif
104
105 #define CHECK_VALUE 0x4ba1dace
106
107
108 typedef struct {
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;
125
126
127
128 /*****************************************************************************\
129  *
130  * pad_openXform - Creates a new instance of the transformer
131  *
132  *****************************************************************************
133  *
134  * This returns a handle for the new instance to be passed into
135  * all subsequent calls.
136  *
137  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
138  *
139 \*****************************************************************************/
140
141 static WORD pad_openXform (
142     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
143 {
144     PPAD_INST g;
145
146     INSURE (pXform != NULL);
147     IP_MEM_ALLOC (sizeof(PAD_INST), g);
148     *pXform = g;
149     memset (g, 0, sizeof(PAD_INST));
150     g->dwValidChk = CHECK_VALUE;
151     return IP_DONE;
152
153     fatal_error:
154     return IP_FATAL_ERROR;
155 }
156
157
158
159 /*****************************************************************************\
160  *
161  * pad_setDefaultInputTraits - Specifies default input image traits
162  *
163  *****************************************************************************
164  *
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
168  * this routine.
169  *
170  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
171  *
172 \*****************************************************************************/
173
174 static WORD pad_setDefaultInputTraits (
175     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
176     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
177 {
178     PPAD_INST g;
179
180     HANDLE_TO_PTR (hXform, g);
181
182     /* insure that traits we care about are known */
183     INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>0);
184     g->traits = *pTraits;   /* a structure copy */
185     return IP_DONE;
186
187     fatal_error:
188     return IP_FATAL_ERROR;
189 }
190
191
192
193 /*****************************************************************************\
194  *
195  * pad_setXformSpec - Provides xform-specific information
196  *
197 \*****************************************************************************/
198
199 static WORD pad_setXformSpec (
200     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
201     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
202 {
203     PPAD_INST g;
204
205     HANDLE_TO_PTR (hXform, g);
206
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;
213
214     return IP_DONE;
215
216     fatal_error:
217     return IP_FATAL_ERROR;
218 }
219
220
221
222 /*****************************************************************************\
223  *
224  * pad_getHeaderBufSize- Returns size of input buf needed to hold header
225  *
226 \*****************************************************************************/
227
228 static WORD pad_getHeaderBufSize (
229     IP_XFORM_HANDLE  hXform,          /* in:  handle for xform */
230     DWORD           *pdwInBufLen)     /* out: buf size for parsing header */
231 {
232     /* since input is raw pixels, there is no header, so set it to zero */
233     *pdwInBufLen = 0;
234     return IP_DONE;
235 }
236
237
238
239 /*****************************************************************************\
240  *
241  * pad_getActualTraits - Parses header, and returns input & output traits
242  *
243 \*****************************************************************************/
244
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 */
253 {
254     PPAD_INST g;
255     int        left, right, shift, more;
256     int        inWidth, outWidth;
257     int        bpp;
258
259     HANDLE_TO_PTR (hXform, g);
260
261     /* Since there is no header, we'll report no usage of input */
262
263     *pdwInputUsed    = 0;
264     *pdwInputNextPos = 0;
265
266     /* Compute the pad info */
267
268     bpp      = g->traits.iBitsPerPixel;
269     left     = g->dwLeft;
270     right    = g->dwRight;
271     inWidth  = g->traits.iPixelsPerRow;
272
273     if (left < 0) {
274         left = -left;
275         // pad horizontally so that width is a multiple of left
276         outWidth = ((inWidth+left-1) / left) * left;
277         more = outWidth - inWidth;
278         left = more >> 1;
279         right = more - left;
280         g->dwLeft  = left;
281         g->dwRight = right;
282     }
283
284     outWidth = inWidth + left + right;
285
286     if (bpp == 1) {
287         /* shift to start at nearest byte boundary */
288         shift = ((left+4) & ~7) - left;
289         left  += shift;   /* this is now a multiple of 8 */
290         right += shift;
291
292         g->bPadVal = g->bPadVal & 1 ? 0xffu : 0;
293     }
294
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;
299
300     /* Report the traits */
301
302     *pInTraits  = g->traits;   /* structure copies */
303     *pOutTraits = g->traits;
304     pOutTraits->iPixelsPerRow = outWidth;
305
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;
314             top = more >> 1;
315             bot = more - top;
316             g->dwTop    = top;
317             g->dwBottom = bot;
318         }
319
320         pOutTraits->lNumRows = pInTraits->lNumRows + g->dwTop + g->dwBottom;
321     }
322
323     INSURE ((int)g->dwLeft >= 0);
324     INSURE ((int)g->dwTop  >= 0);
325
326     return IP_DONE | (g->dwTop>0 ? 0 : IP_READY_FOR_DATA);
327
328     fatal_error:
329     return IP_FATAL_ERROR;
330 }
331
332
333
334 /****************************************************************************\
335  *
336  * pad_getActualBufSizes - Returns buf sizes needed for remainder of job
337  *
338 \****************************************************************************/
339
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 */
344 {
345     PPAD_INST g;
346
347     HANDLE_TO_PTR (hXform, g);
348
349     *pdwMinInBufLen  = g->dwInBytesPerRow;
350     *pdwMinOutBufLen = g->dwOutBytesPerRow;
351     return IP_DONE;
352
353     fatal_error:
354     return IP_FATAL_ERROR;
355 }
356
357
358
359 /*****************************************************************************\
360  *
361  * pad_convert - Converts one row
362  *
363 \*****************************************************************************/
364
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 */
375 {
376     PPAD_INST g;
377     BOOL      bWhiteRow;
378
379     HANDLE_TO_PTR (hXform, g);
380     bWhiteRow = FALSE;
381
382     /**** Decide what to do ****/
383
384     if (pbInputBuf == NULL) {
385         PRINT (_T("pad_convert: Told to flush.\n"), 0, 0);
386
387         if (g->dwInRows < g->dwMinInRows) {
388             /* We need to output another pad row on the bottom */
389             bWhiteRow = TRUE;
390             g->dwInRows += 1;
391         } else if (g->dwBottom > 0) {
392             /* We need to output another pad row on the bottom */
393             bWhiteRow = TRUE;
394             g->dwBottom -= 1;
395         } else {
396             /* We are done */
397             *pdwInputUsed = *pdwOutputUsed = 0;
398             *pdwInputNextPos  = g->dwInNextPos;
399             *pdwOutputThisPos = g->dwOutNextPos;
400             return IP_DONE;
401         }
402     } else if (g->dwOutRows < g->dwTop) {
403         /* We need to output another pad row on the top */
404         bWhiteRow = TRUE;
405     }
406
407     /**** Output a Row ****/
408
409     INSURE (bWhiteRow || (dwInputAvail >= g->dwInBytesPerRow));
410     INSURE (dwOutputAvail >= g->dwOutBytesPerRow);
411
412     if (bWhiteRow)
413         memset (pbOutputBuf, g->bPadVal, g->dwOutBytesPerRow);
414     else {
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);
421
422         g->dwInRows += 1;
423         *pdwInputUsed     = g->dwInBytesPerRow;
424         g->dwInNextPos   += g->dwInBytesPerRow;
425     }
426
427     g->dwOutRows += 1;
428     *pdwInputNextPos  = g->dwInNextPos;
429     *pdwOutputUsed    = g->dwOutBytesPerRow;
430     *pdwOutputThisPos = g->dwOutNextPos;
431     g->dwOutNextPos  += g->dwOutBytesPerRow;
432
433     return (bWhiteRow ? 0 : IP_CONSUMED_ROW) |
434            IP_PRODUCED_ROW |
435            (g->dwOutRows < g->dwTop ? 0 : IP_READY_FOR_DATA);
436
437     fatal_error:
438     return IP_FATAL_ERROR;
439 }
440
441
442
443 /*****************************************************************************\
444  *
445  * pad_insertedData - client inserted into our output stream
446  *
447 \*****************************************************************************/
448
449 static WORD pad_insertedData (
450     IP_XFORM_HANDLE hXform,
451     DWORD           dwNumBytes)
452 {
453     fatalBreakPoint ();
454     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
455 }
456
457
458
459 /*****************************************************************************\
460  *
461  * pad_newPage - Tells us to flush this page, and start a new page
462  *
463 \*****************************************************************************/
464
465 static WORD pad_newPage (
466     IP_XFORM_HANDLE hXform)
467 {
468     PPAD_INST g;
469
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 */
473
474     fatal_error:
475     return IP_FATAL_ERROR;
476
477 }
478
479
480
481 /*****************************************************************************\
482  *
483  * pad_closeXform - Destroys this instance
484  *
485 \*****************************************************************************/
486
487 static WORD pad_closeXform (IP_XFORM_HANDLE hXform)
488 {
489     PPAD_INST g;
490
491     HANDLE_TO_PTR (hXform, g);
492
493     g->dwValidChk = 0;
494     IP_MEM_FREE (g);       /* free memory for the instance */
495
496     return IP_DONE;
497
498     fatal_error:
499     return IP_FATAL_ERROR;
500 }
501
502
503
504 /*****************************************************************************\
505  *
506  * padTbl - Jump-table for transform driver
507  *
508 \*****************************************************************************/
509
510 IP_XFORM_TBL padTbl = {
511     pad_openXform,
512     pad_setDefaultInputTraits,
513     pad_setXformSpec,
514     pad_getHeaderBufSize,
515     pad_getActualTraits,
516     pad_getActualBufSizes,
517     pad_convert,
518     pad_newPage,
519     pad_insertedData,
520     pad_closeXform
521 };
522
523 /* End of File */