Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xconvolve.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  * xconvolve.c - convolution using any number or rows and columns up to max
40  *
41  ******************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    convolveTbl
46  *
47  * Items in aXformInfo array passed into setXformSpec:
48  *
49  *    aXformInfo[IP_CONVOLVE_NROWS  ] = # rows in convolution matrix (odd)
50  *    aXformInfo[IP_CONVOLVE_NCOLS  ] = # columns in convolution matrix (odd)
51  *    aXformInfo[IP_CONVOLVE_MATRIX ] = ptr to convolution matrix
52  *    aXformInfo[IP_CONVOLVE_DIVISOR] = divide by this after summing products
53  *
54  *    The matrix is an array of int's, ordered left to right, top to bottom.
55  *    After the pixels are multiplied by the elements in the matrix and these
56  *    products summed together, the sum is divided by the integer divisor.
57  *
58  *    If you set nRows and nCols to 7, then this xform is identical to the
59  *    "User defined filter" feature in Paint Shop Pro.
60  *
61  *    This xform makes a copy of the given matrix, so its memory can be freed
62  *    after you've called setXformSpec.
63  *
64  *    IP_CONVOLVE_MAXSIZE is the max number of rows or columns.
65  *
66  * Capabilities and Limitations:
67  *
68  *    The input data must be grayscale (8 or 16 bits/pixel), or color (24 or
69  *    48 bits/pixel) in a luminance-chrominance color-space.  This xform only
70  *    changes the first component of color data (assumed to be the luminance).
71  *
72  * Default Input Traits, and Output Traits:
73  *
74  *          trait             default input             output
75  *    -------------------  ---------------------  ------------------------
76  *    iPixelsPerRow         * passed into output   same as default input
77  *    iBitsPerPixel         * 8, 16, 24 or 48      same as default input
78  *    iComponentsPerPixel   * 1 or 3               same as default input
79  *    lHorizDPI               passed into output   same as default input
80  *    lVertDPI                passed into output   same as default input
81  *    lNumRows                passed into output   same as default input
82  *    iNumPages               passed into output   same as default input
83  *    iPageNum                passed into output   same as default input
84  *
85  *    Above, a "*" by an item indicates it must be valid (not negative).
86  *
87 \******************************************************************************/
88
89 /* Use the #define below if this transform will exist in a dll outside of the
90  * image pipeline.  This will allow the functions to be exported.
91  * #define EXPORT_TRANFORM 1
92  */
93
94 #include "hpip.h"
95 #include "ipdefs.h"
96 #include "string.h"    /* for memset and memcpy */
97
98
99 #if 0
100     #include "stdio.h"
101     #include <tchar.h>
102     #define PRINT(msg,arg1,arg2) \
103         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
104 #else
105     #define PRINT(msg,arg1,arg2)
106 #endif
107
108 #define CHECK_VALUE 0x4ba1dace
109
110 #ifdef EXPORT_TRANSFORM
111 #define FUNC_STATUS __declspec (dllexport)
112 #else
113 #define FUNC_STATUS static
114 #endif
115
116 typedef struct {
117     IP_IMAGE_TRAITS traits;   /* traits of the input and output image */
118     DWORD    dwBytesPerRow;   /* # of bytes in each row */
119     int      iBytesPerPixel;  /* # bytes in each pixel */
120     DWORD    dwRowsRead;      /* number of rows read so far */
121     DWORD    dwRowsWritten;   /* number of rows output so far */
122     DWORD    dwInNextPos;     /* file pos for subsequent input */
123     DWORD    dwOutNextPos;    /* file pos for subsequent output */
124     int      nCols;           /* # columns in the matrix (must be odd) */
125     int      nRows;           /* # rows in the matrix (must be odd) */
126     int      nRowsFilled;     /* # rows filled so far in the matrix */
127     int      iDivisor;        /* divide sum of products by this */
128     int      matrix[IP_CONVOLVE_MAXSIZE*IP_CONVOLVE_MAXSIZE];  /* the matrix */
129     PBYTE    apRows[IP_CONVOLVE_MAXSIZE];  /* ptrs to buffered rows */
130     DWORD    dwValidChk;      /* struct validity check value */
131 } CONV_INST, *PCONV_INST;
132
133
134
135 /*****************************************************************************\
136  *
137  * convolve_openXform - Creates a new instance of the transformer
138  *
139  *****************************************************************************
140  *
141  * This returns a handle for the new instance to be passed into
142  * all subsequent calls.
143  *
144  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
145  *
146 \*****************************************************************************/
147
148 FUNC_STATUS WORD convolve_openXform (
149     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
150 {
151     PCONV_INST g;
152
153     INSURE (pXform != NULL);
154     IP_MEM_ALLOC (sizeof(CONV_INST), g);
155     *pXform = g;
156     memset (g, 0, sizeof(CONV_INST));
157     g->dwValidChk = CHECK_VALUE;
158     return IP_DONE;
159
160     fatal_error:
161     return IP_FATAL_ERROR;
162 }
163
164
165
166 /*****************************************************************************\
167  *
168  * convolve_setDefaultInputTraits - Specifies default input image traits
169  *
170  *****************************************************************************
171  *
172  * The header of the file-type handled by the transform probably does
173  * not include *all* the image traits we'd like to know.  Those not
174  * specified in the file-header are filled in from info provided by
175  * this routine.
176  *
177  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
178  *
179 \*****************************************************************************/
180
181 FUNC_STATUS WORD convolve_setDefaultInputTraits (
182     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
183     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
184 {
185     PCONV_INST g;
186     int        bpp;
187     int           comps;
188
189     HANDLE_TO_PTR (hXform, g);
190
191     /* insure that traits we care about are valid */
192     bpp   = pTraits->iBitsPerPixel;
193     comps = pTraits->iComponentsPerPixel;
194     INSURE ((comps==1 && (bpp==8 || bpp==16))  ||
195             (comps==3 && (bpp==24 || bpp==48)));
196     INSURE (pTraits->iPixelsPerRow > 0);
197
198     g->traits = *pTraits;   /* a structure copy */
199     g->iBytesPerPixel = g->traits.iBitsPerPixel / 8;
200     g->dwBytesPerRow = g->traits.iPixelsPerRow * g->iBytesPerPixel;
201     return IP_DONE;
202
203     fatal_error:
204     return IP_FATAL_ERROR;
205 }
206
207
208
209 /*****************************************************************************\
210  *
211  * convolve_setXformSpec - Provides xform-specific information
212  *
213 \*****************************************************************************/
214
215 FUNC_STATUS WORD convolve_setXformSpec (
216     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
217     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
218 {
219     PCONV_INST g;
220     int        i, n;
221
222     HANDLE_TO_PTR (hXform, g);
223
224     g->nRows    = aXformInfo[IP_CONVOLVE_NROWS  ].dword;
225     g->nCols    = aXformInfo[IP_CONVOLVE_NCOLS  ].dword;
226     g->iDivisor = aXformInfo[IP_CONVOLVE_DIVISOR].dword;
227
228     INSURE ((g->nRows&1)!=0 && g->nRows>0 && g->nRows<=IP_CONVOLVE_MAXSIZE);
229     INSURE ((g->nCols&1)!=0 && g->nCols>0 && g->nCols<=IP_CONVOLVE_MAXSIZE);
230     INSURE (g->iDivisor != 0);
231     INSURE (aXformInfo[IP_CONVOLVE_MATRIX].pvoid != 0);
232
233     n = g->nRows * g->nCols;
234     for (i=0; i<n; i++)
235         g->matrix[i] = ((int*)(aXformInfo[IP_CONVOLVE_MATRIX].pvoid))[i];
236
237     return IP_DONE;
238
239     fatal_error:
240     return IP_FATAL_ERROR;
241 }
242
243
244
245 /*****************************************************************************\
246  *
247  * convolve_getHeaderBufSize- Returns size of input buf needed to hold header
248  *
249 \*****************************************************************************/
250
251 FUNC_STATUS WORD convolve_getHeaderBufSize (
252     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
253     DWORD           *pdwInBufLen)    /* out: buf size for parsing header */
254 {
255     /* since input is raw pixels, there is no header, so set it to zero */
256     *pdwInBufLen = 0;
257     return IP_DONE;
258 }
259
260
261
262 /*****************************************************************************\
263  *
264  * convolve_getActualTraits - Parses header, and returns input & output traits
265  *
266 \*****************************************************************************/
267
268 FUNC_STATUS WORD convolve_getActualTraits (
269     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
270     DWORD            dwInputAvail,   /* in:  # avail bytes in input buf */
271     PBYTE            pbInputBuf,     /* in:  ptr to input buffer */
272     PDWORD           pdwInputUsed,   /* out: # bytes used from input buf */
273     PDWORD           pdwInputNextPos,/* out: file-pos to read from next */
274     PIP_IMAGE_TRAITS pIntraits,      /* out: input image traits */
275     PIP_IMAGE_TRAITS pOutTraits)     /* out: output image traits */
276 {
277     PCONV_INST g;
278
279     HANDLE_TO_PTR (hXform, g);
280
281     /* Since there is no header, we'll report no usage of input */
282     *pdwInputUsed    = 0;
283     *pdwInputNextPos = 0;
284
285     *pIntraits  = g->traits;   /* structure copies */
286     *pOutTraits = g->traits;
287
288     return IP_DONE | IP_READY_FOR_DATA;
289
290     fatal_error:
291     return IP_FATAL_ERROR;
292 }
293
294
295
296 /****************************************************************************\
297  *
298  * convolve_getActualBufSizes - Returns buf sizes needed for remainder of job
299  *
300 \****************************************************************************/
301
302 FUNC_STATUS WORD convolve_getActualBufSizes (
303     IP_XFORM_HANDLE hXform,          /* in:  handle for xform */
304     PDWORD          pdwMinInBufLen,  /* out: min input buf size */
305     PDWORD          pdwMinOutBufLen) /* out: min output buf size */
306 {
307     PCONV_INST g;
308
309     HANDLE_TO_PTR (hXform, g);
310
311     *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
312     return IP_DONE;
313
314     fatal_error:
315     return IP_FATAL_ERROR;
316 }
317
318
319
320 /*****************************************************************************\
321  *
322  * CopyRow - Copies row to row-buffer, filling over-run zone on sides
323  *
324 \*****************************************************************************/
325
326 static void CopyRow (
327     PCONV_INST g,       /* ptr to our instance variables */
328     PBYTE      pbSrc,   /* input buffer */
329     PBYTE      pbDest)  /* output buffer in apRows (with side-zones allocated) */
330 {
331     int nSidePixels;
332     int i;
333
334     nSidePixels = g->nCols / 2;
335
336     /* copy leftmost pixel into all pixels in left side-zone */
337     for (i=0; i<nSidePixels; i++) {
338         memcpy (pbDest, pbSrc, g->iBytesPerPixel);
339         pbDest += g->iBytesPerPixel;
340     }
341
342     /* copy the buffer */
343     memcpy (pbDest, pbSrc, g->dwBytesPerRow);
344     pbDest += g->dwBytesPerRow;
345     pbSrc  += g->dwBytesPerRow - g->iBytesPerPixel;  /* leave at rightmost pixel */
346
347     /* copy rightmost pixel into all pixels in right side-zone */
348     for (i=0; i<nSidePixels; i++) {
349         memcpy (pbDest, pbSrc, g->iBytesPerPixel);
350         pbDest += g->iBytesPerPixel;
351     }
352 }
353
354
355
356 /*****************************************************************************\
357  *
358  * convolve_bytes - performs convolution on a row pixels with 8 or 24 bits each
359  *
360 \*****************************************************************************/
361
362 static void convolve_bytes (
363     PCONV_INST g,       /* ptr to our instance variables */
364     PBYTE      pbDest)  /* output buffer */
365 {
366     PBYTE pbSrc, pbDestAfter;
367     int   iSrcOffset, iSideOffset, iSum;
368     int  *pMatrix;
369     int   row, col;
370
371     pbDestAfter = pbDest + g->dwBytesPerRow;
372     iSrcOffset = 0;
373     iSideOffset = g->iBytesPerPixel * (g->nCols>>1);
374
375     while (pbDest < pbDestAfter)   /* for each output pixel ... */
376     {
377         iSum = 0;
378         pMatrix = g->matrix;
379
380         for (row=0; row<g->nRows; row++) {
381             pbSrc = g->apRows[row] + iSrcOffset;
382             for (col=0; col<g->nCols; col++) {
383                 iSum += (*pMatrix++) * (int)(unsigned)(*pbSrc);
384                 pbSrc += g->iBytesPerPixel;
385             }
386         }
387
388         iSum = (iSum + (g->iDivisor>>1)) / g->iDivisor;
389         if (iSum < 0) iSum = 0; else if (iSum > 255) iSum = 255;
390         *pbDest++ = (BYTE)iSum;
391
392         if (g->iBytesPerPixel == 3) {
393             /* copy chrominance values from the center pixel to the output pixel */
394             pbSrc = g->apRows[g->nRows>>1] + (iSideOffset + iSrcOffset + 1);
395             *pbDest++ = *pbSrc++;
396             *pbDest++ = *pbSrc++;
397         }
398
399         iSrcOffset += g->iBytesPerPixel;
400     }
401 }
402
403
404
405 /*****************************************************************************\
406  *
407  * convolve_words - performs convolution on a row pixels with 16 or 48 bits each
408  *
409 \*****************************************************************************/
410
411 static void convolve_words (
412     PCONV_INST g,       /* ptr to our instance variables */
413     PWORD      pwDest)  /* output buffer */
414 {
415     PWORD pwSrc, pwDestAfter;
416     int   iSrcOffset, iSideOffset, iSum;
417     int  *pMatrix;
418     int   row, col;
419
420     pwDestAfter = pwDest + (g->dwBytesPerRow>>1);
421     iSrcOffset = 0;
422     iSideOffset = g->traits.iComponentsPerPixel * (g->nCols>>1);
423
424     while (pwDest < pwDestAfter)   /* for each output pixel ... */
425     {
426         iSum = 0;
427         pMatrix = g->matrix;
428
429         for (row=0; row<g->nRows; row++) {
430             pwSrc = (WORD*)(g->apRows[row]) + iSrcOffset;
431             for (col=0; col<g->nCols; col++) {
432                 iSum += (*pMatrix++) * (int)(unsigned)(*pwSrc);
433                 pwSrc += g->traits.iComponentsPerPixel;
434             }
435         }
436
437         iSum = (iSum + (g->iDivisor>>1)) / g->iDivisor;
438         if (iSum < 0) iSum = 0; else if (iSum > 0x00ffff) iSum = 0x00ffff;
439         *pwDest++ = (WORD)iSum;
440
441         if (g->traits.iComponentsPerPixel == 3) {
442             /* copy chrominance values from the center pixel to the output pixel */
443             pwSrc = (WORD*)(g->apRows[g->nRows>>1]) + (iSideOffset + iSrcOffset + 1);
444             *pwDest++ = *pwSrc++;
445             *pwDest++ = *pwSrc++;
446         }
447
448         iSrcOffset += g->traits.iComponentsPerPixel;
449     }
450 }
451
452
453
454 /*****************************************************************************\
455  *
456  * convolve_convert - Converts one row
457  *
458 \*****************************************************************************/
459
460 FUNC_STATUS WORD convolve_convert (
461     IP_XFORM_HANDLE hXform,
462     DWORD           dwInputAvail,     /* in:  # avail bytes in in-buf */
463     PBYTE           pbInputBuf,       /* in:  ptr to in-buffer */
464     PDWORD          pdwInputUsed,     /* out: # bytes used from in-buf */
465     PDWORD          pdwInputNextPos,  /* out: file-pos to read from next */
466     DWORD           dwOutputAvail,    /* in:  # avail bytes in out-buf */
467     PBYTE           pbOutputBuf,      /* in:  ptr to out-buffer */
468     PDWORD          pdwOutputUsed,    /* out: # bytes written in out-buf */
469     PDWORD          pdwOutputThisPos) /* out: file-pos to write the data */
470 {
471     PCONV_INST g;
472     WORD       wFlags;
473
474     HANDLE_TO_PTR (hXform, g);
475
476     *pdwInputUsed = *pdwOutputUsed = 0;
477     *pdwInputNextPos  = g->dwInNextPos;
478     *pdwOutputThisPos = g->dwOutNextPos;
479     wFlags = 0;
480
481     /**** We'll always consume an input row, so update its vars ****/
482
483     if (pbInputBuf != NULL) {
484         INSURE (dwInputAvail >= g->dwBytesPerRow);
485         *pdwInputUsed     = g->dwBytesPerRow;
486         g->dwInNextPos   += g->dwBytesPerRow;
487         *pdwInputNextPos  = g->dwInNextPos;
488         g->dwRowsRead += 1;
489         wFlags |= IP_CONSUMED_ROW | IP_READY_FOR_DATA;
490     }
491
492     /**** Fill the row-buffers ****/
493
494     if (g->nRowsFilled < g->nRows) {    /* This is the initial fill */
495         INSURE (pbInputBuf != NULL);  /* not allowed to flush now */
496         do {
497             IP_MEM_ALLOC (g->dwBytesPerRow + g->iBytesPerPixel*g->nCols,
498                           g->apRows[g->nRowsFilled]);
499             CopyRow (g, pbInputBuf, g->apRows[g->nRowsFilled]);
500             g->nRowsFilled += 1;
501         } while (g->nRowsFilled < (g->nRows+1)/2);
502
503         if (g->nRowsFilled < g->nRows)
504             return wFlags;  /* we're not done with initial fill */
505     } else {
506         /* rotate buffer-pointers, and copy new row to bottom row */
507         int i;
508         PBYTE pBottomRow;
509
510         if (pbInputBuf == NULL) {
511             /* flushing */
512             if (g->dwRowsRead == g->dwRowsWritten)
513                 return IP_DONE;
514             pbInputBuf = g->apRows[g->nRows-1];  /* duplicate prior row */
515         }
516
517         pBottomRow = g->apRows[0];  /* new bottom row overwrites oldest top row */
518         for (i=1; i<g->nRows; i++)
519             g->apRows[i-1] = g->apRows[i];
520         g->apRows[g->nRows-1] = pBottomRow;
521
522         CopyRow (g, pbInputBuf, pBottomRow);
523     }
524
525     /**** Output a Row ****/
526
527     INSURE (dwOutputAvail >= g->dwBytesPerRow);
528
529     if (g->traits.iBitsPerPixel==8 || g->traits.iBitsPerPixel==24)
530         convolve_bytes (g, pbOutputBuf);
531     else
532         convolve_words (g, (WORD*)pbOutputBuf);
533
534     *pdwOutputUsed    = g->dwBytesPerRow;
535     *pdwOutputThisPos = g->dwOutNextPos;
536     g->dwOutNextPos  += g->dwBytesPerRow;
537     g->dwRowsWritten += 1;
538     wFlags |= IP_PRODUCED_ROW;
539
540     return wFlags;
541
542     fatal_error:
543     return IP_FATAL_ERROR;
544 }
545
546
547
548 /*****************************************************************************\
549  *
550  * convolve_insertedData - client inserted into our output stream
551  *
552 \*****************************************************************************/
553
554 FUNC_STATUS WORD convolve_insertedData (
555     IP_XFORM_HANDLE hXform,
556     DWORD           dwNumBytes)
557 {
558     fatalBreakPoint ();
559     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
560 }
561
562
563
564 /*****************************************************************************\
565  *
566  * convolve_newPage - Tells us to flush this page, and start a new page
567  *
568 \*****************************************************************************/
569
570 FUNC_STATUS WORD convolve_newPage (
571     IP_XFORM_HANDLE hXform)
572 {
573     PCONV_INST g;
574
575     HANDLE_TO_PTR (hXform, g);
576     /* todo: return fatal error if convert is called again? */
577     return IP_DONE;   /* can't insert page-breaks, so ignore this call */
578
579     fatal_error:
580     return IP_FATAL_ERROR;
581
582 }
583
584
585
586 /*****************************************************************************\
587  *
588  * convolve_closeXform - Destroys this instance
589  *
590 \*****************************************************************************/
591
592 FUNC_STATUS WORD convolve_closeXform (IP_XFORM_HANDLE hXform)
593 {
594     PCONV_INST g;
595     int        i;
596
597     HANDLE_TO_PTR (hXform, g);
598
599     /* free any rows that were allocated */
600     for (i=0; i<IP_CONVOLVE_MAXSIZE; i++)
601         if (g->apRows[i] != NULL)
602             IP_MEM_FREE (g->apRows[i]);
603
604     g->dwValidChk = 0;
605     IP_MEM_FREE (g);       /* free memory for the instance */
606
607     return IP_DONE;
608
609     fatal_error:
610     return IP_FATAL_ERROR;
611 }
612
613
614
615 /*****************************************************************************\
616  *
617  * convolveTbl - Jump-table for transform driver
618  *
619 \*****************************************************************************/
620
621 #ifdef EXPORT_TRANSFORM
622 __declspec (dllexport)
623 #endif
624 IP_XFORM_TBL convolveTbl = {
625     convolve_openXform,
626     convolve_setDefaultInputTraits,
627     convolve_setXformSpec,
628     convolve_getHeaderBufSize,
629     convolve_getActualTraits,
630     convolve_getActualBufSizes,
631     convolve_convert,
632     convolve_newPage,
633     convolve_insertedData,
634     convolve_closeXform
635 };
636
637 /* End of File */
638
639
640 /*****************************************************************************\
641  *
642  * ipGetXformTable - Returns pointer to the jump table
643  *
644 \*****************************************************************************/
645
646 #ifdef EXPORT_TRANSFORM
647 EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
648 {
649     WORD wRet = IP_DONE;
650
651     if (pXform)
652         *pXform = clrmapTbl;
653     else
654         wRet = IP_FATAL_ERROR;
655
656     return wRet;
657 }
658 #endif