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 (minus bilevel scaling) by David Paschal.
37 /******************************************************************************\
39 * xscale.c - Scales (and interpolates) bi-level, gray and color
41 ******************************************************************************
43 * Name of Global Jump-Table:
47 * Items in aXformInfo array passed into setXformSpec:
49 * aXformInfo[IP_SCALE_HORIZ_FACTOR] = Horizontal scale-factor, in 8.24 fixed point
51 * aXformInfo[IP_SCALE_VERT_FACTOR] = Vertical scale-factor, in 8.24 fixed point
53 * aXformInfo[IP_SCALE_FAST] = scale fast using simple pixel-replication? 0=no, 1=yes
54 * currently, this only affects bi-level up-scaling.
56 * Capabilities and Limitations:
58 * This driver can scale both up and down, independently. That is, one
59 * direction can up-scale while the other direction down-scales. Bi-level
60 * scaling is done using tables to maximize speed. 24-bit color,
61 * 8-bit gray and bi-level pixels can be scaled.
63 * Color and gray data are interpolated intellegently.
64 * Bi-level data are smoothed when up-scaling (several patents), and
65 * data-loss is avoided when down-scaling (another patent).
67 * The allowed scale-factor ranges differ based on data type (bi-level,
68 * gray and color). An assert will occur if range is exceeded.
71 * bi-level: horiz_fac=[1/2..4.0] vert_fac=[1/16..4.0]
72 * gray: horiz_fac=[1/4..6.0] vert_fac=[1/4..6.0]
73 * color: horiz_fac=[1/4..6.0] vert_fac=[1/4..6.0]
75 * Default Input Traits, and Output Traits:
77 * trait default input output
78 * ------------------- --------------------- ------------------------
79 * iPixelsPerRow * passed into output computed
80 * iBitsPerPixel * passed into output same as default input
81 * iComponentsPerPixel * passed into output same as default input
82 * lHorizDPI passed into output same as default input
83 * lVertDPI passed into output same as default input
84 * lNumRows passed into output computed
85 * iNumPages passed into output same as default input
86 * iPageNum passed into output same as default input
88 * Above, a "*" by an item indicates it must be valid (not negative).
91 * Feb 1998 Mark Overton, ported to new Windows software Image Processor
92 * Jun 1997 Mark Overton, added color scaling
93 * May 1997 Mark Overton, added gray scaling
94 * 1995 Mark Overton, wrote original code (bi-level only)
96 \******************************************************************************/
98 #include "string.h" /* for memset and memcpy */
109 #define PRINT(msg,arg1,arg2) \
110 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
112 #define PRINT(msg,arg1,arg2)
115 #define CHECK_VALUE 0x1ce5ca7e
116 #define SC_WHITE_ROW 1 /* was for tracking all-white rows; not used */
119 /*____________________________________________________________________________
121 | Things common to all image-types |
122 |____________________________________________________________________________|
126 #define MAX_ROWS_AP 6 /* Number of entries in rows_ap */
127 #define HELD_ARRAY_SIZE 7 /* # entries in apHeldOutRows array */
136 /* SC_INST contains all the variables for a scaling-instance */
139 IM_TYPE image_type; /* type of image (bilevel, gray, color) */
140 BOOL fast; /* scale (quickly) using pixel replication? */
141 BYTE nMoreFlush; /* # more flush calls reqd to send buffered rows */
142 ULONG horiz_fac; /* horiz scale-factor (16.16 fixed-pt) */
143 ULONG vert_fac; /* vert scale-factor (16.16 fixed-pt) */
144 long vert_pos; /* current vert pos (16.16; signed, we use neg) */
145 int in_row_nbytes; /* # bytes in each input row */
146 int out_row_nbytes; /* # bytes in each output row */
147 int out_row_pixels; /* # pixels in each output row */
148 int in_nrows; /* number of rows read in so far */
149 int out_nrows; /* number of rows written so far */
150 BYTE *rows_ap[MAX_ROWS_AP]; /* ptrs to successive input rows */
151 int nMaxOutRows; /* max # output rows resulting from one input row*/
152 int nMoreHeldOutRows;/* more output rows needed to be returned */
153 int iNextHeldOutRow; /* index of next output row to be returned */
154 BYTE *apHeldOutRows[HELD_ARRAY_SIZE];
155 /* output rows stored for subsequent returning; */
156 /* index [0] is caller's output buffer */
157 int top_row; /* bilevel: index of top of 3 rows in rows_ap */
158 ULONG post_fac; /* bilevel: additional upscaling */
159 BYTE mid_traits; /* bilevel: trait-bits of middle row */
161 ULONG inv_horiz_fac; /* gray: inverse of horiz scaling factor (16.16) */
162 ULONG inv_vert_fac; /* gray: inverse of vert scaling factor (16.16) */
163 long inv_vert_pos; /* cur inv vert pos (16.16; signed, we use neg) */
164 BYTE n_saved_rows; /* gray: # rows saved in rows_ap for vert scaling*/
165 BYTE n_alloced_rows; /* gray: # rows allocated in rows_ap */
167 IP_IMAGE_TRAITS inTraits;/* traits of the input image */
168 DWORD dwInNextPos; /* file pos for subsequent input */
169 DWORD dwOutNextPos; /* file pos for subsequent output */
170 DWORD dwValidChk; /* struct validity check value */
171 } SC_INST, *PSC_INST;
174 /******************************************************************************
175 ******************************************************************************
177 DUMMY BILEVEL FUNCTIONS
179 ******************************************************************************
180 ******************************************************************************/
182 /* These functions were removed because they contained patented algorithms.
183 * Therefore, only gray and color (not bilevel) scaling are currently
184 * supported. If this is ever fixed, then remove the assert in
185 * scale_setDefaultInputTraits(). */
187 void bi_fast_open(PSC_INST g, UINT in_row_len) {
191 void bi_scale_open(PSC_INST g, UINT in_row_len) {
195 int bi_fast_row(PSC_INST g,PBYTE pbInputBuf,BYTE src_traits,
196 BYTE *apHeldOutRows[],ULONG *pdest_traits) {
201 int bi_scale_row(PSC_INST g,PBYTE pbInputBuf,BYTE src_traits,
202 BYTE *apHeldOutRows[],ULONG *pdest_traits) {
207 void bi_fast_close(PSC_INST g) {
211 void bi_scale_close(PSC_INST g) {
216 /******************************************************************************
217 ******************************************************************************
219 CONTONE (GRAY AND COLOR)
221 ******************************************************************************
222 ******************************************************************************/
228 * The descriptions below are for the X axis. For the Y axis, substitute
229 * "input row" for "input pixel", and "output row" for "output pixel", and
230 * apply weights to entire rows using the same algorithms.
232 * Each axis is scaled separately using the these methods. So you can
233 * down-scale in one axis and up-scale in the other, if you wish.
236 * Down-scaling Algorithm
238 * Imagine marking the pixel-boundaries on two rulers, and laying them
239 * next to each other:
242 * |______|______|______|______|______|______|______| <-- input pixels
243 * | | | | | <-- output pixels
246 * An output pixel consists of a weighted sum of the input pixels that
247 * it overlaps. The weights are the amount of overlap.
249 * pos is the right side of the leftmost input pixel that overlaps the
250 * current output pixel. This position is in units of output pixels (a
251 * distance of 1 is the width of an output pixel), and 0 is the left side
252 * of the current output pixel. Since this position is in units of output
253 * pixels, it can be used to easily compute the weights.
255 * The weights of the overlapping input pixels are:
258 * middle pixels (if any): scale factor (which is less than 1)
259 * rightmost: 1.0 - (sum of above weights)
261 * Above, the pixel 'out' is computed as:
263 * out = pos*in1 + scalefactor*in2 + (1-pos-scalefactor)*in3
266 * Up-scaling Algorithm
268 * I first tried an overlap method like that used for down-scaling, but
269 * for large scale-factors, one output pixel would overlap two input
270 * pixels, and many output pixels would overlap just one input pixel.
271 * So the result looked almost as bad as pixel-replication, because many
272 * pixels were indeed just replications.
274 * So I devised an interpolating algorithm wherein a pos value is the
275 * weight of the next input pixel, and (1-pos) is the weight of the
276 * current input pixel. As pos increases along the current input pixel,
277 * the weight will smoothly shift from it to the next input pixel,
278 * eliminating jaggies.
281 * |___________|___________|___________|___________| <-- input_pixels
282 * | | | out | | | | | <-- output pixels
285 * pos is the left side of the current output pixel, in units of input
286 * pixels. 0 is the left side of the current input pixel (in0 above).
288 * pos is advanced by adding 1/scalefactor to it. When it becomes >= 1,
289 * move to the next input pixel, and subtract 1 from pos.
291 * Above, the pixel 'out' is computed as: out = (1-pos)*in0 + pos*in1
294 #define CONTONE_MIN_HORIZ_FAC (ULONG)0x04000 /* 0.25 */
295 /* Minimum horizontal scale-factor (16.16) */
297 #define CONTONE_MAX_HORIZ_FAC ((ULONG)MAX_ROWS_AP << 16)
298 /* Maximum horizontal scale-factor (arbitrary) */
300 #define CONTONE_MIN_VERT_FAC (ULONG)0x04000 /* 0.25 */
301 /* Minimum vertical scale-factor (16.16) */
303 #define CONTONE_MAX_VERT_FAC ((ULONG)MAX_ROWS_AP << 16)
304 /* Maximum vertical scale-factor (16.16) */
308 /*____________________________________________________________________________
310 | gray_horiz_scale | Scales the given input row into the given output row |
311 |__________________|_________________________________________________________|
313 | Up-scaling is done by interpolation using horiz_pos. |
314 | Down-scaling is done by blending (averaging two or more input pixels |
315 | together, forming an output pixel). |
316 |____________________________________________________________________________|
318 static void gray_horiz_scale (
319 SC_INST *g, /* in: our instance variables */
320 BYTE *src_p, /* in: input row to be scaled */
321 BYTE *dest_p) /* out: output row that we scaled */
323 ULONG horiz_pos, new_pos;
324 BYTE *in_p, *out_p, *out_aft_p;
331 out_aft_p = out_p + g->out_row_nbytes;
332 in_p[g->in_row_nbytes] = in_p[g->in_row_nbytes-1]; /* dup right pixel */
338 if (g->horiz_fac >= 0x00010000u)
342 while (out_p < out_aft_p) {
344 w2 = (UINT) (horiz_pos >> 8);
346 *out_p++ = (w1*in_p[0] + w2*in_p[1]) >> 8;
347 horiz_pos += g->inv_horiz_fac;
348 } while ((horiz_pos>>16) == 0);
350 horiz_pos &= 0x0000ffffu;
362 while (out_p < out_aft_p) {
364 horiz_pos += g->inv_horiz_fac;
365 in_p += horiz_pos >> 16;
366 horiz_pos &= 0x0000ffffu;
371 horiz_pos = g->horiz_fac;
372 w2 = g->horiz_fac >> 8;
374 while (out_p < out_aft_p) {
378 new_pos += g->horiz_fac;
380 } while ((new_pos>>16) == 0);
382 /* Blend n_pix pixels together using these weights:
383 * 1st pixel: horiz_pos
384 * mid pixels: horiz_fac
385 * final pixel: 1.0 - (sum of above weights)
387 sum = horiz_pos >> 8;
388 pix = sum * (*in_p++); /* 1st pixel */
390 for (u=1; u<=n_pix-2; u++) {
391 pix += w2 * (*in_p++); /* middle pixels */
395 pix += (256-sum) * (*in_p); /* final pixel */
398 horiz_pos = new_pos & 0x0000ffffu;
400 } /* end if up-scaling else down-scaling */
405 /*____________________________________________________________________________
407 | color_horiz_scale | Scales the given input row into the given output row |
408 |___________________|________________________________________________________|
410 | Up-scaling is done by interpolation using horiz_pos. |
411 | Down-scaling is done by blending (averaging two or more input pixels |
412 | together, forming an output pixel). |
413 |____________________________________________________________________________|
415 static void color_horiz_scale (
416 SC_INST *g, /* in: our instance variables */
417 BYTE *src_p, /* in: input row to be scaled */
418 BYTE *dest_p) /* out: output row that we scaled */
420 ULONG horiz_pos, new_pos;
421 BYTE *in_p, *out_p, *out_aft_p, *p;
422 UINT sum, pix_y, pix_u, pix_v;
428 out_aft_p = out_p + g->out_row_nbytes;
430 p = in_p + g->in_row_nbytes;
431 p[0] = p[-3]; /* dup right pixel */
439 if (g->horiz_fac >= 0x00010000u)
443 while (out_p < out_aft_p) {
445 w2 = (UINT) (horiz_pos >> 8);
447 *out_p++ = (w1*in_p[0] + w2*in_p[3]) >> 8; /* y component */
448 *out_p++ = (w1*in_p[1] + w2*in_p[4]) >> 8; /* u component */
449 *out_p++ = (w1*in_p[2] + w2*in_p[5]) >> 8; /* v component */
450 horiz_pos += g->inv_horiz_fac;
451 } while ((horiz_pos>>16) == 0);
453 horiz_pos &= 0x0000ffffu;
466 while (out_p < out_aft_p) {
471 horiz_pos += g->inv_horiz_fac;
472 iStep = horiz_pos >> 16;
473 in_p += iStep + iStep + iStep;
474 horiz_pos &= 0x0000ffffu;
477 else // down-scaling, not fast
479 horiz_pos = g->horiz_fac;
480 w2 = g->horiz_fac >> 8;
482 while (out_p < out_aft_p) {
486 new_pos += g->horiz_fac;
488 } while ((new_pos>>16) == 0);
490 /* Blend n_pix pixels together using these weights:
491 * 1st pixel: horiz_pos
492 * mid pixels: horiz_fac
493 * final pixel: 1.0 - (sum of above weights)
495 sum = horiz_pos >> 8;
496 pix_y = sum * (*in_p++); /* 1st pixel */
497 pix_u = sum * (*in_p++);
498 pix_v = sum * (*in_p++);
500 for (u=1; u<=n_pix-2; u++) {
501 pix_y += w2 * (*in_p++); /* middle pixels */
502 pix_u += w2 * (*in_p++);
503 pix_v += w2 * (*in_p++);
508 pix_y += sum * in_p[0]; /* final pixel */
509 pix_u += sum * in_p[1];
510 pix_v += sum * in_p[2];
512 *out_p++ = pix_y >> 8;
513 *out_p++ = pix_u >> 8;
514 *out_p++ = pix_v >> 8;
515 horiz_pos = new_pos & 0x0000ffffu;
517 } /* end if up-scaling else down-scaling */
522 /*____________________________________________________________________________
524 | weight_two_rows | Output row is a weighted-average of two rows in rows_ap |
525 |_________________|__________________________________________________________|
527 | rows_ap[0] is weighted by first_weight. |
528 | rows_ap[1] is weighted by 1.0 - first_weight. |
529 | The output is written to dest_p. |
530 |____________________________________________________________________________|
532 static void weight_two_rows (
533 SC_INST *g, /* in: our instance variables */
534 ULONG first_weight, /* in: weight for first row (16.16) */
535 BYTE *dest_p) /* out: output row */
538 BYTE *out_p, *out_aft_p;
543 out_aft_p = out_p + g->out_row_nbytes;
547 w1 = first_weight >> 8;
549 while (out_p < out_aft_p)
550 *out_p++ = (w1*(*p1++) + w2*(*p2++)) >> 8;
552 switch ((first_weight+(1u<<12)) >> 13) /* round weight to closest 8th */
555 memcpy (out_p, p2, g->out_row_nbytes);
558 while (out_p < out_aft_p)
559 *out_p++ = (*p1>>3) + *p2 - (*p2>>3);
563 while (out_p < out_aft_p)
564 *out_p++ = (*p1>>2) + *p2 - (*p2>>2);
568 while (out_p < out_aft_p)
569 *out_p++ = (*p1>>2) + (*p1>>3) + (*p2>>1) + (*p2>>3);
573 while (out_p < out_aft_p)
574 *out_p++ = (*p1>>1) + (*p2>>1);
578 while (out_p < out_aft_p)
579 *out_p++ = (*p1>>1) + (*p1>>3) + (*p2>>2) + (*p2>>3);
583 while (out_p < out_aft_p)
584 *out_p++ = *p1 - (*p1>>2) + (*p2>>2);
588 while (out_p < out_aft_p)
589 *out_p++ = *p1 - (*p1>>3) + (*p2>>3);
593 memcpy (out_p, p1, g->out_row_nbytes);
603 /*____________________________________________________________________________
605 | weight_n_rows | Blends two or more rows in rows_ap into one output row |
606 |_______________|____________________________________________________________|
609 | 1st row: first_weight |
610 | middle rows: mid_weight |
611 | final row: 1.0 - (sum of above weights) |
612 |____________________________________________________________________________|
614 static void weight_n_rows (
615 SC_INST *g, /* in: our instance variables */
616 UINT n_rows, /* in: number of rows to blend together */
617 ULONG first_weight, /* in: weight of first row (16.16) */
618 ULONG mid_weight, /* in: weight of middle rows (16.16) */
619 BYTE *dest_p) /* out: output row */
621 BYTE *in_p[MAX_ROWS_AP];
622 BYTE *out_p, *out_aft_p;
623 UINT weights[MAX_ROWS_AP];
627 assert (n_rows>=2 && n_rows<=MAX_ROWS_AP);
630 weight_two_rows (g, first_weight, dest_p);
635 out_aft_p = out_p + g->out_row_nbytes;
636 for (u=0; u<n_rows; u++)
637 in_p[u] = g->rows_ap[u];
639 sum = weights[0] = first_weight >> 8;
640 for (u=1; u<=n_rows-2; u++)
641 sum += (weights[u] = mid_weight >> 8);
642 weights[n_rows-1] = 256 - sum;
644 while (out_p < out_aft_p) {
646 for (u=0; u<n_rows; u++)
647 sum += weights[u] * (*in_p[u]++);
654 /*____________________________________________________________________________
656 | contone_scale_open | sets up the given scaling job |
657 |____________________|_______________________________________________________|
659 static void contone_scale_open (
660 SC_INST *g, /* ptr to our scaling instance */
661 UINT in_row_len) /* # pixels per input row */
663 ULONG horiz_fac; /* scale-factors in 16.16 fixed-point */
667 horiz_fac = g->horiz_fac;
668 vert_fac = g->vert_fac;
671 assert (horiz_fac>=CONTONE_MIN_HORIZ_FAC &&
672 horiz_fac<=CONTONE_MAX_HORIZ_FAC);
673 assert ( vert_fac>=CONTONE_MIN_VERT_FAC &&
674 vert_fac<=CONTONE_MAX_VERT_FAC);
678 g->in_row_nbytes = in_row_len;
679 g->out_row_pixels = g->out_row_nbytes = (horiz_fac*in_row_len) >> 16;
681 if (g->image_type == IM_COLOR) {
682 g->in_row_nbytes *= 3;
683 g->out_row_nbytes *= 3;
686 g->inv_horiz_fac = ((0x80000000u / horiz_fac) << 1) + 1u;
687 g->inv_vert_fac = ((0x80000000u / vert_fac) << 1) + 1u;
688 /* We added 1 to the inverse factors above as an unusual way of rounding */
691 g->n_alloced_rows = 0;
692 } else if (vert_fac >= 0x00010000u) { /* up-scaling vertically */
693 g->inv_vert_pos = g->inv_vert_fac;
694 g->n_alloced_rows = 2;
695 } else { /* down-scaling vertically */
696 g->n_alloced_rows = (BYTE)((g->inv_vert_fac+0x0000ffffu) >> 16) + 1;
697 g->vert_pos = vert_fac;
700 for (n=0; n<g->n_alloced_rows; n++) {
701 IP_MEM_ALLOC (g->out_row_nbytes, g->rows_ap[n]);
702 memset (g->rows_ap[n], 0xff, g->out_row_nbytes + 4);
705 g->nMoreFlush = 0; /* no flush-calls are needed */
714 /*____________________________________________________________________________
716 | contone_scale_close | de-allocates scaling instance |
717 |_____________________|______________________________________________________|
719 static void contone_scale_close (SC_INST *g)
723 for (n=0; n<g->n_alloced_rows; n++)
724 IP_MEM_FREE (g->rows_ap[n]);
729 /*____________________________________________________________________________
731 | contone_scale_row | scales the given input row into 0 or more output rows |
732 |___________________|________________________________________________________|
734 static int contone_scale_row (
735 SC_INST *g, /* in: ptr to our scaling instance */
736 BYTE *src_row_p, /* in: input row */
737 BYTE *dest_rows_ap[]) /* out: output rows */
745 assert (src_row_p != NULL);
747 if (g->fast && g->vert_fac<=0x00010000u)
749 /* down-scaling fast */
750 g->vert_pos += g->vert_fac;
751 n_out_rows = g->vert_pos >> 16;
752 g->vert_pos &= 0x0000ffffu;
754 if (n_out_rows > 0) {
755 if (g->image_type == IM_GRAY) gray_horiz_scale (g, src_row_p, dest_rows_ap[0]);
756 else color_horiz_scale (g, src_row_p, dest_rows_ap[0]);
762 p = g->rows_ap[g->n_saved_rows];
763 if (g->image_type == IM_GRAY) gray_horiz_scale (g, src_row_p, p);
764 else color_horiz_scale (g, src_row_p, p);
766 g->n_saved_rows += 1;
768 if (g->n_saved_rows == 1) {
769 /* call again to duplicate the first row to get us started */
770 return contone_scale_row (g, src_row_p, dest_rows_ap);
773 /*************************/
774 /* Up-scaling Vertically */
775 /*************************/
777 if (g->vert_fac >= 0x00010000u)
781 if (g->n_saved_rows == 2) {
784 weight_two_rows (g, 0x10000u-g->vert_pos,
785 dest_rows_ap[n_out_rows]);
787 g->vert_pos += g->inv_vert_fac;
788 } while ((g->vert_pos>>16) == 0);
789 g->vert_pos &= 0x0000ffffu;
791 /* We use vert_pos solely to determine the number of rows.
792 * We use inv_vert_pos to create the weights.
793 * In the commented-out code above, inv_vert_pos did both,
794 * but the problem was that the number of rows output can
795 * off by 1 compared with (num_in_rows*vert_fac), which is
796 * what our callers expect.
798 g->vert_pos += g->vert_fac;
799 n_out_rows = (UINT)(g->vert_pos >> 16);
800 g->vert_pos &= 0x0000ffffu;
802 for (u=0; u<n_out_rows; u++) {
803 weight = 0x10000 - g->inv_vert_pos;
804 if (weight < 0) weight = 0;
805 else if (weight > 0x10000) weight = 0x10000;
806 weight_two_rows (g, weight, dest_rows_ap[u]);
807 g->inv_vert_pos += g->inv_vert_fac;
810 g->inv_vert_pos -= 0x10000;
812 /* discard the oldest row */
815 g->rows_ap[0] = g->rows_ap[1];
820 /***************************/
821 /* Down-scaling Vertically */
822 /***************************/
827 new_pos = g->vert_pos + (g->n_saved_rows-1)*g->vert_fac;
829 if ((new_pos>>16) != 0) {
830 weight_n_rows (g, g->n_saved_rows, g->vert_pos, g->vert_fac,
833 g->vert_pos = new_pos & 0x0000ffffu;
835 /* retain the newest row */
837 g->rows_ap[0] = g->rows_ap[g->n_saved_rows-1];
838 g->rows_ap[g->n_saved_rows-1] = p;
848 /******************************************************************************
849 ******************************************************************************
851 E X P O R T E D R O U T I N E S
853 ******************************************************************************
854 ******************************************************************************/
858 /*****************************************************************************\
860 * scale_openXform - Creates a new instance of the transformer
862 *****************************************************************************
864 * This returns a handle for the new instance to be passed into
865 * all subsequent calls.
867 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
869 \*****************************************************************************/
871 static WORD scale_openXform (
872 IP_XFORM_HANDLE *pXform) /* out: returned handle */
876 INSURE (pXform != NULL);
877 IP_MEM_ALLOC (sizeof(SC_INST), g);
879 memset (g, 0, sizeof(SC_INST));
880 g->dwValidChk = CHECK_VALUE;
884 return IP_FATAL_ERROR;
889 /*****************************************************************************\
891 * scale_setDefaultInputTraits - Specifies default input image traits
893 *****************************************************************************
895 * The header of the file-type handled by the transform probably does
896 * not include *all* the image traits we'd like to know. Those not
897 * specified in the file-header are filled in from info provided by
900 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
902 \*****************************************************************************/
904 static WORD scale_setDefaultInputTraits (
905 IP_XFORM_HANDLE hXform, /* in: handle for xform */
906 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
910 HANDLE_TO_PTR (hXform, g);
912 /* Insure that values we care about are correct */
913 INSURE ( (pTraits->iBitsPerPixel==24 && pTraits->iComponentsPerPixel==3)
914 || (pTraits->iBitsPerPixel==8 && pTraits->iComponentsPerPixel==1)
915 || (pTraits->iBitsPerPixel==1 && pTraits->iComponentsPerPixel==1));
916 INSURE (pTraits->iPixelsPerRow > 0);
918 switch (pTraits->iBitsPerPixel) {
919 case 1: g->image_type = IM_BILEVEL; break;
920 case 8: g->image_type = IM_GRAY; break;
921 case 24: g->image_type = IM_COLOR; break;
924 /* We don't actually support IM_BILEVEL currently. */
925 INSURE(g->image_type != IM_BILEVEL);
927 g->inTraits = *pTraits; /* a structure copy */
931 return IP_FATAL_ERROR;
936 /*****************************************************************************\
938 * scale_setXformSpec - Provides xform-specific information
940 \*****************************************************************************/
942 static WORD scale_setXformSpec (
943 IP_XFORM_HANDLE hXform, /* in: handle for xform */
944 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
947 HANDLE_TO_PTR (hXform, g);
949 g->horiz_fac = (aXformInfo[IP_SCALE_HORIZ_FACTOR].dword+0x80) >> 8;
950 g->vert_fac = (aXformInfo[IP_SCALE_VERT_FACTOR].dword+0x80) >> 8;
951 g->fast = aXformInfo[IP_SCALE_FAST].dword;
955 return IP_FATAL_ERROR;
960 /*****************************************************************************\
962 * scale_getHeaderBufSize- Returns size of input buf needed to hold header
964 \*****************************************************************************/
966 static WORD scale_getHeaderBufSize (
967 IP_XFORM_HANDLE hXform, /* in: handle for xform */
968 DWORD *pdwInBufLen) /* out: buf size for parsing header */
970 /* since input is raw pixels, there is no header, so set it to zero */
977 /*****************************************************************************\
979 * scale_getActualTraits - Parses header, and returns input & output traits
981 \*****************************************************************************/
983 static WORD scale_getActualTraits (
984 IP_XFORM_HANDLE hXform, /* in: handle for xform */
985 DWORD dwInputAvail, /* in: # avail bytes in input buf */
986 PBYTE pbInputBuf, /* in: ptr to input buffer */
987 PDWORD pdwInputUsed, /* out: # bytes used from input buf */
988 PDWORD pdwInputNextPos,/* out: file-pos to read from next */
989 PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
990 PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
996 HANDLE_TO_PTR (hXform, g);
998 /**** Since there is no header, we'll report no usage of input ****/
1001 *pdwInputNextPos = 0;
1003 /**** Open the particular type of scaler we'll need ****/
1005 in_row_len = g->inTraits.iPixelsPerRow;
1007 switch (g->image_type) {
1009 if (g->vert_fac < 0x10000u)
1010 g->fast = FALSE; /* bi-level down-scale doesn't have fast case */
1011 if (g->fast) bi_fast_open (g, in_row_len);
1012 else bi_scale_open (g, in_row_len);
1017 if (g->vert_fac > 0x10000u)
1018 g->fast = FALSE; /* contone up-scale doesn't have fast case */
1019 contone_scale_open (g, in_row_len);
1023 /**** Allocate the held output rows ****/
1025 g->nMaxOutRows = (g->vert_fac+0x0000ffffu) >> 16;
1026 INSURE (g->nMaxOutRows <= HELD_ARRAY_SIZE);
1027 for (i=1; i<g->nMaxOutRows; i++)
1028 IP_MEM_ALLOC (g->out_row_nbytes, g->apHeldOutRows[i]);
1030 /**** Report back input- and output-traits ****/
1032 *pInTraits = g->inTraits; /* structure copies */
1033 *pOutTraits = g->inTraits;
1034 pOutTraits->iPixelsPerRow = g->out_row_pixels;
1035 if (pInTraits->lNumRows >= 0) {
1036 /* use floating point because fixed-point product would
1037 * overflow if # rows is over 16 bits */
1038 pOutTraits->lNumRows = (long)
1039 ((float)pInTraits->lNumRows * g->vert_fac / 65536.0);
1042 return IP_DONE | IP_READY_FOR_DATA;
1045 return IP_FATAL_ERROR;
1050 /****************************************************************************\
1052 * scale_getActualBufSizes - Returns buf sizes needed for remainder of job
1054 \****************************************************************************/
1056 static WORD scale_getActualBufSizes (
1057 IP_XFORM_HANDLE hXform, /* in: handle for xform */
1058 PDWORD pdwMinInBufLen, /* out: min input buf size */
1059 PDWORD pdwMinOutBufLen) /* out: min output buf size */
1063 HANDLE_TO_PTR (hXform, g);
1064 *pdwMinInBufLen = g->in_row_nbytes;
1065 *pdwMinOutBufLen = g->out_row_nbytes;
1070 return IP_FATAL_ERROR;
1075 /*****************************************************************************\
1077 * scale_convert - Converts one row
1079 \*****************************************************************************/
1081 static WORD scale_convert (
1082 IP_XFORM_HANDLE hXform,
1083 DWORD dwInputAvail, /* in: # avail bytes in in-buf */
1084 PBYTE pbInputBuf, /* in: ptr to in-buffer */
1085 PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
1086 PDWORD pdwInputNextPos, /* out: file-pos to read from next */
1087 DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
1088 PBYTE pbOutputBuf, /* in: ptr to out-buffer */
1089 PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
1090 PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
1095 int inUsed, outUsed;
1099 HANDLE_TO_PTR (hXform, g);
1103 /**** Return next stored output-row, if any ****/
1105 if (g->nMoreHeldOutRows > 0) {
1106 memcpy (pbOutputBuf,
1107 g->apHeldOutRows[g->iNextHeldOutRow],
1109 g->nMoreHeldOutRows -= 1;
1110 g->iNextHeldOutRow += 1;
1111 outUsed = g->out_row_nbytes;
1115 /**** Check if we were told to flush ****/
1117 if (pbInputBuf == NULL) {
1118 PRINT (_T("scale_convert: Told to flush.\n"), 0, 0);
1119 if (g->nMoreFlush == 0)
1122 /* do "scale a row" section below, with pbInputBuf equal to NULL */
1124 inUsed = g->in_row_nbytes;
1126 /**** Scale a Row ****/
1128 g->apHeldOutRows[0] = pbOutputBuf; /* 1st out-row is client's buffer */
1129 n_rows = 0; /* init to avoid compiler warning */
1132 switch (g->image_type) {
1135 n_rows = bi_fast_row (g, pbInputBuf, src_traits,
1136 g->apHeldOutRows, &dest_traits);
1138 n_rows = bi_scale_row (g, pbInputBuf, src_traits,
1139 g->apHeldOutRows, &dest_traits);
1144 n_rows = contone_scale_row (g, pbInputBuf, g->apHeldOutRows);
1148 INSURE (n_rows <= g->nMaxOutRows);
1150 g->nMoreHeldOutRows = n_rows - 1;
1151 g->iNextHeldOutRow = 1;
1152 outUsed = g->out_row_nbytes;
1155 /**** Report results and return (inUsed and outUsed are valid here) ****/
1159 *pdwInputUsed = (DWORD)inUsed;
1160 g->dwInNextPos += (DWORD)inUsed;
1161 *pdwInputNextPos = g->dwInNextPos;
1163 *pdwOutputUsed = (DWORD)outUsed;
1164 *pdwOutputThisPos = g->dwOutNextPos;
1165 g->dwOutNextPos += (DWORD)outUsed;
1167 wResults = ( inUsed>0 ? IP_CONSUMED_ROW : 0)
1168 | (outUsed>0 ? IP_PRODUCED_ROW : 0)
1169 | (g->nMoreHeldOutRows==0 ? IP_READY_FOR_DATA : 0)
1170 | (pbInputBuf==NULL &&
1172 g->nMoreHeldOutRows==0 ? IP_DONE : 0);
1176 return IP_FATAL_ERROR;
1181 /*****************************************************************************\
1183 * scale_insertedData - client inserted into our output stream
1185 \*****************************************************************************/
1187 static WORD scale_insertedData (
1188 IP_XFORM_HANDLE hXform,
1192 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
1197 /*****************************************************************************\
1199 * scale_newPage - Tells us to flush this page, and start a new page
1201 \*****************************************************************************/
1203 static WORD scale_newPage (
1204 IP_XFORM_HANDLE hXform)
1208 HANDLE_TO_PTR (hXform, g);
1209 /* todo: return fatal error if convert is called again? */
1210 return IP_DONE; /* can't insert page-breaks, so ignore this call */
1213 return IP_FATAL_ERROR;
1219 /*****************************************************************************\
1221 * scale_closeXform - Destroys this instance
1223 \*****************************************************************************/
1225 static WORD scale_closeXform (IP_XFORM_HANDLE hXform)
1230 HANDLE_TO_PTR (hXform, g);
1232 switch (g->image_type) {
1234 if (g->fast) bi_fast_close (g);
1235 else bi_scale_close (g);
1240 contone_scale_close (g);
1244 for (i=1; i<g->nMaxOutRows; i++)
1245 IP_MEM_FREE (g->apHeldOutRows[i]);
1248 IP_MEM_FREE (g); /* free memory for the instance */
1253 return IP_FATAL_ERROR;
1258 /*****************************************************************************\
1260 * scaleTbl - Jump-table for scaler
1262 \*****************************************************************************/
1264 IP_XFORM_TBL scaleTbl = {
1266 scale_setDefaultInputTraits,
1268 scale_getHeaderBufSize,
1269 scale_getActualTraits,
1270 scale_getActualBufSizes,