Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xgamma.c
1 /* libhpojip -- HP OfficeJet image-processing library. */
2
3 /* Copyright (C) 1995-2002 Hewlett-Packard Company
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
12  * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
13  * NON-INFRINGEMENT.  See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18  * MA 02111-1307, USA.
19  *
20  * In addition, as a special exception, Hewlett-Packard Company
21  * gives permission to link the code of this program with any
22  * version of the OpenSSL library which is distributed under a
23  * license identical to that listed in the included LICENSE.OpenSSL
24  * file, and distribute linked combinations including the two.
25  * You must obey the GNU General Public License in all respects
26  * for all of the code used other than OpenSSL.  If you modify
27  * this file, you may extend this exception to your version of the
28  * file, but you are not obligated to do so.  If you do not wish to
29  * do so, delete this exception statement from your version.
30  */
31
32 /* Original author: Mark Overton and others.
33  *
34  * Ported to Linux by David Paschal.
35  */
36
37 /******************************************************************************\
38  *
39  * xgamma.c - Applies Gamma transform
40  *
41  ******************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    gammaTbl
46  *
47  * Items in aXformInfo array passed into setXformSpec:
48  *
49  *    aXformInfo[0] = gamma value, in 16.16 fixed point
50  *
51  * Capabilities and Limitations:
52  *
53  *    Gamma values must range between 0.0 and 3.5.
54  *    Only operates on 8-bit grayscale data.
55  *    Uses cubic splines for speed.
56  *
57  * Default Input Traits, and Output Traits:
58  *
59  *          trait             default input             output
60  *    -------------------  ---------------------  ------------------------
61  *    iPixelsPerRow         * passed into output   same as default input
62  *    iBitsPerPixel         * must be 8            8
63  *    iComponentsPerPixel   * must be 1            1
64  *    lHorizDPI               passed into output   same as default input
65  *    lVertDPI                passed into output   same as default input
66  *    lNumRows                passed into output   same as default input
67  *    iNumPages               passed into output   same as default input
68  *    iPageNum                passed into output   same as default input
69  *
70  *    Above, a "*" by an item indicates it must be valid (not negative).
71  *
72  * Feb   1998 Mark Overton -- ported code to software
73  * early 1997 Mark Overton -- wrote original code for Kodiak firmware
74  *
75 \******************************************************************************/
76
77 #include "hpip.h"
78 #include "ipdefs.h"
79 #include "string.h"    /* for memset and memcpy */
80
81
82 #if 0
83     #include "stdio.h"
84     #define PRINT(msg,arg1,arg2) \
85         fprintf(stderr, msg, (int)arg1, (int)arg2)
86 #else
87     #define PRINT(msg,arg1,arg2)
88 #endif
89
90 #define CHECK_VALUE 0x4ba1dace
91
92
93 typedef struct {
94     IP_IMAGE_TRAITS traits;   /* traits of the input image */
95     BYTE     gammaTable[256]; /* the gamma table */
96     WORD     wRowsDone;       /* number of rows converted so far */
97     DWORD    dwInNextPos;     /* file pos for subsequent input */
98     DWORD    dwOutNextPos;    /* file pos for subsequent output */
99     DWORD    dwValidChk;      /* struct validity check value */
100 } GAM_INST, *PGAM_INST;
101
102
103
104
105 /*____________________________________________________________________________
106  |                   |                                                        |
107  | fast_sin fast_cos | fast sine and cosine functions                         |
108  |___________________|________________________________________________________|
109  |                                                                            |
110  | Input:    Units of angle is fraction of circle (e.g., 1.0 is 360 deg).     |
111  |           Format is 0.32 fixed-point (i.e., 32 bits of fraction).          |
112  |                                                                            |
113  | Returns:  Sine or cosine expressed as 16.16 signed fixed-point.            |
114  |                                                                            |
115  | Accuracy: Max error is 0.000054 (i.e., 14 good bits of fraction).          |
116  |____________________________________________________________________________|
117 */
118 static long fast_sin (ULONG ang)
119 {
120     ULONG ang31, ang30, delta_ang, result;
121     UINT  index, base, next;
122
123     /* 90 deg is divided into this many intervals */
124     #define INDEX_BITS      6
125     #define N_INTERVALS     (1<<INDEX_BITS)
126     #define HALF_WORST_ERR  3
127
128     static const USHORT sin_table[N_INTERVALS+2] = {
129             0,  1608,  3216,  4821,  6424,  8022,  9616, 11204,
130         12785, 14359, 15924, 17479, 19024, 20557, 22078, 23586,
131         25080, 26558, 28020, 29466, 30893, 32303, 33692, 35062,
132         36410, 37736, 39040, 40320, 41576, 42806, 44011, 45190,
133         46341, 47464, 48559, 49624, 50660, 51665, 52639, 53581,
134         54491, 55368, 56212, 57022, 57798, 58538, 59244, 59914,
135         60547, 61145, 61705, 62228, 62714, 63162, 63572, 63944,
136         64277, 64571, 64827, 65043, 65220, 65358, 65457, 65516,
137         65535, 65535  /* <-- these should be 65536 (won't fit in 16 bits) */
138     };
139
140     /* zero the msb (representing 180 deg), leaving 31 bits */
141     ang31 = (ang << 1) >> 1;
142
143     /* fold angle to first quadrant, leaving 30 bits */
144     ang30 = ang31;
145     if (ang30 >= 0x40000000u)
146         ang30 = 0x80000000u - ang30;   /* sin(180-a) = sin(a) */
147
148     index = ang30 >> (30-INDEX_BITS);
149     base = sin_table [index];
150     next = sin_table [index+1];
151     delta_ang = ang30>>(14-INDEX_BITS) & 0x0000ffffu;
152     result = ((next-base)*delta_ang >> 16) + base + HALF_WORST_ERR;
153
154     /* negate result if 180-bit was set in original angle */
155     if ((long)ang < 0)
156         result = (ULONG)(-(long)result);
157
158     return (long)result;
159
160     #undef INDEX_BITS
161     #undef N_INTERVALS
162     #undef HALF_WORST_ERR
163 }
164
165
166 static /* inline */ int fast_cos (UINT ang)
167 {
168     return fast_sin(0x40000000u-ang);
169 }
170
171
172 #if 0
173
174 #include <stdio.h>
175 #include <math.h>
176
177 void main (void)
178 {
179     int i;
180     float err, max_err;
181
182     max_err = 0.0;
183
184     for (i=0; i<=16*65536; i++) {
185         err = sin ((float)i * (2.0*3.1415926535897932384626/(16*65536.0)))
186                 - fast_sin(i<<12)/65536.0;
187         if (err < 0) err = -err;
188         if (err > max_err) max_err = err;
189     }
190
191     printf ("max err = %f\n", max_err);
192 }
193
194 #endif
195
196
197 #if 0
198
199 #include <stdio.h>
200 #include <math.h>
201
202 void main (void)
203 {
204     int i;
205     float s;
206
207     for (i=0; i<=64; i++) {
208         s = sin ((float)i * (3.1415926535897932384626/(2.0*64.0)));
209         printf ("%5d, ", (int)(s*(1<<16) + 0.5));
210         if (i%8 == 7) puts("");
211     }
212 }
213
214 #endif
215
216
217
218 typedef struct {
219     long a, b, c;   /* x = at + bt^2 + ct^3 */
220     long d, e, f;   /* y = dt + et^2 + ft^3 */
221 } cubic_t;
222
223
224
225 /*____________________________________________________________________________
226  |                   |                                                        |
227  | calc_cubic_coeffs | calcs coefficients given start/end angles/velocities   |
228  |___________________|________________________________________________________|
229  |                                                                            |
230  | Units of angle is fraction of circle (e.g., 1.0 is 360 deg).               |
231  | Format is 0.32 fixed-point (i.e., 32 bits of fraction).                    |
232  |____________________________________________________________________________|
233 */
234 static void calc_cubic_coeffs (
235     ULONG    start_ang,
236     ULONG    final_ang, 
237     long     start_vel,   /* velocities are in 16.16 fixed point */
238     long     final_vel,
239     cubic_t *p)
240 {
241     long start_x, start_y, final_x, final_y;
242
243     /* For both start and final below:  vel = vel * 2.0 / (1.0 + cos(ang)),
244      * where vel is 16.16 before calc, and is 20.12 after the calc below.
245      */
246     start_vel = (start_vel<<11) / ((1lu<<14) + (fast_cos(start_ang)>>2));
247     final_vel = (final_vel<<11) / ((1lu<<14) + (fast_cos(final_ang)>>2));
248
249     /* Below:   (vel is 20.12) * (cos>>2 is 18.14) yields a 6.26;
250      *          the >>10 changes 6.26 into a 16.16.
251      */
252     start_x = start_vel*(fast_cos(start_ang)>>2) >> 10;
253     start_y = start_vel*(fast_sin(start_ang)>>2) >> 10;
254     final_x = final_vel*(fast_cos(final_ang)>>2) >> 10;
255     final_y = final_vel*(fast_sin(final_ang)>>2) >> 10;
256
257     p->a = start_x;
258     p->d = start_y;
259     p->b = (3<<16) - 2*start_x - final_x;
260     p->e = -2*start_y - final_y;
261     p->c = start_x + final_x - (2<<16);
262     p->f = start_y + final_y;
263 }
264
265
266
267 /*____________________________________________________________________________
268  |                 |                                                          |
269  | transform_cubic | makes cubic end at (x_end,y_end) instead of (1,0)        |
270  |_________________|__________________________________________________________|
271 */
272 static void transform_cubic (
273     int      x_end,
274     int      y_end,
275     cubic_t *p)
276 {
277     cubic_t q;
278
279     q.a = p->a*x_end - p->d*y_end;
280     q.b = p->b*x_end - p->e*y_end;
281     q.c = p->c*x_end - p->f*y_end;
282
283     q.d = p->a*y_end + p->d*x_end;
284     q.e = p->b*y_end + p->e*x_end;
285     q.f = p->c*y_end + p->f*x_end;
286
287     *p = q;
288 }
289
290
291
292 /*____________________________________________________________________________
293  |                        |                                                   |
294  | calc_gamma_from_coeffs | calcs gamma table, given the coefficients         |
295  |________________________|___________________________________________________|
296 */
297 static void calc_gamma_from_coeffs (
298     cubic_t *p,       /* in:  coefficients of cubic curve */
299     BYTE     tbl[])   /* out: array to receive the gamma table */
300 {
301     #define LG_N_INTERVALS 7   /* 7 is the max; 8 causes overflow */
302     #define N_INTERVALS    (1u<<LG_N_INTERVALS)
303     #define RND_PROD(p)    (((p) + ((1<<LG_N_INTERVALS)-1)) >> LG_N_INTERVALS)
304
305     int  t, x, y, xprev=0, yprev=0, xtmp, ytmp;
306
307     for (t=0; t<=N_INTERVALS; t+=1) {
308         x = (((RND_PROD((RND_PROD(p->c*t) + p->b)*t) + p->a)*t
309                 >> (LG_N_INTERVALS+15)) + 1) >> 1;
310         y = (((RND_PROD((RND_PROD(p->f*t) + p->e)*t) + p->d)*t
311                 >> (LG_N_INTERVALS+15)) + 1) >> 1;
312
313         if (t==0 || x!=xprev) tbl[x] = y;
314
315         if (t > 0) {
316             xtmp = xprev + 1;
317             ytmp = (yprev+y) / 2;
318             while (xtmp < x)
319                 tbl[xtmp++] = ytmp;
320         }
321
322         xprev = x;  yprev = y;
323     }
324 }
325
326
327
328 /*____________________________________________________________________________
329  |                  |                                                         |
330  | calc_gamma_table | calculates gamma table using a cubic curve              |
331  |__________________|_________________________________________________________|
332 */
333 static void calc_gamma_table (
334     long gamma,  /* in:  gamma value as 24.8 (0.7 .. 3.5 is useful range) */
335     BYTE tbl[])  /* out: array to receive the gamma table */
336 {
337     #define FLOAT_TO_FIX(f) ((short)((f)*0x1000 + 0.5))  /* output is 8.8 */
338     #define FLOAT_TO_ANG(f) ((USHORT)(long)((f)*0x10000/360.0 + 0.5))
339
340     #define MIN_INDEX 0  /* corresponds to gamma=0.0 */
341     #define MAX_INDEX 6  /* corresponds to gamma=3.0 */
342
343     typedef struct {  /* ang_base=0.16; all others are 4.12 */
344         short  start_vel_base;   short start_vel_slope;
345         USHORT start_ang_base;   short start_ang_slope;
346         short  final_vel_base;   short final_vel_slope;
347         USHORT final_ang_base;   short final_ang_slope;
348     } spec_t;
349
350     static const spec_t specs[MAX_INDEX-MIN_INDEX+1] = {
351         {   /* 0.0 .. 0.5  (just does a straight line) */
352             FLOAT_TO_FIX(1.0),   FLOAT_TO_FIX(0.0),          /* start vel */
353             FLOAT_TO_ANG(0.0),   FLOAT_TO_FIX(0.0),          /* start ang */
354             FLOAT_TO_FIX(1.0),   FLOAT_TO_FIX(0.0),          /* final vel */
355             FLOAT_TO_ANG(0.0),   FLOAT_TO_FIX(0.0),          /* final ang */
356         },
357         {   /* 0.5 .. 1.0 (bogus below about 0.7) */
358             FLOAT_TO_FIX(0.05),  FLOAT_TO_FIX(0.5),          /* start vel */
359             FLOAT_TO_ANG(-75.0), FLOAT_TO_FIX(150.0/360.0),  /* start ang */
360             FLOAT_TO_FIX(2.0),   FLOAT_TO_FIX(0.0),          /* final vel */
361             FLOAT_TO_ANG(15.0),  FLOAT_TO_FIX(-30.0/360.0),  /* final ang */
362         },
363         {   /* 1.0 .. 1.5 */
364             FLOAT_TO_FIX(0.3),   FLOAT_TO_FIX(0.2),          /* start vel */
365             FLOAT_TO_ANG(0.0),   FLOAT_TO_FIX(60.0/360.0),   /* start ang */
366             FLOAT_TO_FIX(2.0),   FLOAT_TO_FIX(0.0),          /* final vel */
367             FLOAT_TO_ANG(0.0),   FLOAT_TO_FIX(-20.0/360.0),  /* final ang */
368         },
369         {   /* 1.5 .. 2.0 */
370             FLOAT_TO_FIX(0.4),   FLOAT_TO_FIX(0.2),          /* start vel */
371             FLOAT_TO_ANG(30.0),  FLOAT_TO_FIX(20.0/360.0),   /* start ang */
372             FLOAT_TO_FIX(2.0),   FLOAT_TO_FIX(0.0),          /* final vel */
373             FLOAT_TO_ANG(-10.0), FLOAT_TO_FIX(-16.0/360.0),  /* final ang */
374         },
375         {   /* 2.0 .. 2.5 */
376             FLOAT_TO_FIX(0.5),   FLOAT_TO_FIX(0.3),          /* start vel */
377             FLOAT_TO_ANG(40.0),  FLOAT_TO_FIX(4.0/360.0),    /* start ang */
378             FLOAT_TO_FIX(2.0),   FLOAT_TO_FIX(0.0),          /* final vel */
379             FLOAT_TO_ANG(-18.0), FLOAT_TO_FIX(-8.0/360.0),   /* final ang */
380         },
381         {   /* 2.5 .. 3.0 */
382             FLOAT_TO_FIX(0.65),  FLOAT_TO_FIX(0.4),          /* start vel */
383             FLOAT_TO_ANG(42.0),  FLOAT_TO_FIX(4.0/360.0),    /* start ang */
384             FLOAT_TO_FIX(2.0),   FLOAT_TO_FIX(0.0),          /* final vel */
385             FLOAT_TO_ANG(-22.0), FLOAT_TO_FIX(-6.0/360.0),   /* final ang */
386         },
387         {   /* 3.0 .. 3.5 */
388             FLOAT_TO_FIX(0.85),  FLOAT_TO_FIX(0.5),          /* start vel */
389             FLOAT_TO_ANG(44.0),  FLOAT_TO_FIX(1.0/360.0),    /* start ang */
390             FLOAT_TO_FIX(2.0),   FLOAT_TO_FIX(0.0),          /* final vel */
391             FLOAT_TO_ANG(-25.0), FLOAT_TO_FIX(-4.0/360.0),   /* final ang */
392         },
393     };
394
395     #define BEGIN_BLACKS 0      /* # of 0's at beginning of gamma table */
396     #define END_WHITES   4      /* # of 255's at final of gamma table */
397
398     const spec_t *p;
399     long    start_vel, final_vel;
400     ULONG   start_ang, final_ang;
401     cubic_t cubic;
402     int     i;
403
404     i = gamma >> 7;
405     if (i > MAX_INDEX) i = MAX_INDEX;
406     p = &specs[i-MIN_INDEX];
407     gamma -= i << 7;
408
409     start_vel = ((long)p->start_vel_base << 4)
410                 + (p->start_vel_slope*gamma >> 4);
411     final_vel = ((long)p->final_vel_base << 4)
412                 + (p->final_vel_slope*gamma >> 4);
413     start_ang = ((long)p->start_ang_base << 16)
414                 + (p->start_ang_slope*gamma << 12);
415     final_ang = ((long)p->final_ang_base << 16)
416                 + (p->final_ang_slope*gamma << 12);
417
418     calc_cubic_coeffs (start_ang, final_ang, start_vel, final_vel, &cubic);
419     transform_cubic (255-BEGIN_BLACKS-END_WHITES, 254, &cubic);
420     calc_gamma_from_coeffs (&cubic, tbl);
421
422     memmove (&tbl[BEGIN_BLACKS], &tbl[0], (256-BEGIN_BLACKS)*sizeof(BYTE));
423     tbl[0] = 0;
424     for (i=0; i<BEGIN_BLACKS; i++)
425         tbl[i] = 0;
426
427     for (i=256-END_WHITES; i<=255; i++)
428         tbl[i] = 255;
429 }
430
431
432
433
434 /*****************************************************************************\
435  *
436  * gamma_openXform - Creates a new instance of the transformer
437  *
438  *****************************************************************************
439  *
440  * This returns a handle for the new instance to be passed into
441  * all subsequent calls.
442  *
443  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
444  *
445 \*****************************************************************************/
446
447 static WORD gamma_openXform (
448     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
449 {
450     PGAM_INST g;
451
452     INSURE (pXform != NULL);
453     IP_MEM_ALLOC (sizeof(GAM_INST), g);
454     *pXform = g;
455     memset (g, 0, sizeof(GAM_INST));
456     g->dwValidChk = CHECK_VALUE;
457     return IP_DONE;
458
459     fatal_error:
460     return IP_FATAL_ERROR;
461 }
462
463
464
465 /*****************************************************************************\
466  *
467  * gamma_setDefaultInputTraits - Specifies default input image traits
468  *
469  *****************************************************************************
470  *
471  * The header of the file-type handled by the transform probably does
472  * not include *all* the image traits we'd like to know.  Those not
473  * specified in the file-header are filled in from info provided by
474  * this routine.
475  *
476  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
477  *
478 \*****************************************************************************/
479
480 static WORD gamma_setDefaultInputTraits (
481     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
482     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
483 {
484     PGAM_INST g;
485
486     HANDLE_TO_PTR (hXform, g);
487
488     /* Insure that values we care about are correct */
489     INSURE (pTraits->iBitsPerPixel == 8);
490     INSURE (pTraits->iComponentsPerPixel == 1);
491     INSURE (pTraits->iPixelsPerRow > 0);
492
493     g->traits = *pTraits;   /* a structure copy */
494     return IP_DONE;
495
496     fatal_error:
497     return IP_FATAL_ERROR;
498 }
499
500
501
502 /*****************************************************************************\
503  *
504  * gamma_setXformSpec - Provides xform-specific information
505  *
506 \*****************************************************************************/
507
508 static WORD gamma_setXformSpec (
509     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
510     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
511 {
512     PGAM_INST g;
513     DWORD     gamma;
514
515     HANDLE_TO_PTR (hXform, g);
516     gamma = aXformInfo[0].dword;
517     INSURE (gamma <= 0x38000u);   /* 3.5 is our limit */
518
519     calc_gamma_table ((gamma+0x0080u)>>8, g->gammaTable);
520     /* todo: make calc_gamma_table accept a 16.16 gamma value */
521
522     return IP_DONE;
523
524     fatal_error:
525     return IP_FATAL_ERROR;
526 }
527
528
529
530 /*****************************************************************************\
531  *
532  * gamma_getHeaderBufSize- Returns size of input buf needed to hold header
533  *
534 \*****************************************************************************/
535
536 static WORD gamma_getHeaderBufSize (
537     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
538     DWORD           *pwInBufLen)     /* out: buf size for parsing header */
539 {
540     /* since input is raw pixels, there is no header, so set it to zero */
541     *pwInBufLen = 0;
542     return IP_DONE;
543 }
544
545
546
547 /*****************************************************************************\
548  *
549  * gamma_getActualTraits - Parses header, and returns input & output traits
550  *
551 \*****************************************************************************/
552
553 static WORD gamma_getActualTraits (
554     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
555     DWORD            wInputAvail,    /* in:  # avail bytes in input buf */
556     PBYTE            pbInputBuf,     /* in:  ptr to input buffer */
557     PDWORD           pwInputUsed,    /* out: # bytes used from input buf */
558     PDWORD           pdwInputNextPos,/* out: file-pos to read from next */
559     PIP_IMAGE_TRAITS pIntraits,      /* out: input image traits */
560     PIP_IMAGE_TRAITS pOutTraits)     /* out: output image traits */
561 {
562     PGAM_INST g;
563
564     HANDLE_TO_PTR (hXform, g);
565
566     /* Since there is no header, we'll report no usage of input */
567     *pwInputUsed = 0;
568     *pdwInputNextPos = 0;
569
570     *pIntraits  = g->traits;   /* structure copies */
571     *pOutTraits = g->traits;
572
573     return IP_DONE;
574
575     fatal_error:
576     return IP_FATAL_ERROR;
577 }
578
579
580
581 /****************************************************************************\
582  *
583  * gamma_getActualBufSizes - Returns buf sizes needed for remainder of job
584  *
585 \****************************************************************************/
586
587 static WORD gamma_getActualBufSizes (
588     IP_XFORM_HANDLE hXform,          /* in:  handle for xform */
589     PDWORD          pwMinInBufLen,   /* out: min input buf size */
590     PDWORD          pwMinOutBufLen)  /* out: min output buf size */
591 {
592     PGAM_INST g;
593
594     HANDLE_TO_PTR (hXform, g);
595     *pwMinInBufLen = *pwMinOutBufLen = g->traits.iPixelsPerRow;
596     return IP_DONE;
597
598     fatal_error:
599     return IP_FATAL_ERROR;
600 }
601
602
603
604 /*****************************************************************************\
605  *
606  * gamma_convert - Converts one row
607  *
608 \*****************************************************************************/
609
610 static WORD gamma_convert (
611     IP_XFORM_HANDLE hXform,
612     DWORD           wInputAvail,      /* in:  # avail bytes in in-buf */
613     PBYTE           pbInputBuf,       /* in:  ptr to in-buffer */
614     PDWORD          pwInputUsed,      /* out: # bytes used from in-buf */
615     PDWORD          pdwInputNextPos,  /* out: file-pos to read from next */
616     DWORD           wOutputAvail,     /* in:  # avail bytes in out-buf */
617     PBYTE           pbOutputBuf,      /* in:  ptr to out-buffer */
618     PDWORD          pwOutputUsed,     /* out: # bytes written in out-buf */
619     PDWORD          pdwOutputThisPos) /* out: file-pos to write the data */
620 {
621     PGAM_INST g;
622     int       nBytes;
623     PBYTE     pIn, pOut, pOutAfter;
624
625     HANDLE_TO_PTR (hXform, g);
626
627     /**** Check if we were told to flush ****/
628
629     if (pbInputBuf == NULL) {
630         PRINT ("gamma_convert: Told to flush.\n", 0, 0);
631         *pwInputUsed = *pwOutputUsed = 0;
632         *pdwInputNextPos  = g->dwInNextPos;
633         *pdwOutputThisPos = g->dwOutNextPos;
634         return IP_DONE;
635     }
636
637     /**** Output a Row ****/
638
639     nBytes = g->traits.iPixelsPerRow;
640     INSURE (wInputAvail  >= nBytes );
641     INSURE (wOutputAvail >= nBytes);
642
643     pIn  = pbInputBuf;
644     pOut = pbOutputBuf;
645     pOutAfter = pOut + nBytes;
646
647     while (pOut < pOutAfter) {
648         pOut[0] = g->gammaTable[pIn[0]];
649         pOut[1] = g->gammaTable[pIn[1]];
650         pOut[2] = g->gammaTable[pIn[2]];
651         pOut[3] = g->gammaTable[pIn[3]];
652         pOut[4] = g->gammaTable[pIn[4]];
653         pOut[5] = g->gammaTable[pIn[5]];
654         pOut[6] = g->gammaTable[pIn[6]];
655         pOut[7] = g->gammaTable[pIn[7]];
656
657         pIn  += 8;
658         pOut += 8;
659     }
660
661     *pwInputUsed      = nBytes;
662     g->dwInNextPos   += nBytes;
663     *pdwInputNextPos  = g->dwInNextPos;
664
665     *pwOutputUsed     = nBytes;
666     *pdwOutputThisPos = g->dwOutNextPos;
667     g->dwOutNextPos  += nBytes;
668
669     g->wRowsDone += 1;
670
671     PRINT ("gamma_convert: Returning, out used = %d\n", out_used, 0);
672     return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
673
674     fatal_error:
675     return IP_FATAL_ERROR;
676 }
677
678
679
680 /*****************************************************************************\
681  *
682  * gamma_insertedData - client inserted into our output stream
683  *
684 \*****************************************************************************/
685
686 static WORD gamma_insertedData (
687     IP_XFORM_HANDLE hXform,
688     DWORD           wNumBytes)
689 {
690     fatalBreakPoint ();
691     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
692 }
693
694
695
696 /*****************************************************************************\
697  *
698  * gamma_newPage - Tells us to flush this page, and start a new page
699  *
700 \*****************************************************************************/
701
702 static WORD gamma_newPage (
703     IP_XFORM_HANDLE hXform)
704 {
705     PGAM_INST g;
706
707     HANDLE_TO_PTR (hXform, g);
708     /* todo: return fatal error if convert is called again? */
709     return IP_DONE;   /* can't insert page-breaks, so ignore this call */
710
711     fatal_error:
712     return IP_FATAL_ERROR;
713
714 }
715
716
717
718 /*****************************************************************************\
719  *
720  * gamma_closeXform - Destroys this instance
721  *
722 \*****************************************************************************/
723
724 static WORD gamma_closeXform (IP_XFORM_HANDLE hXform)
725 {
726     PGAM_INST g;
727
728     HANDLE_TO_PTR (hXform, g);
729
730     g->dwValidChk = 0;
731     IP_MEM_FREE (g);       /* free memory for the instance */
732
733     return IP_DONE;
734
735     fatal_error:
736     return IP_FATAL_ERROR;
737 }
738
739
740
741 /*****************************************************************************\
742  *
743  * gammaTbl - Jump-table for transform driver
744  *
745 \*****************************************************************************/
746
747 IP_XFORM_TBL gammaTbl = {
748     gamma_openXform,
749     gamma_setDefaultInputTraits,
750     gamma_setXformSpec,
751     gamma_getHeaderBufSize,
752     gamma_getActualTraits,
753     gamma_getActualBufSizes,
754     gamma_convert,
755     gamma_newPage,
756     gamma_insertedData,
757     gamma_closeXform
758 };
759
760 /* End of File */