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 * xmatrix.c - runs color data thru a 3x3 matrix (24 or 48 bits/pixel)
41 * Mark Overton, June 2000
43 ******************************************************************************
45 * Name of Global Jump-Table:
49 * Items in aXformInfo array passed into setXformSpec:
51 * aXformInfo[0] = pointer to the matrix, which is an array of nine
52 * signed integers (type int) in 8.24 fixed-point. If we pretend that
53 * the array is named 'm', then pixels are computed as follows:
55 * r_out = m[0]*r_in + m[1]*g_in + m[2]*b_in
56 * g_out = m[3]*r_in + m[4]*g_in + m[5]*b_in
57 * b_out = m[6]*r_in + m[7]*g_in + m[8]*b_in
59 * Capabilities and Limitations:
61 * Passes pixels through a 3x3 matrix. 24 or 48 bits/pixel only.
63 * Default Input Traits, and Output Traits:
65 * trait default input output
66 * ------------------- --------------------- ------------------------
67 * iPixelsPerRow * passed into output same as default input
68 * iBitsPerPixel * must be 24 or 48 same as default input
69 * iComponentsPerPixel * must be 3 same as default input
70 * lHorizDPI passed into output same as default input
71 * lVertDPI passed into output same as default input
72 * lNumRows passed into output same as default input
73 * iNumPages passed into output same as default input
74 * iPageNum passed into output same as default input
76 * Above, a "*" by an item indicates it must be valid (not negative).
78 \******************************************************************************/
80 /* Use the #define below if this transform will exist in a dll outside of the
81 * image pipeline. This will allow the functions to be exported.
82 * #define EXPORT_TRANFORM 1
87 #include "string.h" /* for memset and memcpy */
93 #define PRINT(msg,arg1,arg2) \
94 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
96 #define PRINT(msg,arg1,arg2)
99 #define CHECK_VALUE 0x4ba1dace
101 #ifdef EXPORT_TRANSFORM
102 #define FUNC_STATUS __declspec (dllexport)
104 #define FUNC_STATUS static
109 IP_IMAGE_TRAITS traits; /* traits of the input and output image */
110 DWORD dwBytesPerRow; /* # of bytes in each row */
111 DWORD dwRowsDone; /* number of rows processed so far */
112 DWORD dwInNextPos; /* file pos for subsequent input */
113 DWORD dwOutNextPos; /* file pos for subsequent output */
114 int mat[9]; /* the matrix */
115 DWORD dwValidChk; /* struct validity check value */
116 } MAT_INST, *PMAT_INST;
120 /*****************************************************************************\
122 * mat_openXform - Creates a new instance of the transformer
124 *****************************************************************************
126 * This returns a handle for the new instance to be passed into
127 * all subsequent calls.
129 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
131 \*****************************************************************************/
133 FUNC_STATUS WORD mat_openXform (
134 IP_XFORM_HANDLE *pXform) /* out: returned handle */
138 INSURE (pXform != NULL);
139 IP_MEM_ALLOC (sizeof(MAT_INST), g);
141 memset (g, 0, sizeof(MAT_INST));
142 g->dwValidChk = CHECK_VALUE;
146 return IP_FATAL_ERROR;
151 /*****************************************************************************\
153 * mat_setDefaultInputTraits - Specifies default input image traits
155 *****************************************************************************
157 * The header of the file-type handled by the transform probably does
158 * not include *all* the image traits we'd like to know. Those not
159 * specified in the file-header are filled in from info provided by
162 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
164 \*****************************************************************************/
166 FUNC_STATUS WORD mat_setDefaultInputTraits (
167 IP_XFORM_HANDLE hXform, /* in: handle for xform */
168 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
172 HANDLE_TO_PTR (hXform, g);
174 /* insure that traits we care about are known */
175 INSURE (pTraits->iPixelsPerRow > 0);
176 INSURE (pTraits->iBitsPerPixel==24 || pTraits->iBitsPerPixel==48);
177 INSURE (pTraits->iComponentsPerPixel == 3);
179 g->traits = *pTraits; /* a structure copy */
183 return IP_FATAL_ERROR;
188 /*****************************************************************************\
190 * mat_setXformSpec - Provides xform-specific information
192 \*****************************************************************************/
194 FUNC_STATUS WORD mat_setXformSpec (
195 IP_XFORM_HANDLE hXform, /* in: handle for xform */
196 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
201 HANDLE_TO_PTR (hXform, g);
203 ptr = (int*)aXformInfo[0].pvoid;
204 INSURE (ptr != NULL);
205 memcpy (g->mat, ptr, sizeof(g->mat));
210 return IP_FATAL_ERROR;
215 /*****************************************************************************\
217 * mat_getHeaderBufSize- Returns size of input buf needed to hold header
219 \*****************************************************************************/
221 FUNC_STATUS WORD mat_getHeaderBufSize (
222 IP_XFORM_HANDLE hXform, /* in: handle for xform */
223 DWORD *pdwInBufLen) /* out: buf size for parsing header */
225 /* since input is raw pixels, there is no header, so set it to zero */
232 /*****************************************************************************\
234 * mat_getActualTraits - Parses header, and returns input & output traits
236 \*****************************************************************************/
238 FUNC_STATUS WORD mat_getActualTraits (
239 IP_XFORM_HANDLE hXform, /* in: handle for xform */
240 DWORD dwInputAvail, /* in: # avail bytes in input buf */
241 PBYTE pbInputBuf, /* in: ptr to input buffer */
242 PDWORD pdwInputUsed, /* out: # bytes used from input buf */
243 PDWORD pdwInputNextPos,/* out: file-pos to read from next */
244 PIP_IMAGE_TRAITS pIntraits, /* out: input image traits */
245 PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
249 HANDLE_TO_PTR (hXform, g);
251 /* Since there is no header, we'll report no usage of input */
253 *pdwInputNextPos = 0;
255 *pIntraits = g->traits; /* structure copies */
256 *pOutTraits = g->traits;
258 /* At this point, nothing will change, so compute internal variables */
259 g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
261 if (g->traits.iBitsPerPixel == 24) {
263 for (i=0; i<9; i++) {
264 /* we'll use 16 bits of fraction instead of 24 */
265 g->mat[i] = (g->mat[i]+(1<<7)) >> 8;
269 return IP_DONE | IP_READY_FOR_DATA;
272 return IP_FATAL_ERROR;
277 /****************************************************************************\
279 * mat_getActualBufSizes - Returns buf sizes needed for remainder of job
281 \****************************************************************************/
283 FUNC_STATUS WORD mat_getActualBufSizes (
284 IP_XFORM_HANDLE hXform, /* in: handle for xform */
285 PDWORD pdwMinInBufLen, /* out: min input buf size */
286 PDWORD pdwMinOutBufLen) /* out: min output buf size */
290 HANDLE_TO_PTR (hXform, g);
292 *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
296 return IP_FATAL_ERROR;
301 /*****************************************************************************\
303 * mat_convert - Converts one row
305 \*****************************************************************************/
307 FUNC_STATUS WORD mat_convert (
308 IP_XFORM_HANDLE hXform,
309 DWORD dwInputAvail, /* in: # avail bytes in in-buf */
310 PBYTE pbInputBuf, /* in: ptr to in-buffer */
311 PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
312 PDWORD pdwInputNextPos, /* out: file-pos to read from next */
313 DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
314 PBYTE pbOutputBuf, /* in: ptr to out-buffer */
315 PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
316 PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
320 PBYTE pIn, pOut, pOutAfter;
321 int rIn, gIn, bIn, rOut, gOut, bOut;
323 HANDLE_TO_PTR (hXform, g);
325 /**** Check for flushing ****/
327 if (pbInputBuf == NULL) {
328 PRINT (_T("mat_convert: Told to flush.\n"), 0, 0);
330 *pdwInputUsed = *pdwOutputUsed = 0;
331 *pdwInputNextPos = g->dwInNextPos;
332 *pdwOutputThisPos = g->dwOutNextPos;
336 /**** Output a Row ****/
338 nBytes = g->dwBytesPerRow;
339 INSURE (dwInputAvail >= (DWORD)nBytes);
340 INSURE (dwOutputAvail >= (DWORD)nBytes);
344 pOutAfter = pbOutputBuf + nBytes;
346 if (g->traits.iBitsPerPixel == 24)
348 while (pOut < pOutAfter)
350 rIn = (int)(unsigned)(*pIn++);
351 gIn = (int)(unsigned)(*pIn++);
352 bIn = (int)(unsigned)(*pIn++);
354 /* for this 24-bit case, we assume that the matrix has already
355 * been shifted down to just 16 bits of fraction instead of 24 */
356 rOut = rIn*g->mat[0] + gIn*g->mat[1] + bIn*g->mat[2];
357 gOut = rIn*g->mat[3] + gIn*g->mat[4] + bIn*g->mat[5];
358 bOut = rIn*g->mat[6] + gIn*g->mat[7] + bIn*g->mat[8];
360 /* we have 16 bits of fraction, so round to integer */
361 rOut = (rOut+(1<<15)) >> 16;
362 gOut = (gOut+(1<<15)) >> 16;
363 bOut = (bOut+(1<<15)) >> 16;
365 /* make sure the result fits in a byte */
366 if (rOut > 255) rOut = 255; else if (rOut < 0) rOut = 0;
367 if (gOut > 255) gOut = 255; else if (gOut < 0) gOut = 0;
368 if (bOut > 255) bOut = 255; else if (bOut < 0) bOut = 0;
370 *pOut++ = (BYTE)rOut;
371 *pOut++ = (BYTE)gOut;
372 *pOut++ = (BYTE)bOut;
375 else /* 48 bits per pixel */
381 while (pwOut < (WORD*)pOutAfter)
383 int prod0, prod1, prod2;
385 /* The fixed-point calculations below are as follows:
386 * 17.15 = input pixel
387 * 8.24 = factor from matrix
388 * 25.39 = result of 32x32->64 multiply of above numbers
389 * 25.7 = result of discarding low 32 bits of 64-bit product
390 * Finally, we add (1<<6) and shift right 7 to round to integer.
392 * The MUL32HIHALF macro does a signed 32x32->64 multiply, and then
393 * discards the low 32 bits, giving you the high 32 bits.
396 rIn = (int)(unsigned)(*pwIn++) << 15;
397 gIn = (int)(unsigned)(*pwIn++) << 15;
398 bIn = (int)(unsigned)(*pwIn++) << 15;
400 MUL32HIHALF (rIn, g->mat[0], prod0);
401 MUL32HIHALF (gIn, g->mat[1], prod1);
402 MUL32HIHALF (bIn, g->mat[2], prod2);
403 rOut = (prod0 + prod1 + prod2 + (1<<6)) >> 7;
404 if (rOut > 0x00ffff) rOut = 0x00ffff; else if (rOut < 0) rOut = 0;
407 MUL32HIHALF (rIn, g->mat[3], prod0);
408 MUL32HIHALF (gIn, g->mat[4], prod1);
409 MUL32HIHALF (bIn, g->mat[5], prod2);
410 gOut = (prod0 + prod1 + prod2 + (1<<6)) >> 7;
411 if (gOut > 0x00ffff) gOut = 0x00ffff; else if (gOut < 0) gOut = 0;
414 MUL32HIHALF (rIn, g->mat[6], prod0);
415 MUL32HIHALF (gIn, g->mat[7], prod1);
416 MUL32HIHALF (bIn, g->mat[8], prod2);
417 bOut = (prod0 + prod1 + prod2 + (1<<6)) >> 7;
418 if (bOut > 0x00ffff) bOut = 0x00ffff; else if (bOut < 0) bOut = 0;
423 *pdwInputUsed = nBytes;
424 g->dwInNextPos += nBytes;
425 *pdwInputNextPos = g->dwInNextPos;
427 *pdwOutputUsed = nBytes;
428 *pdwOutputThisPos = g->dwOutNextPos;
429 g->dwOutNextPos += nBytes;
432 return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
435 return IP_FATAL_ERROR;
440 /*****************************************************************************\
442 * mat_insertedData - client inserted into our output stream
444 \*****************************************************************************/
446 FUNC_STATUS WORD mat_insertedData (
447 IP_XFORM_HANDLE hXform,
451 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
456 /*****************************************************************************\
458 * mat_newPage - Tells us to flush this page, and start a new page
460 \*****************************************************************************/
462 FUNC_STATUS WORD mat_newPage (
463 IP_XFORM_HANDLE hXform)
467 HANDLE_TO_PTR (hXform, g);
468 /* todo: return fatal error if convert is called again? */
469 return IP_DONE; /* can't insert page-breaks, so ignore this call */
472 return IP_FATAL_ERROR;
478 /*****************************************************************************\
480 * mat_closeXform - Destroys this instance
482 \*****************************************************************************/
484 FUNC_STATUS WORD mat_closeXform (IP_XFORM_HANDLE hXform)
488 HANDLE_TO_PTR (hXform, g);
491 IP_MEM_FREE (g); /* free memory for the instance */
496 return IP_FATAL_ERROR;
501 /*****************************************************************************\
503 * matTbl - Jump-table for transform driver
505 \*****************************************************************************/
506 #ifdef EXPORT_TRANSFORM
507 __declspec (dllexport)
509 IP_XFORM_TBL matrixTbl = {
511 mat_setDefaultInputTraits,
513 mat_getHeaderBufSize,
515 mat_getActualBufSizes,
525 /*****************************************************************************\
527 * ipGetXformTable - Returns pointer to the jump table
529 \*****************************************************************************/
531 #ifdef EXPORT_TRANSFORM
532 EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
542 wRet = IP_FATAL_ERROR;