1 /* libhpojip -- HP OfficeJet image-processing library. */
3 /* Copyright (C) 1995-2002 Hewlett-Packard Company
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
13 * NON-INFRINGEMENT. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 * In addition, as a special exception, Hewlett-Packard Company
21 * gives permission to link the code of this program with any
22 * version of the OpenSSL library which is distributed under a
23 * license identical to that listed in the included LICENSE.OpenSSL
24 * file, and distribute linked combinations including the two.
25 * You must obey the GNU General Public License in all respects
26 * for all of the code used other than OpenSSL. If you modify
27 * this file, you may extend this exception to your version of the
28 * file, but you are not obligated to do so. If you do not wish to
29 * do so, delete this exception statement from your version.
32 /* Original author: Mark Overton and others.
34 * Ported to Linux by David Paschal.
37 /******************************************************************************\
39 * xtonemap.c - Performs a 256-byte tonemap to grayscale or color data
41 ******************************************************************************
43 * Name of Global Jump-Table:
47 * Items in aXformInfo array passed into setXformSpec:
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)
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.
58 * An internal copy is made of the tonemap.
60 * Capabilities and Limitations:
62 * The incoming data can be 8-bit gray or 24-bit color or 48-bit color.
64 * Default Input Traits, and Output Traits:
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
77 * Above, a "*" by an item indicates it must be valid (not negative).
79 * Jan 2000 Mark Overton -- wrote original code
81 \******************************************************************************/
85 #include "string.h" /* for memset and memcpy */
92 #define PRINT(msg,arg1,arg2) \
93 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
95 #define PRINT(msg,arg1,arg2)
98 #define CHECK_VALUE 0x4ba1dace
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;
114 /*****************************************************************************\
116 * tonemap_openXform - Creates a new instance of the transformer
118 *****************************************************************************
120 * This returns a handle for the new instance to be passed into
121 * all subsequent calls.
123 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
125 \*****************************************************************************/
127 static WORD tonemap_openXform (
128 IP_XFORM_HANDLE *pXform) /* out: returned handle */
132 INSURE (pXform != NULL);
133 IP_MEM_ALLOC (sizeof(TMAP_INST), g);
135 memset (g, 0, sizeof(TMAP_INST));
136 g->dwValidChk = CHECK_VALUE;
140 return IP_FATAL_ERROR;
145 /*****************************************************************************\
147 * tonemap_setDefaultInputTraits - Specifies default input image traits
149 *****************************************************************************
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
156 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
158 \*****************************************************************************/
160 static WORD tonemap_setDefaultInputTraits (
161 IP_XFORM_HANDLE hXform, /* in: handle for xform */
162 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
166 HANDLE_TO_PTR (hXform, g);
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;
175 return IP_FATAL_ERROR;
180 /*****************************************************************************\
182 * tonemap_setXformSpec - Provides xform-specific information
184 \*****************************************************************************/
186 static WORD tonemap_setXformSpec (
187 IP_XFORM_HANDLE hXform, /* in: handle for xform */
188 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
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;
198 return IP_FATAL_ERROR;
203 /*****************************************************************************\
205 * tonemap_getHeaderBufSize- Returns size of input buf needed to hold header
207 \*****************************************************************************/
209 static WORD tonemap_getHeaderBufSize (
210 IP_XFORM_HANDLE hXform, /* in: handle for xform */
211 DWORD *pdwInBufLen) /* out: buf size for parsing header */
213 /* since input is raw pixels, there is no header, so set it to zero */
220 /*****************************************************************************\
222 * tonemap_getActualTraits - Parses header, and returns input & output traits
224 \*****************************************************************************/
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 */
237 HANDLE_TO_PTR (hXform, g);
239 /* Since there is no header, we'll report no usage of input */
241 *pdwInputNextPos = 0;
243 *pIntraits = g->traits; /* structure copies */
244 *pOutTraits = g->traits;
246 return IP_DONE | IP_READY_FOR_DATA;
249 return IP_FATAL_ERROR;
254 /****************************************************************************\
256 * tonemap_getActualBufSizes - Returns buf sizes needed for remainder of job
258 \****************************************************************************/
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 */
267 HANDLE_TO_PTR (hXform, g);
269 *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
273 return IP_FATAL_ERROR;
278 /*****************************************************************************\
280 * tonemap_convert - Converts one row
282 \*****************************************************************************/
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 */
297 PBYTE pIn, pOut, pOutAfter;
299 HANDLE_TO_PTR (hXform, g);
301 /**** Check if we were told to flush ****/
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;
311 /**** Output a Row ****/
313 nBytes = g->dwBytesPerRow;
314 INSURE (dwInputAvail >= (DWORD)nBytes );
315 INSURE (dwOutputAvail >= (DWORD)nBytes);
319 pOutAfter = pOut + nBytes;
321 if (g->traits.iBitsPerPixel == 8) {
323 while (pOut < pOutAfter) {
324 *pOut++ = g->tonemap[*pIn++];
326 } else if (g->traits.iBitsPerPixel == 24) {
328 /* easy case: 24-bit color in a luminance space */
329 while (pOut < pOutAfter) {
330 *pOut = g->tonemap[*pIn];
335 /* 24-bit color in RGB */
337 int l_old, l_new, dl;
339 while (pOut < pOutAfter) {
344 l_old = NTSC_LUMINANCE (rv, gv, bv);
345 l_new = g->tonemap[l_old]; /* new luminance */
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;
360 } else { /* 48 bits/pixel */
361 PWORD src = (PWORD)pIn;
362 PWORD dst = (PWORD)pOut;
363 PWORD dstAfter = (PWORD)pOutAfter;
366 int l_old, l_old8, l_new1, l_new2, l_new, dl;
368 while (dst < dstAfter) {
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);
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);
383 if (rv > 65535) rv = 65535; else if (rv < 0) rv = 0;
385 if (! g->bLumSpace) {
388 if (gv > 65535) gv = 65535; else if (gv < 0) gv = 0;
389 if (bv > 65535) bv = 65535; else if (bv < 0) bv = 0;
398 *pdwInputUsed = nBytes;
399 g->dwInNextPos += nBytes;
400 *pdwInputNextPos = g->dwInNextPos;
402 *pdwOutputUsed = nBytes;
403 *pdwOutputThisPos = g->dwOutNextPos;
404 g->dwOutNextPos += nBytes;
408 return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
411 return IP_FATAL_ERROR;
416 /*****************************************************************************\
418 * tonemap_insertedData - client inserted into our output stream
420 \*****************************************************************************/
422 static WORD tonemap_insertedData (
423 IP_XFORM_HANDLE hXform,
427 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
432 /*****************************************************************************\
434 * tonemap_newPage - Tells us to flush this page, and start a new page
436 \*****************************************************************************/
438 static WORD tonemap_newPage (
439 IP_XFORM_HANDLE hXform)
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 */
448 return IP_FATAL_ERROR;
454 /*****************************************************************************\
456 * tonemap_closeXform - Destroys this instance
458 \*****************************************************************************/
460 static WORD tonemap_closeXform (IP_XFORM_HANDLE hXform)
464 HANDLE_TO_PTR (hXform, g);
467 IP_MEM_FREE (g); /* free memory for the instance */
472 return IP_FATAL_ERROR;
477 /*****************************************************************************\
479 * tonemapTbl - Jump-table for transform driver
481 \*****************************************************************************/
483 IP_XFORM_TBL tonemapTbl = {
485 tonemap_setDefaultInputTraits,
486 tonemap_setXformSpec,
487 tonemap_getHeaderBufSize,
488 tonemap_getActualTraits,
489 tonemap_getActualBufSizes,
492 tonemap_insertedData,