Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xmatrix.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  * xmatrix.c - runs color data thru a 3x3 matrix (24 or 48 bits/pixel)
40  *
41  * Mark Overton, June 2000
42  *
43  ******************************************************************************
44  *
45  * Name of Global Jump-Table:
46  *
47  *    matrixTbl
48  *
49  * Items in aXformInfo array passed into setXformSpec:
50  *
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:
54  *
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
58  *
59  * Capabilities and Limitations:
60  *
61  *    Passes pixels through a 3x3 matrix.  24 or 48 bits/pixel only.
62  *
63  * Default Input Traits, and Output Traits:
64  *
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
75  *
76  *    Above, a "*" by an item indicates it must be valid (not negative).
77  *
78 \******************************************************************************/
79
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
83  */
84
85 #include "hpip.h"
86 #include "ipdefs.h"
87 #include "string.h"    /* for memset and memcpy */
88
89
90 #if 0
91     #include "stdio.h"
92     #include <tchar.h>
93     #define PRINT(msg,arg1,arg2) \
94         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
95 #else
96     #define PRINT(msg,arg1,arg2)
97 #endif
98
99 #define CHECK_VALUE 0x4ba1dace
100
101 #ifdef EXPORT_TRANSFORM
102 #define FUNC_STATUS __declspec (dllexport)
103 #else
104 #define FUNC_STATUS static
105 #endif
106
107
108 typedef struct {
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;
117
118
119
120 /*****************************************************************************\
121  *
122  * mat_openXform - Creates a new instance of the transformer
123  *
124  *****************************************************************************
125  *
126  * This returns a handle for the new instance to be passed into
127  * all subsequent calls.
128  *
129  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
130  *
131 \*****************************************************************************/
132
133 FUNC_STATUS WORD mat_openXform (
134     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
135 {
136     PMAT_INST g;
137
138     INSURE (pXform != NULL);
139     IP_MEM_ALLOC (sizeof(MAT_INST), g);
140     *pXform = g;
141     memset (g, 0, sizeof(MAT_INST));
142     g->dwValidChk = CHECK_VALUE;
143     return IP_DONE;
144
145     fatal_error:
146     return IP_FATAL_ERROR;
147 }
148
149
150
151 /*****************************************************************************\
152  *
153  * mat_setDefaultInputTraits - Specifies default input image traits
154  *
155  *****************************************************************************
156  *
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
160  * this routine.
161  *
162  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
163  *
164 \*****************************************************************************/
165
166 FUNC_STATUS WORD mat_setDefaultInputTraits (
167     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
168     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
169 {
170     PMAT_INST g;
171
172     HANDLE_TO_PTR (hXform, g);
173
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);
178
179     g->traits = *pTraits;   /* a structure copy */
180     return IP_DONE;
181
182     fatal_error:
183     return IP_FATAL_ERROR;
184 }
185
186
187
188 /*****************************************************************************\
189  *
190  * mat_setXformSpec - Provides xform-specific information
191  *
192 \*****************************************************************************/
193
194 FUNC_STATUS WORD mat_setXformSpec (
195     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
196     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
197 {
198     PMAT_INST g;
199     int       *ptr;
200
201     HANDLE_TO_PTR (hXform, g);
202
203     ptr = (int*)aXformInfo[0].pvoid;
204     INSURE (ptr != NULL);
205     memcpy (g->mat, ptr, sizeof(g->mat));
206
207     return IP_DONE;
208
209     fatal_error:
210     return IP_FATAL_ERROR;
211 }
212
213
214
215 /*****************************************************************************\
216  *
217  * mat_getHeaderBufSize- Returns size of input buf needed to hold header
218  *
219 \*****************************************************************************/
220
221 FUNC_STATUS WORD mat_getHeaderBufSize (
222     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
223     DWORD           *pdwInBufLen)    /* out: buf size for parsing header */
224 {
225     /* since input is raw pixels, there is no header, so set it to zero */
226     *pdwInBufLen = 0;
227     return IP_DONE;
228 }
229
230
231
232 /*****************************************************************************\
233  *
234  * mat_getActualTraits - Parses header, and returns input & output traits
235  *
236 \*****************************************************************************/
237
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 */
246 {
247     PMAT_INST g;
248
249     HANDLE_TO_PTR (hXform, g);
250
251     /* Since there is no header, we'll report no usage of input */
252     *pdwInputUsed    = 0;
253     *pdwInputNextPos = 0;
254
255     *pIntraits  = g->traits;   /* structure copies */
256     *pOutTraits = g->traits;
257
258     /* At this point, nothing will change, so compute internal variables */
259     g->dwBytesPerRow = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
260
261     if (g->traits.iBitsPerPixel == 24) {
262         int i;
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;
266         }
267     }
268
269     return IP_DONE | IP_READY_FOR_DATA;
270
271     fatal_error:
272     return IP_FATAL_ERROR;
273 }
274
275
276
277 /****************************************************************************\
278  *
279  * mat_getActualBufSizes - Returns buf sizes needed for remainder of job
280  *
281 \****************************************************************************/
282
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 */
287 {
288     PMAT_INST g;
289
290     HANDLE_TO_PTR (hXform, g);
291
292     *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
293     return IP_DONE;
294
295     fatal_error:
296     return IP_FATAL_ERROR;
297 }
298
299
300
301 /*****************************************************************************\
302  *
303  * mat_convert - Converts one row
304  *
305 \*****************************************************************************/
306
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 */
317 {
318     PMAT_INST g;
319     int       nBytes;
320     PBYTE     pIn, pOut, pOutAfter;
321     int rIn, gIn, bIn, rOut, gOut, bOut;
322
323     HANDLE_TO_PTR (hXform, g);
324
325     /**** Check for flushing ****/
326
327     if (pbInputBuf == NULL) {
328         PRINT (_T("mat_convert: Told to flush.\n"), 0, 0);
329         /* we are done */
330         *pdwInputUsed = *pdwOutputUsed = 0;
331         *pdwInputNextPos  = g->dwInNextPos;
332         *pdwOutputThisPos = g->dwOutNextPos;
333         return IP_DONE;
334     }
335
336     /**** Output a Row ****/
337
338     nBytes = g->dwBytesPerRow;
339     INSURE (dwInputAvail  >= (DWORD)nBytes);
340     INSURE (dwOutputAvail >= (DWORD)nBytes);
341
342     pIn       = pbInputBuf;
343     pOut      = pbOutputBuf;
344     pOutAfter = pbOutputBuf + nBytes;
345
346     if (g->traits.iBitsPerPixel == 24)
347     {
348         while (pOut < pOutAfter)
349         {
350             rIn = (int)(unsigned)(*pIn++);
351             gIn = (int)(unsigned)(*pIn++);
352             bIn = (int)(unsigned)(*pIn++);
353
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];
359
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;
364
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;
369
370             *pOut++ = (BYTE)rOut;
371             *pOut++ = (BYTE)gOut;
372             *pOut++ = (BYTE)bOut;
373         }
374     }
375     else   /* 48 bits per pixel */
376     {
377         WORD *pwIn, *pwOut;
378         pwIn  = (WORD*)pIn;
379         pwOut = (WORD*)pOut;
380
381         while (pwOut < (WORD*)pOutAfter)
382         {
383             int prod0, prod1, prod2;
384
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.
391              *
392              * The MUL32HIHALF macro does a signed 32x32->64 multiply, and then
393              * discards the low 32 bits, giving you the high 32 bits.
394              */
395
396             rIn = (int)(unsigned)(*pwIn++) << 15;
397             gIn = (int)(unsigned)(*pwIn++) << 15;
398             bIn = (int)(unsigned)(*pwIn++) << 15;
399
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;
405             *pwOut++ = rOut;
406
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;
412             *pwOut++ = gOut;
413
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;
419             *pwOut++ = bOut;
420         }
421     }
422
423     *pdwInputUsed     = nBytes;
424     g->dwInNextPos   += nBytes;
425     *pdwInputNextPos  = g->dwInNextPos;
426
427     *pdwOutputUsed    = nBytes;
428     *pdwOutputThisPos = g->dwOutNextPos;
429     g->dwOutNextPos  += nBytes;
430
431     g->dwRowsDone += 1;
432     return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
433
434     fatal_error:
435     return IP_FATAL_ERROR;
436 }
437
438
439
440 /*****************************************************************************\
441  *
442  * mat_insertedData - client inserted into our output stream
443  *
444 \*****************************************************************************/
445
446 FUNC_STATUS WORD mat_insertedData (
447     IP_XFORM_HANDLE hXform,
448     DWORD           dwNumBytes)
449 {
450     fatalBreakPoint ();
451     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
452 }
453
454
455
456 /*****************************************************************************\
457  *
458  * mat_newPage - Tells us to flush this page, and start a new page
459  *
460 \*****************************************************************************/
461
462 FUNC_STATUS WORD mat_newPage (
463     IP_XFORM_HANDLE hXform)
464 {
465     PMAT_INST g;
466
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 */
470
471     fatal_error:
472     return IP_FATAL_ERROR;
473
474 }
475
476
477
478 /*****************************************************************************\
479  *
480  * mat_closeXform - Destroys this instance
481  *
482 \*****************************************************************************/
483
484 FUNC_STATUS WORD mat_closeXform (IP_XFORM_HANDLE hXform)
485 {
486     PMAT_INST g;
487
488     HANDLE_TO_PTR (hXform, g);
489
490     g->dwValidChk = 0;
491     IP_MEM_FREE (g);       /* free memory for the instance */
492
493     return IP_DONE;
494
495     fatal_error:
496     return IP_FATAL_ERROR;
497 }
498
499
500
501 /*****************************************************************************\
502  *
503  * matTbl - Jump-table for transform driver
504  *
505 \*****************************************************************************/
506 #ifdef EXPORT_TRANSFORM
507 __declspec (dllexport)
508 #endif
509 IP_XFORM_TBL matrixTbl = {
510     mat_openXform,
511     mat_setDefaultInputTraits,
512     mat_setXformSpec,
513     mat_getHeaderBufSize,
514     mat_getActualTraits,
515     mat_getActualBufSizes,
516     mat_convert,
517     mat_newPage,
518     mat_insertedData,
519     mat_closeXform
520 };
521
522 /* End of File */
523
524
525 /*****************************************************************************\
526  *
527  * ipGetXformTable - Returns pointer to the jump table
528  *
529 \*****************************************************************************/
530
531 #ifdef EXPORT_TRANSFORM
532 EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
533 {
534     WORD wRet = IP_DONE;
535
536     if (pXform)
537     {
538         *pXform = clrmapTbl;
539     }
540     else
541     {
542         wRet = IP_FATAL_ERROR;
543     }
544
545     return wRet;
546 }
547 #endif