Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xthumb.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  * xthumb.c - Downscales quickly by large factor for generating thumbnail image
40  *
41  ******************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    thumbTbl
46  *
47  * Items in aXformInfo array passed into setXformSpec:
48  *
49  *    aXformInfo[IP_THUMB_SCALE_SPEC] determines scale-factor indirectly or directly,
50  *    depending on whether it's positive or negative.
51  *
52  *    positive:  value is the maximum output-width in pixels. xthumb will
53  *               select the N for the scale-factor of the form 1/N which
54  *               results in the largest possible output width not exceeding
55  *               the value in aXformInfo[IP_THUMB_SCALE_SPEC].
56  *
57  *    negative:  absolute value is N for the scale-factor of the form 1/N.
58  *               the scale-factor is being specified directly.
59  *
60  * Capabilities and Limitations:
61  *
62  *    Downscales any type of raw data quickly by a large scale-factor
63  *    specified by aXformInfo[IP_THUMB_SCALE_SPEC].  The pixels are averaged together.
64  *    For bilevel input, the output is 8-bit gray, where each gray pixel
65  *    is the average blackness of an area of the input bilevel image.
66  *    For 8-bit gray and 24-bit color input data, the output data is
67  *    the same type as the input.
68  *
69  *    The scale-factor is of the form 1/N, where N is an integer.
70  *    Warning: If N is 1 or almost 1, the actual output width will be
71  *    quite smaller than that requested.
72  *
73  *    If input width is smaller than output width, N will be 1 (no
74  *    scaling).
75  *
76  *    ipGetImageTraits must be called to determine the actual output width.
77  *
78  * Default Input Traits, and Output Traits:
79  *
80  *          trait             default input             output
81  *    -------------------  ---------------------  ------------------------
82  *    iPixelsPerRow         * used                 based on scale factor
83  *    iBitsPerPixel         * must be 1, 8 or 24   8 or 24
84  *    iComponentsPerPixel   * must be 1 or 3       same as default input
85  *    lHorizDPI               passed into output   same as default input
86  *    lVertDPI                passed into output   same as default input
87  *    lNumRows                used if valid        based on scale factor
88  *    iNumPages               passed into output   same as default input
89  *    iPageNum                passed into output   same as default input
90  *
91  *    Above, a "*" by an item indicates it must be valid (not negative).
92  *
93  * Mar 1998 Mark Overton -- wrote original code
94  *
95 \******************************************************************************/
96
97 #include "hpip.h"
98 #include "ipdefs.h"
99 #include "string.h"    /* for memset and memcpy */
100
101
102 #if 0
103     #include "stdio.h"
104     #include <tchar.h>
105
106     #define PRINT(msg,arg1,arg2) \
107         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
108 #else
109     #define PRINT(msg,arg1,arg2)
110 #endif
111
112 #define CHECK_VALUE 0x4ba1dace
113
114
115 typedef struct {
116     IP_IMAGE_TRAITS inTraits; /* traits of the input image */
117     int       iFactorSpec;    /* factor spec in aXformInfo[0] */
118     WORD      wScale;         /* the N in scale-factor of 1/N */
119     WORD      wPreShift;      /* # bits to shift sum right before multiply */
120     DWORD     dwSumFac;       /* factor to multiply sum by (16.16 fixed-pt) */
121     DWORD     dwOutputWidth;  /* # pixels per row in output */
122     DWORD     dwInRowBytes;   /* # bytes in each input row */
123     DWORD     dwOutRowBytes;  /* # bytes in each output row */
124     WORD      wMoreRows2Sum;  /* # more rows to be summed together */
125     PULONG    pulSums;        /* pixel-sums; each pixel is a ULONG */
126     ULONG     ulRowsInput;    /* # of rows input  so far */
127     ULONG     ulRowsOutput;   /* # of rows output so far */
128     DWORD     dwInNextPos;    /* file pos for subsequent input */
129     DWORD     dwOutNextPos;   /* file pos for subsequent output */
130     DWORD     dwValidChk;     /* struct validity check value */
131 } TN_INST, *PTN_INST;
132
133
134
135 /*****************************************************************************\
136  *
137  * thumb_openXform - Creates a new instance of the transformer
138  *
139  *****************************************************************************
140  *
141  * This returns a handle for the new instance to be passed into
142  * all subsequent calls.
143  *
144  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
145  *
146 \*****************************************************************************/
147
148 static WORD thumb_openXform (
149     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
150 {
151     PTN_INST g;
152
153     INSURE (pXform != NULL);
154     IP_MEM_ALLOC (sizeof(TN_INST), g);
155     *pXform = g;
156     memset (g, 0, sizeof(TN_INST));
157     g->dwValidChk = CHECK_VALUE;
158     return IP_DONE;
159
160     fatal_error:
161     return IP_FATAL_ERROR;
162 }
163
164
165
166 /*****************************************************************************\
167  *
168  * thumb_setDefaultInputTraits - Specifies default input image traits
169  *
170  *****************************************************************************
171  *
172  * The header of the file-type handled by the transform probably does
173  * not include *all* the image traits we'd like to know.  Those not
174  * specified in the file-header are filled in from info provided by
175  * this routine.
176  *
177  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
178  *
179 \*****************************************************************************/
180
181 static WORD thumb_setDefaultInputTraits (
182     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
183     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
184 {
185     PTN_INST g;
186
187     HANDLE_TO_PTR (hXform, g);
188
189     INSURE (pTraits->iPixelsPerRow > 0);
190     g->inTraits = *pTraits;   /* a structure copy */
191     return IP_DONE;
192
193     fatal_error:
194     return IP_FATAL_ERROR;
195 }
196
197
198
199 /*****************************************************************************\
200  *
201  * thumb_setXformSpec - Provides xform-specific information
202  *
203 \*****************************************************************************/
204
205 static WORD thumb_setXformSpec (
206     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
207     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
208 {
209     PTN_INST g;
210
211     HANDLE_TO_PTR (hXform, g);
212     g->iFactorSpec = (int)aXformInfo[IP_THUMB_SCALE_SPEC].dword;
213     return IP_DONE;
214
215     fatal_error:
216     return IP_FATAL_ERROR;
217 }
218
219
220
221 /*****************************************************************************\
222  *
223  * thumb_getHeaderBufSize- Returns size of input buf needed to hold header
224  *
225 \*****************************************************************************/
226
227 static WORD thumb_getHeaderBufSize (
228     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
229     DWORD           *pdwInBufLen)    /* out: buf size for parsing header */
230 {
231     /* since input is raw pixels, there is no header, so set it to zero */
232     *pdwInBufLen = 0;
233     return IP_DONE;
234 }
235
236
237
238 /*****************************************************************************\
239  *
240  * thumb_getActualTraits - Parses header, and returns input & output traits
241  *
242 \*****************************************************************************/
243
244 static WORD thumb_getActualTraits (
245     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
246     DWORD            dwInputAvail,   /* in:  # avail bytes in input buf */
247     PBYTE            pbInputBuf,     /* in:  ptr to input buffer */
248     PDWORD           pdwInputUsed,   /* out: # bytes used from input buf */
249     PDWORD           pdwInputNextPos,/* out: file-pos to read from next */
250     PIP_IMAGE_TRAITS pInTraits,      /* out: input image traits */
251     PIP_IMAGE_TRAITS pOutTraits)     /* out: output image traits */
252 {
253     PTN_INST g;
254     int      N;
255     long     lMaxSum;
256     long     nBytes;
257
258     HANDLE_TO_PTR (hXform, g);
259
260     /* Since there is no header, we'll report no usage of input */
261     *pdwInputUsed    = 0;
262     *pdwInputNextPos = 0;
263
264     /* Compute N in our scale-factor of 1/N */
265     if (g->iFactorSpec <= 0) {
266         N = -(g->iFactorSpec);
267     } else {
268         /* the +iFactorSpec-1 below biases N high (cieling function),
269          * so the output width is biased low, so that we'll never go
270          * larger than the requested output width.
271          */
272         N = (g->inTraits.iPixelsPerRow + g->iFactorSpec - 1) / g->iFactorSpec;
273     }
274
275     if (N < 1) N = 1;
276     g->wScale = N;
277
278     /* Compute max summation of N-by-N input pixels */
279     lMaxSum = (long)N*N * (g->inTraits.iBitsPerPixel==1 ? 1 : 255);
280
281     /* Compute pre-shift so that max sum does not exceed 16 bits */
282          if (lMaxSum >= (1L<<28)) g->wPreShift = 16;
283     else if (lMaxSum >= (1L<<24)) g->wPreShift = 12;
284     else if (lMaxSum >= (1L<<20)) g->wPreShift = 8;
285     else if (lMaxSum >= (1L<<16)) g->wPreShift = 4;
286     else                          g->wPreShift = 0;
287
288     /* Now do the pre-shift on max sum */
289     lMaxSum >>= g->wPreShift;
290     INSURE (lMaxSum < (1L<<16));  /* make sure it fits in 16 bits */
291
292     /* And compute the factor for converting a sum into a 0..255 pixel */
293     g->dwSumFac = (DWORD)((255.0/(float)lMaxSum) * (float)(1L<<16));
294
295     *pInTraits  = g->inTraits;   /* structure copies */
296     *pOutTraits = g->inTraits;
297
298     if (pOutTraits->iBitsPerPixel == 1)
299         pOutTraits->iBitsPerPixel = 8;
300     pOutTraits->iPixelsPerRow = g->dwOutputWidth = pInTraits->iPixelsPerRow / N;
301     if (pOutTraits->lNumRows >= 0)
302         pOutTraits->lNumRows /= N;
303
304     g->wMoreRows2Sum = N;
305     g->dwInRowBytes =
306         (pInTraits->iPixelsPerRow * pInTraits->iBitsPerPixel + 7) / 8;
307     g->dwOutRowBytes = g->dwOutputWidth * pInTraits->iComponentsPerPixel;
308
309     nBytes = g->dwOutRowBytes * sizeof(ULONG);
310     IP_MEM_ALLOC (nBytes, g->pulSums);
311     memset (g->pulSums, 0, nBytes);
312
313     return IP_DONE | IP_READY_FOR_DATA;
314
315     fatal_error:
316     return IP_FATAL_ERROR;
317 }
318
319
320
321 /****************************************************************************\
322  *
323  * thumb_getActualBufSizes - Returns buf sizes needed for remainder of job
324  *
325 \****************************************************************************/
326
327 static WORD thumb_getActualBufSizes (
328     IP_XFORM_HANDLE hXform,          /* in:  handle for xform */
329     PDWORD          pdwMinInBufLen,  /* out: min input buf size */
330     PDWORD          pdwMinOutBufLen) /* out: min output buf size */
331 {
332     PTN_INST g;
333
334     HANDLE_TO_PTR (hXform, g);
335     *pdwMinInBufLen  = g->dwInRowBytes;
336     *pdwMinOutBufLen = g->dwOutRowBytes;
337     return IP_DONE;
338
339     fatal_error:
340     return IP_FATAL_ERROR;
341 }
342
343
344
345 /*****************************************************************************\
346  *
347  * thumb_convert - Converts one row
348  *
349 \*****************************************************************************/
350
351 static WORD thumb_convert (
352     IP_XFORM_HANDLE hXform,
353     DWORD           dwInputAvail,     /* in:  # avail bytes in in-buf */
354     PBYTE           pbInputBuf,       /* in:  ptr to in-buffer */
355     PDWORD          pdwInputUsed,     /* out: # bytes used from in-buf */
356     PDWORD          pdwInputNextPos,  /* out: file-pos to read from next */
357     DWORD           dwOutputAvail,    /* in:  # avail bytes in out-buf */
358     PBYTE           pbOutputBuf,      /* in:  ptr to out-buffer */
359     PDWORD          pdwOutputUsed,    /* out: # bytes written in out-buf */
360     PDWORD          pdwOutputThisPos) /* out: file-pos to write the data */
361 {
362     PTN_INST g;
363     PBYTE    pIn, pOut;
364     BYTE     bMask, bVal=0;
365     ULONG    ulSum, sum0, sum1, sum2;
366     ULONG    *pulSum, *pulSumAfter;
367     UINT     u;
368     BOOL     fSentRow;
369
370     HANDLE_TO_PTR (hXform, g);
371     pulSumAfter = g->pulSums + g->dwOutRowBytes;
372
373     /**** Check if we were told to flush ****/
374
375     if (pbInputBuf == NULL) {
376         PRINT (_T("thumb_convert: Told to flush.\n"), 0, 0);
377         *pdwInputUsed = *pdwOutputUsed = 0;
378         *pdwInputNextPos  = g->dwInNextPos;
379         *pdwOutputThisPos = g->dwOutNextPos;
380         return IP_DONE;
381     }
382
383     /**** Sum this Input Row ****/
384
385     INSURE (dwInputAvail >= g->dwInRowBytes);
386     pIn = pbInputBuf;
387
388     switch (g->inTraits.iBitsPerPixel) {
389         case 1:   /* bilevel input */
390             bMask = 0;
391             for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum++) {
392                 ulSum = *pulSum;
393                 for (u=g->wScale; u>0; u--) {
394                     if (bMask == 0) {
395                         bMask = 0x80u;
396                         bVal = *pIn++;
397                     }
398                     if ((bMask & bVal) == 0) {
399                         /* since the sum is a measure of overall whiteness,
400                          * increment it for a *white* input pixel (0)  */
401                         ulSum += 1;
402                     }
403                     bMask >>= 1;
404                 }
405                 *pulSum = ulSum;
406             }
407         break;
408
409         case 8:   /* 8-bit gray input */
410             for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum++) {
411                 ulSum = *pulSum;
412                 for (u=g->wScale; u>0; u--)
413                     ulSum += (ULONG)(*pIn++);
414                 *pulSum = ulSum;
415             }
416         break;
417
418         case 24:   /* 3-component color input */
419             for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum+=3) {
420                 sum0 = pulSum[0];
421                 sum1 = pulSum[1];
422                 sum2 = pulSum[2];
423                 for (u=g->wScale; u>0; u--) {
424                     sum0 += (ULONG)(*pIn++);
425                     sum1 += (ULONG)(*pIn++);
426                     sum2 += (ULONG)(*pIn++);
427                 }
428                 pulSum[0] = sum0;
429                 pulSum[1] = sum1;
430                 pulSum[2] = sum2;
431             }
432         break;
433     } /* switch */
434
435     *pdwInputUsed     = g->dwInRowBytes;
436     g->dwInNextPos   += g->dwInRowBytes;
437     *pdwInputNextPos  = g->dwInNextPos;
438     g->ulRowsInput += 1;
439
440     /**** If it's time, Compute Output Row ****/
441
442     *pdwOutputThisPos = g->dwOutNextPos;
443     g->wMoreRows2Sum -= 1;
444
445     if (g->wMoreRows2Sum > 0) {
446         fSentRow = FALSE;
447         *pdwOutputUsed = 0;
448     } else {
449         g->wMoreRows2Sum = g->wScale;
450         fSentRow = TRUE;
451         g->ulRowsOutput += 1;
452         INSURE (dwOutputAvail >= g->dwOutRowBytes);
453         *pdwOutputUsed   = g->dwOutRowBytes;
454         g->dwOutNextPos += g->dwOutRowBytes;
455
456         pulSum = g->pulSums;
457         pOut = pbOutputBuf;
458         for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum++) {
459             *pOut++ = (BYTE)((*pulSum >> g->wPreShift) * g->dwSumFac >> 16);
460         }
461
462         memset (g->pulSums, 0, g->dwOutRowBytes*sizeof(ULONG));
463     }
464
465     /**** Return ****/   
466
467     return IP_CONSUMED_ROW   |
468            IP_READY_FOR_DATA |
469            (fSentRow ? IP_PRODUCED_ROW : 0);
470
471     fatal_error:
472     return IP_FATAL_ERROR;
473 }
474
475
476
477 /*****************************************************************************\
478  *
479  * thumb_insertedData - client inserted into our output stream
480  *
481 \*****************************************************************************/
482
483 static WORD thumb_insertedData (
484     IP_XFORM_HANDLE hXform,
485     DWORD           dwNumBytes)
486 {
487     fatalBreakPoint ();
488     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
489 }
490
491
492
493 /*****************************************************************************\
494  *
495  * thumb_newPage - Tells us to flush this page, and start a new page
496  *
497 \*****************************************************************************/
498
499 static WORD thumb_newPage (
500     IP_XFORM_HANDLE hXform)
501 {
502     PTN_INST g;
503
504     HANDLE_TO_PTR (hXform, g);
505     return IP_DONE;   /* can't insert page-breaks, so ignore this call */
506
507     fatal_error:
508     return IP_FATAL_ERROR;
509
510 }
511
512
513
514 /*****************************************************************************\
515  *
516  * thumb_closeXform - Destroys this instance
517  *
518 \*****************************************************************************/
519
520 static WORD thumb_closeXform (IP_XFORM_HANDLE hXform)
521 {
522     PTN_INST g;
523
524     HANDLE_TO_PTR (hXform, g);
525
526     if (g->pulSums != NULL)
527         IP_MEM_FREE (g->pulSums);
528     g->dwValidChk = 0;
529     IP_MEM_FREE (g);       /* free memory for the instance */
530
531     return IP_DONE;
532
533     fatal_error:
534     return IP_FATAL_ERROR;
535 }
536
537
538
539 /*****************************************************************************\
540  *
541  * thumbTbl - Jump-table for transform driver
542  *
543 \*****************************************************************************/
544
545 IP_XFORM_TBL thumbTbl = {
546     thumb_openXform,
547     thumb_setDefaultInputTraits,
548     thumb_setXformSpec,
549     thumb_getHeaderBufSize,
550     thumb_getActualTraits,
551     thumb_getActualBufSizes,
552     thumb_convert,
553     thumb_newPage,
554     thumb_insertedData,
555     thumb_closeXform
556 };
557
558 /* End of File */