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 * xconvolve.c - convolution using any number or rows and columns up to max
41 ******************************************************************************
43 * Name of Global Jump-Table:
47 * Items in aXformInfo array passed into setXformSpec:
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
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.
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.
61 * This xform makes a copy of the given matrix, so its memory can be freed
62 * after you've called setXformSpec.
64 * IP_CONVOLVE_MAXSIZE is the max number of rows or columns.
66 * Capabilities and Limitations:
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).
72 * Default Input Traits, and Output Traits:
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
85 * Above, a "*" by an item indicates it must be valid (not negative).
87 \******************************************************************************/
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
96 #include "string.h" /* for memset and memcpy */
102 #define PRINT(msg,arg1,arg2) \
103 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
105 #define PRINT(msg,arg1,arg2)
108 #define CHECK_VALUE 0x4ba1dace
110 #ifdef EXPORT_TRANSFORM
111 #define FUNC_STATUS __declspec (dllexport)
113 #define FUNC_STATUS static
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;
135 /*****************************************************************************\
137 * convolve_openXform - Creates a new instance of the transformer
139 *****************************************************************************
141 * This returns a handle for the new instance to be passed into
142 * all subsequent calls.
144 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
146 \*****************************************************************************/
148 FUNC_STATUS WORD convolve_openXform (
149 IP_XFORM_HANDLE *pXform) /* out: returned handle */
153 INSURE (pXform != NULL);
154 IP_MEM_ALLOC (sizeof(CONV_INST), g);
156 memset (g, 0, sizeof(CONV_INST));
157 g->dwValidChk = CHECK_VALUE;
161 return IP_FATAL_ERROR;
166 /*****************************************************************************\
168 * convolve_setDefaultInputTraits - Specifies default input image traits
170 *****************************************************************************
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
177 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
179 \*****************************************************************************/
181 FUNC_STATUS WORD convolve_setDefaultInputTraits (
182 IP_XFORM_HANDLE hXform, /* in: handle for xform */
183 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
189 HANDLE_TO_PTR (hXform, g);
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);
198 g->traits = *pTraits; /* a structure copy */
199 g->iBytesPerPixel = g->traits.iBitsPerPixel / 8;
200 g->dwBytesPerRow = g->traits.iPixelsPerRow * g->iBytesPerPixel;
204 return IP_FATAL_ERROR;
209 /*****************************************************************************\
211 * convolve_setXformSpec - Provides xform-specific information
213 \*****************************************************************************/
215 FUNC_STATUS WORD convolve_setXformSpec (
216 IP_XFORM_HANDLE hXform, /* in: handle for xform */
217 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
222 HANDLE_TO_PTR (hXform, g);
224 g->nRows = aXformInfo[IP_CONVOLVE_NROWS ].dword;
225 g->nCols = aXformInfo[IP_CONVOLVE_NCOLS ].dword;
226 g->iDivisor = aXformInfo[IP_CONVOLVE_DIVISOR].dword;
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);
233 n = g->nRows * g->nCols;
235 g->matrix[i] = ((int*)(aXformInfo[IP_CONVOLVE_MATRIX].pvoid))[i];
240 return IP_FATAL_ERROR;
245 /*****************************************************************************\
247 * convolve_getHeaderBufSize- Returns size of input buf needed to hold header
249 \*****************************************************************************/
251 FUNC_STATUS WORD convolve_getHeaderBufSize (
252 IP_XFORM_HANDLE hXform, /* in: handle for xform */
253 DWORD *pdwInBufLen) /* out: buf size for parsing header */
255 /* since input is raw pixels, there is no header, so set it to zero */
262 /*****************************************************************************\
264 * convolve_getActualTraits - Parses header, and returns input & output traits
266 \*****************************************************************************/
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 */
279 HANDLE_TO_PTR (hXform, g);
281 /* Since there is no header, we'll report no usage of input */
283 *pdwInputNextPos = 0;
285 *pIntraits = g->traits; /* structure copies */
286 *pOutTraits = g->traits;
288 return IP_DONE | IP_READY_FOR_DATA;
291 return IP_FATAL_ERROR;
296 /****************************************************************************\
298 * convolve_getActualBufSizes - Returns buf sizes needed for remainder of job
300 \****************************************************************************/
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 */
309 HANDLE_TO_PTR (hXform, g);
311 *pdwMinInBufLen = *pdwMinOutBufLen = g->dwBytesPerRow;
315 return IP_FATAL_ERROR;
320 /*****************************************************************************\
322 * CopyRow - Copies row to row-buffer, filling over-run zone on sides
324 \*****************************************************************************/
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) */
334 nSidePixels = g->nCols / 2;
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;
342 /* copy the buffer */
343 memcpy (pbDest, pbSrc, g->dwBytesPerRow);
344 pbDest += g->dwBytesPerRow;
345 pbSrc += g->dwBytesPerRow - g->iBytesPerPixel; /* leave at rightmost pixel */
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;
356 /*****************************************************************************\
358 * convolve_bytes - performs convolution on a row pixels with 8 or 24 bits each
360 \*****************************************************************************/
362 static void convolve_bytes (
363 PCONV_INST g, /* ptr to our instance variables */
364 PBYTE pbDest) /* output buffer */
366 PBYTE pbSrc, pbDestAfter;
367 int iSrcOffset, iSideOffset, iSum;
371 pbDestAfter = pbDest + g->dwBytesPerRow;
373 iSideOffset = g->iBytesPerPixel * (g->nCols>>1);
375 while (pbDest < pbDestAfter) /* for each output pixel ... */
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;
388 iSum = (iSum + (g->iDivisor>>1)) / g->iDivisor;
389 if (iSum < 0) iSum = 0; else if (iSum > 255) iSum = 255;
390 *pbDest++ = (BYTE)iSum;
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++;
399 iSrcOffset += g->iBytesPerPixel;
405 /*****************************************************************************\
407 * convolve_words - performs convolution on a row pixels with 16 or 48 bits each
409 \*****************************************************************************/
411 static void convolve_words (
412 PCONV_INST g, /* ptr to our instance variables */
413 PWORD pwDest) /* output buffer */
415 PWORD pwSrc, pwDestAfter;
416 int iSrcOffset, iSideOffset, iSum;
420 pwDestAfter = pwDest + (g->dwBytesPerRow>>1);
422 iSideOffset = g->traits.iComponentsPerPixel * (g->nCols>>1);
424 while (pwDest < pwDestAfter) /* for each output pixel ... */
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;
437 iSum = (iSum + (g->iDivisor>>1)) / g->iDivisor;
438 if (iSum < 0) iSum = 0; else if (iSum > 0x00ffff) iSum = 0x00ffff;
439 *pwDest++ = (WORD)iSum;
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++;
448 iSrcOffset += g->traits.iComponentsPerPixel;
454 /*****************************************************************************\
456 * convolve_convert - Converts one row
458 \*****************************************************************************/
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 */
474 HANDLE_TO_PTR (hXform, g);
476 *pdwInputUsed = *pdwOutputUsed = 0;
477 *pdwInputNextPos = g->dwInNextPos;
478 *pdwOutputThisPos = g->dwOutNextPos;
481 /**** We'll always consume an input row, so update its vars ****/
483 if (pbInputBuf != NULL) {
484 INSURE (dwInputAvail >= g->dwBytesPerRow);
485 *pdwInputUsed = g->dwBytesPerRow;
486 g->dwInNextPos += g->dwBytesPerRow;
487 *pdwInputNextPos = g->dwInNextPos;
489 wFlags |= IP_CONSUMED_ROW | IP_READY_FOR_DATA;
492 /**** Fill the row-buffers ****/
494 if (g->nRowsFilled < g->nRows) { /* This is the initial fill */
495 INSURE (pbInputBuf != NULL); /* not allowed to flush now */
497 IP_MEM_ALLOC (g->dwBytesPerRow + g->iBytesPerPixel*g->nCols,
498 g->apRows[g->nRowsFilled]);
499 CopyRow (g, pbInputBuf, g->apRows[g->nRowsFilled]);
501 } while (g->nRowsFilled < (g->nRows+1)/2);
503 if (g->nRowsFilled < g->nRows)
504 return wFlags; /* we're not done with initial fill */
506 /* rotate buffer-pointers, and copy new row to bottom row */
510 if (pbInputBuf == NULL) {
512 if (g->dwRowsRead == g->dwRowsWritten)
514 pbInputBuf = g->apRows[g->nRows-1]; /* duplicate prior row */
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;
522 CopyRow (g, pbInputBuf, pBottomRow);
525 /**** Output a Row ****/
527 INSURE (dwOutputAvail >= g->dwBytesPerRow);
529 if (g->traits.iBitsPerPixel==8 || g->traits.iBitsPerPixel==24)
530 convolve_bytes (g, pbOutputBuf);
532 convolve_words (g, (WORD*)pbOutputBuf);
534 *pdwOutputUsed = g->dwBytesPerRow;
535 *pdwOutputThisPos = g->dwOutNextPos;
536 g->dwOutNextPos += g->dwBytesPerRow;
537 g->dwRowsWritten += 1;
538 wFlags |= IP_PRODUCED_ROW;
543 return IP_FATAL_ERROR;
548 /*****************************************************************************\
550 * convolve_insertedData - client inserted into our output stream
552 \*****************************************************************************/
554 FUNC_STATUS WORD convolve_insertedData (
555 IP_XFORM_HANDLE hXform,
559 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
564 /*****************************************************************************\
566 * convolve_newPage - Tells us to flush this page, and start a new page
568 \*****************************************************************************/
570 FUNC_STATUS WORD convolve_newPage (
571 IP_XFORM_HANDLE hXform)
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 */
580 return IP_FATAL_ERROR;
586 /*****************************************************************************\
588 * convolve_closeXform - Destroys this instance
590 \*****************************************************************************/
592 FUNC_STATUS WORD convolve_closeXform (IP_XFORM_HANDLE hXform)
597 HANDLE_TO_PTR (hXform, g);
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]);
605 IP_MEM_FREE (g); /* free memory for the instance */
610 return IP_FATAL_ERROR;
615 /*****************************************************************************\
617 * convolveTbl - Jump-table for transform driver
619 \*****************************************************************************/
621 #ifdef EXPORT_TRANSFORM
622 __declspec (dllexport)
624 IP_XFORM_TBL convolveTbl = {
626 convolve_setDefaultInputTraits,
627 convolve_setXformSpec,
628 convolve_getHeaderBufSize,
629 convolve_getActualTraits,
630 convolve_getActualBufSizes,
633 convolve_insertedData,
640 /*****************************************************************************\
642 * ipGetXformTable - Returns pointer to the jump table
644 \*****************************************************************************/
646 #ifdef EXPORT_TRANSFORM
647 EXPORT(WORD) ipGetXformTable (LPIP_XFORM_TBL pXform)
654 wRet = IP_FATAL_ERROR;