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 * xthumb.c - Downscales quickly by large factor for generating thumbnail image
41 ******************************************************************************
43 * Name of Global Jump-Table:
47 * Items in aXformInfo array passed into setXformSpec:
49 * aXformInfo[IP_THUMB_SCALE_SPEC] determines scale-factor indirectly or directly,
50 * depending on whether it's positive or negative.
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].
57 * negative: absolute value is N for the scale-factor of the form 1/N.
58 * the scale-factor is being specified directly.
60 * Capabilities and Limitations:
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.
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.
73 * If input width is smaller than output width, N will be 1 (no
76 * ipGetImageTraits must be called to determine the actual output width.
78 * Default Input Traits, and Output Traits:
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
91 * Above, a "*" by an item indicates it must be valid (not negative).
93 * Mar 1998 Mark Overton -- wrote original code
95 \******************************************************************************/
99 #include "string.h" /* for memset and memcpy */
106 #define PRINT(msg,arg1,arg2) \
107 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
109 #define PRINT(msg,arg1,arg2)
112 #define CHECK_VALUE 0x4ba1dace
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;
135 /*****************************************************************************\
137 * thumb_openXform - Creates a new instance of the transformer
139 *****************************************************************************
141 * This returns a handle for the new instance to be passed into
142 * all subsequent calls.
144 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
146 \*****************************************************************************/
148 static WORD thumb_openXform (
149 IP_XFORM_HANDLE *pXform) /* out: returned handle */
153 INSURE (pXform != NULL);
154 IP_MEM_ALLOC (sizeof(TN_INST), g);
156 memset (g, 0, sizeof(TN_INST));
157 g->dwValidChk = CHECK_VALUE;
161 return IP_FATAL_ERROR;
166 /*****************************************************************************\
168 * thumb_setDefaultInputTraits - Specifies default input image traits
170 *****************************************************************************
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
177 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
179 \*****************************************************************************/
181 static WORD thumb_setDefaultInputTraits (
182 IP_XFORM_HANDLE hXform, /* in: handle for xform */
183 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
187 HANDLE_TO_PTR (hXform, g);
189 INSURE (pTraits->iPixelsPerRow > 0);
190 g->inTraits = *pTraits; /* a structure copy */
194 return IP_FATAL_ERROR;
199 /*****************************************************************************\
201 * thumb_setXformSpec - Provides xform-specific information
203 \*****************************************************************************/
205 static WORD thumb_setXformSpec (
206 IP_XFORM_HANDLE hXform, /* in: handle for xform */
207 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
211 HANDLE_TO_PTR (hXform, g);
212 g->iFactorSpec = (int)aXformInfo[IP_THUMB_SCALE_SPEC].dword;
216 return IP_FATAL_ERROR;
221 /*****************************************************************************\
223 * thumb_getHeaderBufSize- Returns size of input buf needed to hold header
225 \*****************************************************************************/
227 static WORD thumb_getHeaderBufSize (
228 IP_XFORM_HANDLE hXform, /* in: handle for xform */
229 DWORD *pdwInBufLen) /* out: buf size for parsing header */
231 /* since input is raw pixels, there is no header, so set it to zero */
238 /*****************************************************************************\
240 * thumb_getActualTraits - Parses header, and returns input & output traits
242 \*****************************************************************************/
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 */
258 HANDLE_TO_PTR (hXform, g);
260 /* Since there is no header, we'll report no usage of input */
262 *pdwInputNextPos = 0;
264 /* Compute N in our scale-factor of 1/N */
265 if (g->iFactorSpec <= 0) {
266 N = -(g->iFactorSpec);
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.
272 N = (g->inTraits.iPixelsPerRow + g->iFactorSpec - 1) / g->iFactorSpec;
278 /* Compute max summation of N-by-N input pixels */
279 lMaxSum = (long)N*N * (g->inTraits.iBitsPerPixel==1 ? 1 : 255);
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;
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 */
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));
295 *pInTraits = g->inTraits; /* structure copies */
296 *pOutTraits = g->inTraits;
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;
304 g->wMoreRows2Sum = N;
306 (pInTraits->iPixelsPerRow * pInTraits->iBitsPerPixel + 7) / 8;
307 g->dwOutRowBytes = g->dwOutputWidth * pInTraits->iComponentsPerPixel;
309 nBytes = g->dwOutRowBytes * sizeof(ULONG);
310 IP_MEM_ALLOC (nBytes, g->pulSums);
311 memset (g->pulSums, 0, nBytes);
313 return IP_DONE | IP_READY_FOR_DATA;
316 return IP_FATAL_ERROR;
321 /****************************************************************************\
323 * thumb_getActualBufSizes - Returns buf sizes needed for remainder of job
325 \****************************************************************************/
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 */
334 HANDLE_TO_PTR (hXform, g);
335 *pdwMinInBufLen = g->dwInRowBytes;
336 *pdwMinOutBufLen = g->dwOutRowBytes;
340 return IP_FATAL_ERROR;
345 /*****************************************************************************\
347 * thumb_convert - Converts one row
349 \*****************************************************************************/
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 */
365 ULONG ulSum, sum0, sum1, sum2;
366 ULONG *pulSum, *pulSumAfter;
370 HANDLE_TO_PTR (hXform, g);
371 pulSumAfter = g->pulSums + g->dwOutRowBytes;
373 /**** Check if we were told to flush ****/
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;
383 /**** Sum this Input Row ****/
385 INSURE (dwInputAvail >= g->dwInRowBytes);
388 switch (g->inTraits.iBitsPerPixel) {
389 case 1: /* bilevel input */
391 for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum++) {
393 for (u=g->wScale; u>0; u--) {
398 if ((bMask & bVal) == 0) {
399 /* since the sum is a measure of overall whiteness,
400 * increment it for a *white* input pixel (0) */
409 case 8: /* 8-bit gray input */
410 for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum++) {
412 for (u=g->wScale; u>0; u--)
413 ulSum += (ULONG)(*pIn++);
418 case 24: /* 3-component color input */
419 for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum+=3) {
423 for (u=g->wScale; u>0; u--) {
424 sum0 += (ULONG)(*pIn++);
425 sum1 += (ULONG)(*pIn++);
426 sum2 += (ULONG)(*pIn++);
435 *pdwInputUsed = g->dwInRowBytes;
436 g->dwInNextPos += g->dwInRowBytes;
437 *pdwInputNextPos = g->dwInNextPos;
440 /**** If it's time, Compute Output Row ****/
442 *pdwOutputThisPos = g->dwOutNextPos;
443 g->wMoreRows2Sum -= 1;
445 if (g->wMoreRows2Sum > 0) {
449 g->wMoreRows2Sum = g->wScale;
451 g->ulRowsOutput += 1;
452 INSURE (dwOutputAvail >= g->dwOutRowBytes);
453 *pdwOutputUsed = g->dwOutRowBytes;
454 g->dwOutNextPos += g->dwOutRowBytes;
458 for (pulSum=g->pulSums; pulSum<pulSumAfter; pulSum++) {
459 *pOut++ = (BYTE)((*pulSum >> g->wPreShift) * g->dwSumFac >> 16);
462 memset (g->pulSums, 0, g->dwOutRowBytes*sizeof(ULONG));
467 return IP_CONSUMED_ROW |
469 (fSentRow ? IP_PRODUCED_ROW : 0);
472 return IP_FATAL_ERROR;
477 /*****************************************************************************\
479 * thumb_insertedData - client inserted into our output stream
481 \*****************************************************************************/
483 static WORD thumb_insertedData (
484 IP_XFORM_HANDLE hXform,
488 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
493 /*****************************************************************************\
495 * thumb_newPage - Tells us to flush this page, and start a new page
497 \*****************************************************************************/
499 static WORD thumb_newPage (
500 IP_XFORM_HANDLE hXform)
504 HANDLE_TO_PTR (hXform, g);
505 return IP_DONE; /* can't insert page-breaks, so ignore this call */
508 return IP_FATAL_ERROR;
514 /*****************************************************************************\
516 * thumb_closeXform - Destroys this instance
518 \*****************************************************************************/
520 static WORD thumb_closeXform (IP_XFORM_HANDLE hXform)
524 HANDLE_TO_PTR (hXform, g);
526 if (g->pulSums != NULL)
527 IP_MEM_FREE (g->pulSums);
529 IP_MEM_FREE (g); /* free memory for the instance */
534 return IP_FATAL_ERROR;
539 /*****************************************************************************\
541 * thumbTbl - Jump-table for transform driver
543 \*****************************************************************************/
545 IP_XFORM_TBL thumbTbl = {
547 thumb_setDefaultInputTraits,
549 thumb_getHeaderBufSize,
550 thumb_getActualTraits,
551 thumb_getActualBufSizes,