Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xtonemap.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  * xtonemap.c - Performs a 256-byte tonemap to grayscale or color data
40  *
41  ******************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    tonemapTbl
46  *
47  * Items in aXformInfo array passed into setXformSpec:
48  *
49  *    aXformInfo[IP_TONEMAP_POINTER] = pointer to the 256-byte tonemap.
50  *    aXformInfo[IP_TONEMAP_LUM_SPACE] = Is color-space luminance-based?
51  *          0: color space is RGB
52  *          1: color space has luminance as first byte (eg, YCC)
53  *
54  *    The tonemap is indexed by luminance (0..255), and returns the new
55  *    luminance.  For color data, the luminance is computed based on r-g-b,
56  *    and these are updated based on th new luminance.
57  *
58  *    An internal copy is made of the tonemap.
59  *
60  * Capabilities and Limitations:
61  *
62  *    The incoming data can be 8-bit gray or 24-bit color or 48-bit color.
63  *
64  * Default Input Traits, and Output Traits:
65  *
66  *          trait             default input             output
67  *    -------------------  ---------------------  ------------------------
68  *    iPixelsPerRow         * passed into output   same as default input
69  *    iBitsPerPixel         * passed into output   same as default input
70  *    iComponentsPerPixel     passed into output   same as default input
71  *    lHorizDPI               passed into output   same as default input
72  *    lVertDPI                passed into output   same as default input
73  *    lNumRows                passed into output   same as default input
74  *    iNumPages               passed into output   same as default input
75  *    iPageNum                passed into output   same as default input
76  *
77  *    Above, a "*" by an item indicates it must be valid (not negative).
78  *
79  * Jan 2000 Mark Overton -- wrote original code
80  *
81 \******************************************************************************/
82
83 #include "hpip.h"
84 #include "ipdefs.h"
85 #include "string.h"    /* for memset and memcpy */
86
87
88 #if 0
89     #include "stdio.h"
90     #include <tchar.h>
91
92     #define PRINT(msg,arg1,arg2) \
93         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
94 #else
95     #define PRINT(msg,arg1,arg2)
96 #endif
97
98 #define CHECK_VALUE 0x4ba1dace
99
100
101 typedef struct {
102     IP_IMAGE_TRAITS traits;   /* traits of the input and output image */
103     BOOL     bLumSpace;       /* luminance-based color space? (else RGB) */
104     BYTE     tonemap[256];    /* the tonemap */
105     DWORD    dwBytesPerRow;   /* # of bytes in each row */
106     DWORD    dwRowsDone;      /* number of rows converted so far */
107     DWORD    dwInNextPos;     /* file pos for subsequent input */
108     DWORD    dwOutNextPos;    /* file pos for subsequent output */
109     DWORD    dwValidChk;      /* struct validity check value */
110 } TMAP_INST, *PTMAP_INST;
111
112
113
114 /*****************************************************************************\
115  *
116  * tonemap_openXform - Creates a new instance of the transformer
117  *
118  *****************************************************************************
119  *
120  * This returns a handle for the new instance to be passed into
121  * all subsequent calls.
122  *
123  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
124  *
125 \*****************************************************************************/
126
127 static WORD tonemap_openXform (
128     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
129 {
130     PTMAP_INST g;
131
132     INSURE (pXform != NULL);
133     IP_MEM_ALLOC (sizeof(TMAP_INST), g);
134     *pXform = g;
135     memset (g, 0, sizeof(TMAP_INST));
136     g->dwValidChk = CHECK_VALUE;
137     return IP_DONE;
138
139     fatal_error:
140     return IP_FATAL_ERROR;
141 }
142
143
144
145 /*****************************************************************************\
146  *
147  * tonemap_setDefaultInputTraits - Specifies default input image traits
148  *
149  *****************************************************************************
150  *
151  * The header of the file-type handled by the transform probably does
152  * not include *all* the image traits we'd like to know.  Those not
153  * specified in the file-header are filled in from info provided by
154  * this routine.
155  *
156  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
157  *
158 \*****************************************************************************/
159
160 static WORD tonemap_setDefaultInputTraits (
161     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
162     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
163 {
164     PTMAP_INST g;
165
166     HANDLE_TO_PTR (hXform, g);
167
168     /* insure that traits we care about are known */
169     INSURE (pTraits->iPixelsPerRow>0 && pTraits->iBitsPerPixel>1);
170     g->traits = *pTraits;   /* a structure copy */
171     g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
172     return IP_DONE;
173
174     fatal_error:
175     return IP_FATAL_ERROR;
176 }
177
178
179
180 /*****************************************************************************\
181  *
182  * tonemap_setXformSpec - Provides xform-specific information
183  *
184 \*****************************************************************************/
185
186 static WORD tonemap_setXformSpec (
187     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
188     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
189 {
190     PTMAP_INST g;
191
192     HANDLE_TO_PTR (hXform, g);
193     memcpy (g->tonemap, aXformInfo[IP_TONEMAP_POINTER].pvoid, 256);
194     g->bLumSpace = aXformInfo[IP_TONEMAP_LUM_SPACE].dword;
195     return IP_DONE;
196
197     fatal_error:
198     return IP_FATAL_ERROR;
199 }
200
201
202
203 /*****************************************************************************\
204  *
205  * tonemap_getHeaderBufSize- Returns size of input buf needed to hold header
206  *
207 \*****************************************************************************/
208
209 static WORD tonemap_getHeaderBufSize (
210     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
211     DWORD           *pdwInBufLen)    /* out: buf size for parsing header */
212 {
213     /* since input is raw pixels, there is no header, so set it to zero */
214     *pdwInBufLen = 0;
215     return IP_DONE;
216 }
217
218
219
220 /*****************************************************************************\
221  *
222  * tonemap_getActualTraits - Parses header, and returns input & output traits
223  *
224 \*****************************************************************************/
225
226 static WORD tonemap_getActualTraits (
227     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
228     DWORD            dwInputAvail,   /* in:  # avail bytes in input buf */
229     PBYTE            pbInputBuf,     /* in:  ptr to input buffer */
230     PDWORD           pdwInputUsed,   /* out: # bytes used from input buf */
231     PDWORD           pdwInputNextPos,/* out: file-pos to read from next */
232     PIP_IMAGE_TRAITS pIntraits,      /* out: input image traits */
233     PIP_IMAGE_TRAITS pOutTraits)     /* out: output image traits */
234 {
235     PTMAP_INST g;
236
237     HANDLE_TO_PTR (hXform, g);
238
239     /* Since there is no header, we'll report no usage of input */
240     *pdwInputUsed    = 0;
241     *pdwInputNextPos = 0;
242
243     *pIntraits  = g->traits;   /* structure copies */
244     *pOutTraits = g->traits;
245
246     return IP_DONE | IP_READY_FOR_DATA;
247
248     fatal_error:
249     return IP_FATAL_ERROR;
250 }
251
252
253
254 /****************************************************************************\
255  *
256  * tonemap_getActualBufSizes - Returns buf sizes needed for remainder of job
257  *
258 \****************************************************************************/
259
260 static WORD tonemap_getActualBufSizes (
261     IP_XFORM_HANDLE hXform,          /* in:  handle for xform */
262     PDWORD          pdwMinInBufLen,  /* out: min input buf size */
263     PDWORD          pdwMinOutBufLen) /* out: min output buf size */
264 {
265     PTMAP_INST g;
266
267     HANDLE_TO_PTR (hXform, g);
268
269     *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
270     return IP_DONE;
271
272     fatal_error:
273     return IP_FATAL_ERROR;
274 }
275
276
277
278 /*****************************************************************************\
279  *
280  * tonemap_convert - Converts one row
281  *
282 \*****************************************************************************/
283
284 static WORD tonemap_convert (
285     IP_XFORM_HANDLE hXform,
286     DWORD           dwInputAvail,     /* in:  # avail bytes in in-buf */
287     PBYTE           pbInputBuf,       /* in:  ptr to in-buffer */
288     PDWORD          pdwInputUsed,     /* out: # bytes used from in-buf */
289     PDWORD          pdwInputNextPos,  /* out: file-pos to read from next */
290     DWORD           dwOutputAvail,    /* in:  # avail bytes in out-buf */
291     PBYTE           pbOutputBuf,      /* in:  ptr to out-buffer */
292     PDWORD          pdwOutputUsed,    /* out: # bytes written in out-buf */
293     PDWORD          pdwOutputThisPos) /* out: file-pos to write the data */
294 {
295     PTMAP_INST g;
296     int       nBytes;
297     PBYTE     pIn, pOut, pOutAfter;
298
299     HANDLE_TO_PTR (hXform, g);
300
301     /**** Check if we were told to flush ****/
302
303     if (pbInputBuf == NULL) {
304         PRINT (_T("tonemap_convert: Told to flush.\n"), 0, 0);
305         *pdwInputUsed = *pdwOutputUsed = 0;
306         *pdwInputNextPos  = g->dwInNextPos;
307         *pdwOutputThisPos = g->dwOutNextPos;
308         return IP_DONE;
309     }
310
311     /**** Output a Row ****/
312
313     nBytes = g->dwBytesPerRow;
314     INSURE (dwInputAvail  >= (DWORD)nBytes );
315     INSURE (dwOutputAvail >= (DWORD)nBytes);
316
317     pIn  = pbInputBuf;
318     pOut = pbOutputBuf;
319     pOutAfter = pOut + nBytes;
320
321     if (g->traits.iBitsPerPixel == 8) {
322         /* easiest case */
323         while (pOut < pOutAfter) {
324             *pOut++ = g->tonemap[*pIn++];
325         }
326     } else if (g->traits.iBitsPerPixel == 24) {
327         if (g->bLumSpace) {
328             /* easy case: 24-bit color in a luminance space */
329             while (pOut < pOutAfter) {
330                 *pOut = g->tonemap[*pIn];
331                 pIn  += 3;
332                 pOut += 3;
333             }
334         } else {
335             /* 24-bit color in RGB */
336             int rv, gv, bv;
337             int l_old, l_new, dl;
338
339             while (pOut < pOutAfter) {
340                 rv = *pIn++;
341                 gv = *pIn++;
342                 bv = *pIn++;
343
344                 l_old = NTSC_LUMINANCE (rv, gv, bv);
345                 l_new = g->tonemap[l_old];  /* new luminance */
346                 dl = l_new - l_old;
347                 rv += dl;
348                 gv += dl;
349                 bv += dl;
350
351                 if (rv > 255) rv = 255; else if (rv < 0) rv = 0;
352                 if (gv > 255) gv = 255; else if (gv < 0) gv = 0;
353                 if (bv > 255) bv = 255; else if (bv < 0) bv = 0;
354
355                 *pOut++ = (BYTE)rv;
356                 *pOut++ = (BYTE)gv;
357                 *pOut++ = (BYTE)bv;
358             }
359         }
360     } else {   /* 48 bits/pixel */
361         PWORD src      = (PWORD)pIn;
362         PWORD dst      = (PWORD)pOut;
363         PWORD dstAfter = (PWORD)pOutAfter;
364
365         int rv, gv, bv;
366         int l_old, l_old8, l_new1, l_new2, l_new, dl;
367
368         while (dst < dstAfter) {
369             rv = *src++;
370             gv = *src++;
371             bv = *src++;
372
373             /* use linear interpolation between tonemap entries
374              * to compute new luminance (l_new) */
375             l_old  = g->bLumSpace ? rv : NTSC_LUMINANCE (rv, gv, bv);
376             l_old8 = l_old >> 8;
377             l_new1 = g->tonemap[l_old8];
378             l_new2 = l_old8<255 ? g->tonemap[l_old8+1] : l_new1;
379             l_new  = (l_new2-l_new1)*(l_old&0x00ff) + (l_new1<<8);
380
381             dl = l_new - l_old;
382             rv += dl;
383             if (rv > 65535) rv = 65535; else if (rv < 0) rv = 0;
384
385             if (! g->bLumSpace) {
386                 gv += dl;
387                 bv += dl;
388                 if (gv > 65535) gv = 65535; else if (gv < 0) gv = 0;
389                 if (bv > 65535) bv = 65535; else if (bv < 0) bv = 0;
390             }
391
392             *dst++ = (WORD)rv;
393             *dst++ = (WORD)gv;
394             *dst++ = (WORD)bv;
395         }
396     }
397
398     *pdwInputUsed     = nBytes;
399     g->dwInNextPos   += nBytes;
400     *pdwInputNextPos  = g->dwInNextPos;
401
402     *pdwOutputUsed    = nBytes;
403     *pdwOutputThisPos = g->dwOutNextPos;
404     g->dwOutNextPos  += nBytes;
405
406     g->dwRowsDone += 1;
407
408     return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
409
410     fatal_error:
411     return IP_FATAL_ERROR;
412 }
413
414
415
416 /*****************************************************************************\
417  *
418  * tonemap_insertedData - client inserted into our output stream
419  *
420 \*****************************************************************************/
421
422 static WORD tonemap_insertedData (
423     IP_XFORM_HANDLE hXform,
424     DWORD           dwNumBytes)
425 {
426     fatalBreakPoint ();
427     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
428 }
429
430
431
432 /*****************************************************************************\
433  *
434  * tonemap_newPage - Tells us to flush this page, and start a new page
435  *
436 \*****************************************************************************/
437
438 static WORD tonemap_newPage (
439     IP_XFORM_HANDLE hXform)
440 {
441     PTMAP_INST g;
442
443     HANDLE_TO_PTR (hXform, g);
444     /* todo: return fatal error if convert is called again? */
445     return IP_DONE;   /* can't insert page-breaks, so ignore this call */
446
447     fatal_error:
448     return IP_FATAL_ERROR;
449
450 }
451
452
453
454 /*****************************************************************************\
455  *
456  * tonemap_closeXform - Destroys this instance
457  *
458 \*****************************************************************************/
459
460 static WORD tonemap_closeXform (IP_XFORM_HANDLE hXform)
461 {
462     PTMAP_INST g;
463
464     HANDLE_TO_PTR (hXform, g);
465
466     g->dwValidChk = 0;
467     IP_MEM_FREE (g);       /* free memory for the instance */
468
469     return IP_DONE;
470
471     fatal_error:
472     return IP_FATAL_ERROR;
473 }
474
475
476
477 /*****************************************************************************\
478  *
479  * tonemapTbl - Jump-table for transform driver
480  *
481 \*****************************************************************************/
482
483 IP_XFORM_TBL tonemapTbl = {
484     tonemap_openXform,
485     tonemap_setDefaultInputTraits,
486     tonemap_setXformSpec,
487     tonemap_getHeaderBufSize,
488     tonemap_getActualTraits,
489     tonemap_getActualBufSizes,
490     tonemap_convert,
491     tonemap_newPage,
492     tonemap_insertedData,
493     tonemap_closeXform
494 };
495
496 /* End of File */