Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xscale.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 (minus bilevel scaling) by David Paschal.
35  */
36
37 /******************************************************************************\
38  *
39  * xscale.c - Scales (and interpolates) bi-level, gray and color
40  *
41  ******************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    scaleTbl
46  *
47  * Items in aXformInfo array passed into setXformSpec:
48  *
49  *    aXformInfo[IP_SCALE_HORIZ_FACTOR] = Horizontal scale-factor, in 8.24 fixed point
50  *
51  *    aXformInfo[IP_SCALE_VERT_FACTOR] = Vertical scale-factor, in 8.24 fixed point
52  *
53  *    aXformInfo[IP_SCALE_FAST] = scale fast using simple pixel-replication? 0=no, 1=yes
54  *                                currently, this only affects bi-level up-scaling.
55  *
56  * Capabilities and Limitations:
57  *
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.
62  *
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).
66  *
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.
69  *    These ranges are:
70  *
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]
74  *
75  * Default Input Traits, and Output Traits:
76  *
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
87  *
88  *    Above, a "*" by an item indicates it must be valid (not negative).
89  *
90  *
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)
95  *
96 \******************************************************************************/
97
98 #include "string.h"    /* for memset and memcpy */
99 #include "assert.h"
100
101 #include "hpip.h"
102 #include "ipdefs.h"
103
104
105 #if 0
106     #include "stdio.h"
107     #include <tchar.h>
108
109     #define PRINT(msg,arg1,arg2) \
110         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
111 #else
112     #define PRINT(msg,arg1,arg2)
113 #endif
114
115 #define CHECK_VALUE 0x1ce5ca7e
116 #define SC_WHITE_ROW 1   /* was for tracking all-white rows; not used */
117
118
119 /*____________________________________________________________________________
120  |                                                                            |
121  | Things common to all image-types                                           |
122  |____________________________________________________________________________|
123 */
124
125
126 #define MAX_ROWS_AP     6   /* Number of entries in rows_ap */
127 #define HELD_ARRAY_SIZE 7   /* # entries in apHeldOutRows array */
128
129 typedef enum {
130     IM_BILEVEL,
131     IM_GRAY,
132     IM_COLOR
133 } IM_TYPE;
134
135
136 /* SC_INST contains all the variables for a scaling-instance */
137
138 typedef struct {
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             */
160
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             */
166
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;
172
173
174 /******************************************************************************
175  ******************************************************************************
176
177                            DUMMY BILEVEL FUNCTIONS
178
179  ******************************************************************************
180  ******************************************************************************/
181
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(). */
186
187 void bi_fast_open(PSC_INST g, UINT in_row_len) {
188     fatalBreakPoint();
189 }
190
191 void bi_scale_open(PSC_INST g, UINT in_row_len) {
192     fatalBreakPoint();
193 }
194
195 int bi_fast_row(PSC_INST g,PBYTE pbInputBuf,BYTE src_traits,
196     BYTE *apHeldOutRows[],ULONG *pdest_traits) {
197     fatalBreakPoint();
198     return 0;
199 }
200
201 int bi_scale_row(PSC_INST g,PBYTE pbInputBuf,BYTE src_traits,
202     BYTE *apHeldOutRows[],ULONG *pdest_traits) {
203     fatalBreakPoint();
204     return 0;
205 }
206
207 void bi_fast_close(PSC_INST g) {
208     fatalBreakPoint();
209 }
210
211 void bi_scale_close(PSC_INST g) {
212     fatalBreakPoint();
213 }
214
215
216 /******************************************************************************
217  ******************************************************************************
218
219                            CONTONE (GRAY AND COLOR)
220
221  ******************************************************************************
222  ******************************************************************************/
223
224
225 /*
226  * Scaling Algorithms
227  * 
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.
231  * 
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.
234  * 
235  * 
236  * Down-scaling Algorithm
237  * 
238  *   Imagine marking the pixel-boundaries on two rulers, and laying them
239  *   next to each other:
240  * 
241  *               in1 pos in2   in3
242  *      |______|______|______|______|______|______|______|  <-- input pixels
243  *      |           |           |           |           |   <-- output pixels
244  *                  0    out    1
245  * 
246  *   An output pixel consists of a weighted sum of the input pixels that
247  *   it overlaps.  The weights are the amount of overlap.
248  * 
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.
254  * 
255  *   The weights of the overlapping input pixels are:
256  * 
257  *      leftmost:                pos
258  *      middle pixels (if any):  scale factor (which is less than 1)
259  *      rightmost:               1.0 - (sum of above weights)
260  *
261  *   Above, the pixel 'out' is computed as:
262  *
263  *      out = pos*in1 + scalefactor*in2 + (1-pos-scalefactor)*in3
264  * 
265  * 
266  * Up-scaling Algorithm
267  * 
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.
273  * 
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.
279  * 
280  *                  0    in0    1    in1
281  *      |___________|___________|___________|___________|   <-- input_pixels
282  *      |      |      | out  |      |      |      |      |  <-- output pixels
283  *                   pos
284  * 
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).
287  * 
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.
290  * 
291  *   Above, the pixel 'out' is computed as:  out = (1-pos)*in0 + pos*in1
292  */
293
294 #define CONTONE_MIN_HORIZ_FAC  (ULONG)0x04000   /* 0.25 */
295    /* Minimum horizontal scale-factor (16.16) */
296
297 #define CONTONE_MAX_HORIZ_FAC  ((ULONG)MAX_ROWS_AP << 16)
298    /* Maximum horizontal scale-factor (arbitrary) */
299
300 #define CONTONE_MIN_VERT_FAC   (ULONG)0x04000   /* 0.25 */
301    /* Minimum vertical scale-factor (16.16) */
302
303 #define CONTONE_MAX_VERT_FAC   ((ULONG)MAX_ROWS_AP << 16)
304    /* Maximum vertical scale-factor (16.16) */
305
306
307
308 /*____________________________________________________________________________
309  |                  |                                                         |
310  | gray_horiz_scale | Scales the given input row into the given output row    |
311  |__________________|_________________________________________________________|
312  |                                                                            |
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  |____________________________________________________________________________|
317 */
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 */
322 {
323     ULONG horiz_pos, new_pos;
324     BYTE *in_p, *out_p, *out_aft_p;
325     UINT  sum, pix;
326     UINT  w1, w2;
327     UINT  n_pix, u;
328
329     in_p      = src_p;
330     out_p     = dest_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 */
333
334       /**************/
335      /* Up-scaling */
336     /**************/
337
338     if (g->horiz_fac >= 0x00010000u)
339     {
340         horiz_pos = 0;
341
342         while (out_p < out_aft_p) {
343             do {
344                 w2 = (UINT) (horiz_pos >> 8);
345                 w1 = 256 - w2;
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);
349
350             horiz_pos &= 0x0000ffffu;
351             in_p += 1;
352         }
353     }
354
355       /****************/
356      /* Down-scaling */
357     /****************/
358
359     else if (g->fast)
360     {
361         horiz_pos = 0;
362         while (out_p < out_aft_p) {
363             *out_p++ = *in_p;
364             horiz_pos += g->inv_horiz_fac;
365             in_p += horiz_pos >> 16;
366             horiz_pos &= 0x0000ffffu;
367         }
368     }
369     else   // not fast
370     {
371         horiz_pos = g->horiz_fac;
372         w2 = g->horiz_fac >> 8;
373
374         while (out_p < out_aft_p) {
375             new_pos = horiz_pos;
376             n_pix = 1;
377             do {
378                 new_pos += g->horiz_fac;
379                 n_pix += 1;
380             } while ((new_pos>>16) == 0);
381
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)
386              */
387             sum = horiz_pos >> 8;
388             pix = sum * (*in_p++);        /* 1st pixel */
389
390             for (u=1; u<=n_pix-2; u++) {
391                 pix += w2 * (*in_p++);    /* middle pixels */
392                 sum += w2;
393             }
394
395             pix += (256-sum) * (*in_p);   /* final pixel */
396
397             *out_p++ = pix >> 8;
398             horiz_pos = new_pos & 0x0000ffffu;
399         }
400     } /* end if up-scaling else down-scaling */
401 }
402
403
404
405 /*____________________________________________________________________________
406  |                   |                                                        |
407  | color_horiz_scale | Scales the given input row into the given output row   |
408  |___________________|________________________________________________________|
409  |                                                                            |
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  |____________________________________________________________________________|
414 */
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 */
419 {
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;
423     UINT  w1, w2;
424     UINT  n_pix, u;
425
426     in_p      = src_p;
427     out_p     = dest_p;
428     out_aft_p = out_p + g->out_row_nbytes;
429
430     p = in_p + g->in_row_nbytes;
431     p[0] = p[-3];  /* dup right pixel */
432     p[1] = p[-2];
433     p[2] = p[-1];
434
435       /**************/
436      /* Up-scaling */
437     /**************/
438
439     if (g->horiz_fac >= 0x00010000u)
440     {
441         horiz_pos = 0;
442
443         while (out_p < out_aft_p) {
444             do {
445                 w2 = (UINT) (horiz_pos >> 8);
446                 w1 = 256 - w2;
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);
452
453             horiz_pos &= 0x0000ffffu;
454             in_p += 3;
455         }
456     }
457
458       /****************/
459      /* Down-scaling */
460     /****************/
461
462     else if (g->fast)
463     {
464         int iStep;
465         horiz_pos = 0;
466         while (out_p < out_aft_p) {
467             *out_p++ = in_p[0];
468             *out_p++ = in_p[1];
469             *out_p++ = in_p[2];
470
471             horiz_pos += g->inv_horiz_fac;
472             iStep = horiz_pos >> 16;
473             in_p += iStep + iStep + iStep;
474             horiz_pos &= 0x0000ffffu;
475         }
476     }
477     else  // down-scaling, not fast
478     {
479         horiz_pos = g->horiz_fac;
480         w2 = g->horiz_fac >> 8;
481
482         while (out_p < out_aft_p) {
483             new_pos = horiz_pos;
484             n_pix = 1;
485             do {
486                 new_pos += g->horiz_fac;
487                 n_pix += 1;
488             } while ((new_pos>>16) == 0);
489
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)
494              */
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++);
499
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++);
504                 sum += w2;
505             }
506
507             sum = 256 - sum;
508             pix_y += sum * in_p[0];   /* final pixel */
509             pix_u += sum * in_p[1];
510             pix_v += sum * in_p[2];
511
512             *out_p++ = pix_y >> 8;
513             *out_p++ = pix_u >> 8;
514             *out_p++ = pix_v >> 8;
515             horiz_pos = new_pos & 0x0000ffffu;
516         }
517     } /* end if up-scaling else down-scaling */
518 }
519
520
521
522 /*____________________________________________________________________________
523  |                 |                                                          |
524  | weight_two_rows | Output row is a weighted-average of two rows in rows_ap  |
525  |_________________|__________________________________________________________|
526  |                                                                            |
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  |____________________________________________________________________________|
531 */
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 */
536 {
537     BYTE *p1, *p2;
538     BYTE *out_p, *out_aft_p;
539
540     p1 = g->rows_ap[0];
541     p2 = g->rows_ap[1];
542     out_p = dest_p;
543     out_aft_p = out_p + g->out_row_nbytes;
544
545 #if 0
546     UINT w1, w2;
547     w1 = first_weight >> 8;
548     w2 = 256 - w1;
549     while (out_p < out_aft_p)
550         *out_p++ = (w1*(*p1++) + w2*(*p2++)) >> 8;
551 #else
552     switch ((first_weight+(1u<<12)) >> 13)   /* round weight to closest 8th */
553     {
554         case 0:
555             memcpy (out_p, p2, g->out_row_nbytes);
556             break;
557         case 1:
558             while (out_p < out_aft_p)
559                 *out_p++ = (*p1>>3) + *p2 - (*p2>>3);
560                 p1++; p2++;
561             break;
562         case 2:
563             while (out_p < out_aft_p)
564                 *out_p++ = (*p1>>2) + *p2 - (*p2>>2);
565                 p1++; p2++;
566             break;
567         case 3:
568             while (out_p < out_aft_p)
569                 *out_p++ = (*p1>>2) + (*p1>>3) + (*p2>>1) + (*p2>>3);
570                 p1++; p2++;
571             break;
572         case 4:
573             while (out_p < out_aft_p)
574                 *out_p++ = (*p1>>1) + (*p2>>1);
575                 p1++; p2++;
576             break;
577         case 5:
578             while (out_p < out_aft_p)
579                 *out_p++ = (*p1>>1) + (*p1>>3) + (*p2>>2) + (*p2>>3);
580                 p1++; p2++;
581             break;
582         case 6:
583             while (out_p < out_aft_p)
584                 *out_p++ = *p1 - (*p1>>2) + (*p2>>2);
585                 p1++; p2++;
586             break;
587         case 7:
588             while (out_p < out_aft_p)
589                 *out_p++ = *p1 - (*p1>>3) + (*p2>>3);
590                 p1++; p2++;
591             break;
592         case 8:
593             memcpy (out_p, p1, g->out_row_nbytes);
594             break;
595         default:
596             assert (0);
597     }
598 #endif
599 }
600
601
602
603 /*____________________________________________________________________________
604  |               |                                                            |
605  | weight_n_rows | Blends two or more rows in rows_ap into one output row     |
606  |_______________|____________________________________________________________|
607  |                                                                            |
608  | The weights are:                                                           |
609  |     1st row:     first_weight                                              |
610  |     middle rows: mid_weight                                                |
611  |     final row:   1.0 - (sum of above weights)                              |
612  |____________________________________________________________________________|
613 */
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 */
620 {
621     BYTE *in_p[MAX_ROWS_AP];
622     BYTE *out_p, *out_aft_p;
623     UINT  weights[MAX_ROWS_AP];
624     UINT  sum;
625     UINT  u;
626
627     assert (n_rows>=2 && n_rows<=MAX_ROWS_AP);
628
629     if (n_rows == 2) {
630         weight_two_rows (g, first_weight, dest_p);
631         return;
632     }
633
634     out_p = 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];
638
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;
643
644     while (out_p < out_aft_p) {
645         sum = 0;
646         for (u=0; u<n_rows; u++)
647             sum += weights[u] * (*in_p[u]++);
648         *out_p++ = sum >> 8;
649     }
650 }
651
652
653
654 /*____________________________________________________________________________
655  |                    |                                                       |
656  | contone_scale_open | sets up the given scaling job                         |
657  |____________________|_______________________________________________________|
658 */
659 static void contone_scale_open (
660     SC_INST *g,            /* ptr to our scaling instance             */
661     UINT     in_row_len)   /* # pixels per input row                  */
662 {
663     ULONG horiz_fac;  /* scale-factors in 16.16 fixed-point */
664     ULONG vert_fac;
665     UINT  n;
666
667     horiz_fac = g->horiz_fac;
668     vert_fac  = g->vert_fac;
669
670     if (! g->fast) {
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);
675     }
676
677     g->vert_pos       = 0;
678     g->in_row_nbytes  = in_row_len;
679     g->out_row_pixels = g->out_row_nbytes = (horiz_fac*in_row_len) >> 16;
680
681     if (g->image_type == IM_COLOR) {
682         g->in_row_nbytes  *= 3;
683         g->out_row_nbytes *= 3;
684     }
685
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 */
689
690     if (g->fast) {
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;
698     }
699
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);
703     }
704
705     g->nMoreFlush = 0;   /* no flush-calls are needed */
706     return;
707
708     fatal_error:
709     assert (0);
710 }
711
712
713
714 /*____________________________________________________________________________
715  |                     |                                                      |
716  | contone_scale_close | de-allocates scaling instance                        |
717  |_____________________|______________________________________________________|
718 */
719 static void contone_scale_close (SC_INST *g)
720 {
721     UINT n;
722
723     for (n=0; n<g->n_alloced_rows; n++)
724         IP_MEM_FREE (g->rows_ap[n]);
725 }
726
727
728
729 /*____________________________________________________________________________
730  |                   |                                                        |
731  | contone_scale_row | scales the given input row into 0 or more output rows  |
732  |___________________|________________________________________________________|
733 */
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                        */
738 {
739     UINT  n_out_rows;
740     UINT  u;
741     long  weight;
742     long  new_pos;
743     BYTE *p;
744
745     assert (src_row_p != NULL);
746
747     if (g->fast && g->vert_fac<=0x00010000u)
748     {
749         /* down-scaling fast */
750         g->vert_pos += g->vert_fac;
751         n_out_rows = g->vert_pos >> 16;
752         g->vert_pos &= 0x0000ffffu;
753
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]);
757         }
758
759         return n_out_rows;
760     }
761
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);
765
766     g->n_saved_rows += 1;
767
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);
771     }
772
773       /*************************/
774      /* Up-scaling Vertically */
775     /*************************/
776
777     if (g->vert_fac >= 0x00010000u)
778     {
779         n_out_rows = 0;
780
781         if (g->n_saved_rows == 2) {
782 #if 0
783             do {
784                 weight_two_rows (g, 0x10000u-g->vert_pos,
785                                  dest_rows_ap[n_out_rows]);
786                 n_out_rows += 1;
787                 g->vert_pos += g->inv_vert_fac;
788             } while ((g->vert_pos>>16) == 0);
789             g->vert_pos &= 0x0000ffffu;
790 #else
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.
797              */
798             g->vert_pos += g->vert_fac;
799             n_out_rows = (UINT)(g->vert_pos >> 16);
800             g->vert_pos &= 0x0000ffffu;
801
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;
808             }
809
810             g->inv_vert_pos -= 0x10000;
811 #endif
812             /* discard the oldest row */
813             g->n_saved_rows = 1;
814             p = g->rows_ap[0];
815             g->rows_ap[0] = g->rows_ap[1];
816             g->rows_ap[1] = p;
817         }
818     }
819
820       /***************************/
821      /* Down-scaling Vertically */
822     /***************************/
823
824     else
825     {
826         n_out_rows = 0;
827         new_pos = g->vert_pos + (g->n_saved_rows-1)*g->vert_fac;
828
829         if ((new_pos>>16) != 0) {
830             weight_n_rows (g, g->n_saved_rows, g->vert_pos, g->vert_fac,
831                            dest_rows_ap[0]);
832             n_out_rows = 1;
833             g->vert_pos = new_pos & 0x0000ffffu;
834
835             /* retain the newest row */
836             p = g->rows_ap[0];
837             g->rows_ap[0] = g->rows_ap[g->n_saved_rows-1];
838             g->rows_ap[g->n_saved_rows-1] = p;
839             g->n_saved_rows = 1;
840         }
841     }
842
843     return n_out_rows;
844 }
845
846
847
848 /******************************************************************************
849  ******************************************************************************
850
851                        E X P O R T E D   R O U T I N E S
852
853  ******************************************************************************
854  ******************************************************************************/
855
856
857
858 /*****************************************************************************\
859  *
860  * scale_openXform - Creates a new instance of the transformer
861  *
862  *****************************************************************************
863  *
864  * This returns a handle for the new instance to be passed into
865  * all subsequent calls.
866  *
867  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
868  *
869 \*****************************************************************************/
870
871 static WORD scale_openXform (
872     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
873 {
874     PSC_INST g;
875
876     INSURE (pXform != NULL);
877     IP_MEM_ALLOC (sizeof(SC_INST), g);
878     *pXform = g;
879     memset (g, 0, sizeof(SC_INST));
880     g->dwValidChk = CHECK_VALUE;
881     return IP_DONE;
882
883     fatal_error:
884     return IP_FATAL_ERROR;
885 }
886
887
888
889 /*****************************************************************************\
890  *
891  * scale_setDefaultInputTraits - Specifies default input image traits
892  *
893  *****************************************************************************
894  *
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
898  * this routine.
899  *
900  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
901  *
902 \*****************************************************************************/
903
904 static WORD scale_setDefaultInputTraits (
905     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
906     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
907 {
908     PSC_INST g;
909
910     HANDLE_TO_PTR (hXform, g);
911
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);
917
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;
922     }
923
924     /* We don't actually support IM_BILEVEL currently. */
925     INSURE(g->image_type != IM_BILEVEL);
926
927     g->inTraits = *pTraits;   /* a structure copy */
928     return IP_DONE;
929
930     fatal_error:
931     return IP_FATAL_ERROR;
932 }
933
934
935
936 /*****************************************************************************\
937  *
938  * scale_setXformSpec - Provides xform-specific information
939  *
940 \*****************************************************************************/
941
942 static WORD scale_setXformSpec (
943     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
944     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
945 {
946     PSC_INST g;
947     HANDLE_TO_PTR (hXform, g);
948
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;
952     return IP_DONE;
953
954     fatal_error:
955     return IP_FATAL_ERROR;
956 }
957
958
959
960 /*****************************************************************************\
961  *
962  * scale_getHeaderBufSize- Returns size of input buf needed to hold header
963  *
964 \*****************************************************************************/
965
966 static WORD scale_getHeaderBufSize (
967     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
968     DWORD           *pdwInBufLen)     /* out: buf size for parsing header */
969 {
970     /* since input is raw pixels, there is no header, so set it to zero */
971     *pdwInBufLen = 0;
972     return IP_DONE;
973 }
974
975
976
977 /*****************************************************************************\
978  *
979  * scale_getActualTraits - Parses header, and returns input & output traits
980  *
981 \*****************************************************************************/
982
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 */
991 {
992     PSC_INST g;
993     int      i;
994     UINT     in_row_len;
995
996     HANDLE_TO_PTR (hXform, g);
997
998     /**** Since there is no header, we'll report no usage of input ****/
999
1000     *pdwInputUsed    = 0;
1001     *pdwInputNextPos = 0;
1002
1003     /**** Open the particular type of scaler we'll need ****/
1004
1005     in_row_len = g->inTraits.iPixelsPerRow;
1006
1007     switch (g->image_type) {
1008         case IM_BILEVEL:
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);
1013             break;
1014
1015         case IM_GRAY:
1016         case IM_COLOR:
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);
1020             break;
1021     }
1022
1023     /**** Allocate the held output rows ****/
1024
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]);
1029
1030     /**** Report back input- and output-traits ****/
1031
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);
1040     }
1041
1042     return IP_DONE | IP_READY_FOR_DATA;
1043
1044     fatal_error:
1045     return IP_FATAL_ERROR;
1046 }
1047
1048
1049
1050 /****************************************************************************\
1051  *
1052  * scale_getActualBufSizes - Returns buf sizes needed for remainder of job
1053  *
1054 \****************************************************************************/
1055
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 */
1060 {
1061     PSC_INST g;
1062
1063     HANDLE_TO_PTR (hXform, g);
1064     *pdwMinInBufLen  = g->in_row_nbytes;
1065     *pdwMinOutBufLen = g->out_row_nbytes;
1066
1067     return IP_DONE;
1068
1069     fatal_error:
1070     return IP_FATAL_ERROR;
1071 }
1072
1073
1074
1075 /*****************************************************************************\
1076  *
1077  * scale_convert - Converts one row
1078  *
1079 \*****************************************************************************/
1080
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 */
1091 {
1092     PSC_INST g;
1093     BYTE     src_traits;
1094     ULONG    dest_traits;
1095     int      inUsed, outUsed;
1096     int      n_rows;
1097     WORD     wResults;
1098
1099     HANDLE_TO_PTR (hXform, g);
1100     inUsed  = 0;
1101     outUsed = 0;
1102
1103     /**** Return next stored output-row, if any ****/
1104
1105     if (g->nMoreHeldOutRows > 0) {
1106         memcpy (pbOutputBuf,
1107                 g->apHeldOutRows[g->iNextHeldOutRow],
1108                 g->out_row_nbytes);
1109         g->nMoreHeldOutRows -= 1;
1110         g->iNextHeldOutRow  += 1;
1111         outUsed = g->out_row_nbytes;
1112         goto finish;
1113     }
1114
1115     /**** Check if we were told to flush ****/
1116
1117     if (pbInputBuf == NULL) {
1118         PRINT (_T("scale_convert: Told to flush.\n"), 0, 0);
1119         if (g->nMoreFlush == 0)
1120             goto finish;
1121         g->nMoreFlush -= 1;
1122         /* do "scale a row" section below, with pbInputBuf equal to NULL */
1123     } else
1124         inUsed = g->in_row_nbytes;
1125
1126     /**** Scale a Row ****/
1127
1128     g->apHeldOutRows[0] = pbOutputBuf;   /* 1st out-row is client's buffer */
1129     n_rows = 0;                          /* init to avoid compiler warning */
1130     src_traits = 0;
1131
1132     switch (g->image_type) {
1133         case IM_BILEVEL:
1134             if (g->fast)
1135                 n_rows = bi_fast_row (g, pbInputBuf, src_traits,
1136                                       g->apHeldOutRows, &dest_traits);
1137             else
1138                 n_rows = bi_scale_row (g, pbInputBuf, src_traits,
1139                                        g->apHeldOutRows, &dest_traits);
1140             break;
1141
1142         case IM_GRAY:
1143         case IM_COLOR:
1144             n_rows = contone_scale_row (g, pbInputBuf, g->apHeldOutRows);
1145             break;
1146     }
1147
1148     INSURE (n_rows <= g->nMaxOutRows);
1149     if (n_rows > 0) {
1150         g->nMoreHeldOutRows = n_rows - 1;
1151         g->iNextHeldOutRow = 1;
1152         outUsed = g->out_row_nbytes;
1153     }
1154
1155     /**** Report results and return (inUsed and outUsed are valid here) ****/
1156
1157     finish:
1158
1159     *pdwInputUsed     = (DWORD)inUsed;
1160     g->dwInNextPos   += (DWORD)inUsed;
1161     *pdwInputNextPos  = g->dwInNextPos;
1162
1163     *pdwOutputUsed    = (DWORD)outUsed;
1164     *pdwOutputThisPos = g->dwOutNextPos;
1165     g->dwOutNextPos  += (DWORD)outUsed;
1166
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 &&
1171                 g->nMoreFlush==0 &&
1172                 g->nMoreHeldOutRows==0 ? IP_DONE           : 0);
1173     return wResults;
1174
1175     fatal_error:
1176     return IP_FATAL_ERROR;
1177 }
1178
1179
1180
1181 /*****************************************************************************\
1182  *
1183  * scale_insertedData - client inserted into our output stream
1184  *
1185 \*****************************************************************************/
1186
1187 static WORD scale_insertedData (
1188     IP_XFORM_HANDLE hXform,
1189     DWORD           dwNumBytes)
1190 {
1191     fatalBreakPoint ();
1192     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
1193 }
1194
1195
1196
1197 /*****************************************************************************\
1198  *
1199  * scale_newPage - Tells us to flush this page, and start a new page
1200  *
1201 \*****************************************************************************/
1202
1203 static WORD scale_newPage (
1204     IP_XFORM_HANDLE hXform)
1205 {
1206     PSC_INST g;
1207
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 */
1211
1212     fatal_error:
1213     return IP_FATAL_ERROR;
1214
1215 }
1216
1217
1218
1219 /*****************************************************************************\
1220  *
1221  * scale_closeXform - Destroys this instance
1222  *
1223 \*****************************************************************************/
1224
1225 static WORD scale_closeXform (IP_XFORM_HANDLE hXform)
1226 {
1227     PSC_INST g;
1228     int      i;
1229
1230     HANDLE_TO_PTR (hXform, g);
1231
1232     switch (g->image_type) {
1233         case IM_BILEVEL:
1234             if (g->fast) bi_fast_close  (g);
1235             else         bi_scale_close (g);
1236             break;
1237
1238         case IM_GRAY:
1239         case IM_COLOR:
1240             contone_scale_close (g);
1241             break;
1242     }
1243
1244     for (i=1; i<g->nMaxOutRows; i++)
1245         IP_MEM_FREE (g->apHeldOutRows[i]);
1246     
1247     g->dwValidChk = 0;
1248     IP_MEM_FREE (g);       /* free memory for the instance */
1249
1250     return IP_DONE;
1251
1252     fatal_error:
1253     return IP_FATAL_ERROR;
1254 }
1255
1256
1257
1258 /*****************************************************************************\
1259  *
1260  * scaleTbl - Jump-table for scaler
1261  *
1262 \*****************************************************************************/
1263
1264 IP_XFORM_TBL scaleTbl = {
1265     scale_openXform,
1266     scale_setDefaultInputTraits,
1267     scale_setXformSpec,
1268     scale_getHeaderBufSize,
1269     scale_getActualTraits,
1270     scale_getActualBufSizes,
1271     scale_convert,
1272     scale_newPage,
1273     scale_insertedData,
1274     scale_closeXform
1275 };
1276
1277 /* End of File */