Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xchgbpp.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  * xchangeBPP.c - Changes bits per pixel
40  *
41  ******************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    changeBPPTbl
46  *
47  * Items in aXformInfo array passed into setXformSpec:
48  *
49  *    aXformInfo[IP_CHANGE_BPP_OUTPUT_BPP] = bits/pixel to output
50  *
51  * Capabilities and Limitations:
52  *
53  *    1 bpp is assumed to be bilevel (0=white, 1=black).
54  *    8 and 16 bpp are assumed to be grayscale.
55  *    24 and 48 bpp are assumed to be 3-component color (rgb is assumed when
56  *    we convert from color into grayscale).
57  *    Among the above supported bpp values, any bpp can be changed into any
58  *    other bpp.  Changing into bi-level (bpp=1) performs simple thresholding.
59  *    Use xgray2bi if you want error-diffusion.
60  *    If the input and output bpp values are the same, this xform merely passes
61  *    the pixels through unexamined.
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         * anything             changed as specified
69  *    iComponentsPerPixel   * 1 or 3               can be changed to 3
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  * Mar 1998 Mark Overton -- wrote code (for 1 -> 8/24 only)
79  * Apr 2000 Mark Overton -- generalized as a change-BPP xform
80  *
81 \******************************************************************************/
82
83 #include "hpip.h"
84 #include "ipdefs.h"
85 #include "string.h"    /* for memset and memcpy */
86 #include "assert.h"
87
88
89 #if 0
90     #include "stdio.h"
91     #include <tchar.h>
92
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 0x1ce5ca7e
100
101 typedef struct {
102     IP_IMAGE_TRAITS inTraits;  /* traits of the input image */
103     UINT     uRowsDone;        /* number of rows converted so far */
104     WORD     wOutBitsPerPixel; /* bits/pixel to output */
105     DWORD    dwInRowBytes;     /* # bytes per input row */
106     DWORD    dwOutRowBytes;    /* # bytes per output row */
107     DWORD    dwInNextPos;      /* file pos for subsequent input */
108     DWORD    dwOutNextPos;     /* file pos for subsequent output */
109     DWORD    dwValidChk;       /* struct validity check value */
110 } CBPP_INST, *PCBPP_INST;
111
112
113
114 /*****************************************************************************\
115  *
116  * changeBPP_openXform - Creates a new instance of the transformer
117  *
118  *****************************************************************************
119  *
120  * This returns a handle for the new instance to be passed into
121  * all subsequent calls.
122  *
123  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
124  *
125 \*****************************************************************************/
126
127 static WORD changeBPP_openXform (
128     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
129 {
130     PCBPP_INST g;
131
132     INSURE (pXform != NULL);
133     IP_MEM_ALLOC (sizeof(CBPP_INST), g);
134     *pXform = g;
135     memset (g, 0, sizeof(CBPP_INST));
136     g->dwValidChk = CHECK_VALUE;
137     return IP_DONE;
138
139     fatal_error:
140     return IP_FATAL_ERROR;
141 }
142
143
144
145 /*****************************************************************************\
146  *
147  * changeBPP_setDefaultInputTraits - Specifies default input image traits
148  *
149  *****************************************************************************
150  *
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
154  * this routine.
155  *
156  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
157  *
158 \*****************************************************************************/
159
160 static WORD changeBPP_setDefaultInputTraits (
161     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
162     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
163 {
164     PCBPP_INST g;
165     int        bpp;
166
167     HANDLE_TO_PTR (hXform, g);
168
169     /* Insure that values we care about are correct */
170     bpp = pTraits->iBitsPerPixel;
171     INSURE (bpp==1 || bpp==8 || bpp==16 || bpp==24 || bpp==48);
172     INSURE (pTraits->iComponentsPerPixel==1 || pTraits->iComponentsPerPixel==3);
173     INSURE (pTraits->iPixelsPerRow > 0);
174
175     g->inTraits = *pTraits;   /* a structure copy */
176     return IP_DONE;
177
178     fatal_error:
179     return IP_FATAL_ERROR;
180 }
181
182
183
184 /*****************************************************************************\
185  *
186  * changeBPP_setXformSpec - Provides xform-specific information
187  *
188 \*****************************************************************************/
189
190 static WORD changeBPP_setXformSpec (
191     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
192     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
193 {
194     PCBPP_INST g;
195     UINT       nBits;
196
197     HANDLE_TO_PTR (hXform, g);
198     nBits = aXformInfo[IP_CHANGE_BPP_OUTPUT_BPP].dword;
199     g->wOutBitsPerPixel = (WORD)nBits;
200     return IP_DONE;
201
202     fatal_error:
203     return IP_FATAL_ERROR;
204 }
205
206
207
208 /*****************************************************************************\
209  *
210  * changeBPP_getHeaderBufSize- Returns size of input buf needed to hold header
211  *
212 \*****************************************************************************/
213
214 static WORD changeBPP_getHeaderBufSize (
215     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
216     DWORD           *pdwInBufLen)    /* out: buf size for parsing header */
217 {
218     /* since input is raw pixels, there is no header, so set it to zero */
219     *pdwInBufLen = 0;
220     return IP_DONE;
221 }
222
223
224
225 /*****************************************************************************\
226  *
227  * changeBPP_getActualTraits - Parses header, and returns input & output traits
228  *
229 \*****************************************************************************/
230
231 static WORD changeBPP_getActualTraits (
232     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
233     DWORD            dwInputAvail,   /* in:  # avail bytes in input buf */
234     PBYTE            pbInputBuf,     /* in:  ptr to input buffer */
235     PDWORD           pdwInputUsed,   /* out: # bytes used from input buf */
236     PDWORD           pdwInputNextPos,/* out: file-pos to read from next */
237     PIP_IMAGE_TRAITS pInTraits,      /* out: input image traits */
238     PIP_IMAGE_TRAITS pOutTraits)     /* out: output image traits */
239 {
240     PCBPP_INST g;
241
242     HANDLE_TO_PTR (hXform, g);
243
244     /* Since there is no header, we'll report no usage of input */
245     *pdwInputUsed    = 0;
246     *pdwInputNextPos = 0;
247
248     *pInTraits  = g->inTraits;   /* structure copies */
249     *pOutTraits = g->inTraits;
250     pOutTraits->iBitsPerPixel       = g->wOutBitsPerPixel;
251     pOutTraits->iComponentsPerPixel = g->wOutBitsPerPixel<24 ? 1 : 3;
252
253     g->dwInRowBytes  = (g->inTraits.iPixelsPerRow*g->inTraits.iBitsPerPixel + 7) / 8;
254     g->dwOutRowBytes = (g->inTraits.iPixelsPerRow*g->wOutBitsPerPixel       + 7) / 8;
255
256     return IP_DONE | IP_READY_FOR_DATA;
257
258     fatal_error:
259     return IP_FATAL_ERROR;
260 }
261
262
263
264 /****************************************************************************\
265  *
266  * changeBPP_getActualBufSizes - Returns buf sizes needed for remainder of job
267  *
268 \****************************************************************************/
269
270 static WORD changeBPP_getActualBufSizes (
271     IP_XFORM_HANDLE hXform,            /* in:  handle for xform */
272     PDWORD           pdwMinInBufLen,   /* out: min input buf size */
273     PDWORD           pdwMinOutBufLen)  /* out: min output buf size */
274 {
275     PCBPP_INST g;
276
277     HANDLE_TO_PTR (hXform, g);
278     *pdwMinInBufLen  = g->dwInRowBytes;
279     *pdwMinOutBufLen = g->dwOutRowBytes;
280
281     return IP_DONE;
282
283     fatal_error:
284     return IP_FATAL_ERROR;
285 }
286
287
288
289 /*****************************************************************************\
290  *
291  * changeBPP_convert - Converts one row
292  *
293 \*****************************************************************************/
294
295 static WORD changeBPP_convert (
296     IP_XFORM_HANDLE hXform,
297     DWORD           dwInputAvail,      /* in:  # avail bytes in in-buf */
298     PBYTE           pbInputBuf,        /* in:  ptr to in-buffer */
299     PDWORD          pdwInputUsed,      /* out: # bytes used from in-buf */
300     PDWORD          pdwInputNextPos,   /* out: file-pos to read from next */
301     DWORD           dwOutputAvail,     /* in:  # avail bytes in out-buf */
302     PBYTE           pbOutputBuf,       /* in:  ptr to out-buffer */
303     PDWORD          pdwOutputUsed,     /* out: # bytes written in out-buf */
304     PDWORD          pdwOutputThisPos)  /* out: file-pos to write the data */
305 {
306     PCBPP_INST g;
307     PBYTE     pIn, pOut, pInAfter;
308     unsigned  rv, gv, bv;
309     BYTE      bMask, bBilevel;
310     BYTE      bPixels;
311     WORD      wPixels;
312     DWORD     dwPixels;
313
314     #define OUTPUT_THRESHOLDED_BIT(grayParam) {        \
315         int gray = grayParam;                        \
316         if (gray < 128) bBilevel |= bMask;            \
317         bMask >>= 1;                                \
318         if (bMask == 0) {                            \
319             *pOut++ = (BYTE)bBilevel;                \
320             bBilevel = 0;                            \
321             bMask = (BYTE)0x80;                        \
322         }                                            \
323     }
324
325     HANDLE_TO_PTR (hXform, g);
326
327     /**** Check if we were told to flush ****/
328
329     if (pbInputBuf == NULL) {
330         PRINT (_T("changeBPP_convert: Told to flush.\n"), 0, 0);
331         *pdwInputUsed     = *pdwOutputUsed = 0;
332         *pdwInputNextPos  = g->dwInNextPos;
333         *pdwOutputThisPos = g->dwOutNextPos;
334         return IP_DONE;
335     }
336
337     /**** Output a Row ****/
338
339     INSURE (dwInputAvail  >= g->dwInRowBytes );
340     INSURE (dwOutputAvail >= g->dwOutRowBytes);
341
342     bMask = 0x80;
343     bBilevel = 0;
344
345     pIn  = pbInputBuf;
346     pOut = pbOutputBuf;
347     pInAfter = pIn + g->dwInRowBytes;
348
349     if (g->inTraits.iBitsPerPixel == g->wOutBitsPerPixel) {
350         /* no change in bpp; just copy the buffer */
351         memcpy (pOut, pIn, g->dwInRowBytes);
352     } else if (g->inTraits.iBitsPerPixel == 1) {
353         while (pIn < pInAfter) {
354             bBilevel = *pIn++;
355
356             if (g->wOutBitsPerPixel == 48) {
357                 for (bMask=0x80u; bMask!=0; bMask>>=1) {
358                     dwPixels = (bMask & bBilevel)
359                                  ? 0            /* black */
360                                  : 0xffffffff;  /* white */
361                     *(DWORD*)pOut    = dwPixels;
362                     *(WORD*)(pOut+4) = (WORD)dwPixels;
363                     pOut += 6;
364                 }
365             } else if (g->wOutBitsPerPixel == 24) {
366                 for (bMask=0x80u; bMask!=0; bMask>>=1) {
367                     *(DWORD*)pOut = (bMask & bBilevel)
368                                  ? 0            /* black */
369                                  : 0xffffffff;  /* white */
370                     pOut += 3;
371                 }
372             } else if (g->wOutBitsPerPixel == 16) {
373                 for (bMask=0x80u; bMask!=0; bMask>>=1) {
374                     *(WORD*)pOut = (bMask & bBilevel)
375                                  ? 0        /* black */
376                                  : 0xffff;  /* white */
377                     pOut += 2;
378                 }
379             } else if (g->wOutBitsPerPixel == 8) {
380                 for (bMask=0x80u; bMask!=0; bMask>>=1) {
381                     *pOut++ = (bMask & bBilevel)
382                                  ? 0      /* black */
383                                  : 0xff;  /* white */
384                 }
385             } else
386                 assert (0);
387         }
388     }
389     else if (g->inTraits.iBitsPerPixel == 8) {
390         if (g->wOutBitsPerPixel == 48) {
391             while (pIn < pInAfter) {
392                 wPixels = (*pIn++ << 8);
393                 *(WORD*)(pOut+0) = wPixels;
394                 *(WORD*)(pOut+2) = wPixels;
395                 *(WORD*)(pOut+4) = wPixels;
396                 pOut += 6;
397             }
398         } else if (g->wOutBitsPerPixel == 24) {
399             while (pIn < pInAfter) {
400                 bPixels = *pIn++;
401                 *pOut++ = bPixels;
402                 *pOut++ = bPixels;
403                 *pOut++ = bPixels;
404             }
405         } else if (g->wOutBitsPerPixel == 16) {
406             while (pIn < pInAfter) {
407                 wPixels = (*pIn++ << 8);
408                 *(WORD*)pOut = wPixels;
409                 pOut += 2;
410             }
411         } else if (g->wOutBitsPerPixel == 1) {
412             while (pIn < pInAfter) {
413                 OUTPUT_THRESHOLDED_BIT (*pIn);
414                 pIn++;
415             }
416         } else
417             assert (0);
418     }
419     else if (g->inTraits.iBitsPerPixel == 16) {
420         if (g->wOutBitsPerPixel == 48) {
421             while (pIn < pInAfter) {
422                 wPixels = *(WORD*)pIn;
423                 *(WORD*)(pOut+0) = wPixels;
424                 *(WORD*)(pOut+2) = wPixels;
425                 *(WORD*)(pOut+4) = wPixels;
426                 pIn  += 2;
427                 pOut += 6;
428             }
429         } else if (g->wOutBitsPerPixel == 24) {
430             while (pIn < pInAfter) {
431                 bPixels = (*(WORD*)pIn) >> 8;
432                 pIn += 2;
433                 *pOut++ = bPixels;
434                 *pOut++ = bPixels;
435                 *pOut++ = bPixels;
436             }
437         } else if (g->wOutBitsPerPixel == 8) {
438             while (pIn < pInAfter) {
439                 *pOut++ = (*(WORD*)pIn) >> 8;
440                 pIn += 2;
441             }
442         } else if (g->wOutBitsPerPixel == 1) {
443             while (pIn < pInAfter) {
444                 OUTPUT_THRESHOLDED_BIT ((*(WORD*)pIn) >> 8);
445                 pIn += 2;
446             }
447         } else
448             assert (0);
449     }
450     else if (g->inTraits.iBitsPerPixel == 24) {
451         if (g->wOutBitsPerPixel == 48) {
452             while (pIn < pInAfter) {
453                 *(WORD*)(pOut+0) = (WORD)(*pIn++) << 8;
454                 *(WORD*)(pOut+2) = (WORD)(*pIn++) << 8;
455                 *(WORD*)(pOut+4) = (WORD)(*pIn++) << 8;
456                 pOut += 6;
457             }
458         } else if (g->wOutBitsPerPixel == 16) {
459             /* converting rgb color (24) to grayscale (16) */
460             while (pIn < pInAfter) {
461                 rv = (*pIn++) << 8;
462                 gv = (*pIn++) << 8;
463                 bv = (*pIn++) << 8;
464                 *(WORD*)pOut = NTSC_LUMINANCE (rv, gv, bv);
465                 pOut += 2;
466             }
467         } else if (g->wOutBitsPerPixel == 8) {
468             /* converting rgb color (24) to grayscale (8) */
469             while (pIn < pInAfter) {
470                 rv = *pIn++;
471                 gv = *pIn++;
472                 bv = *pIn++;
473                 *pOut++ = NTSC_LUMINANCE (rv, gv, bv);
474             }
475         } else if (g->wOutBitsPerPixel == 1) {
476             /* converting rgb color (24) to bi-level */
477             while (pIn < pInAfter) {
478                 rv = *pIn++;
479                 gv = *pIn++;
480                 bv = *pIn++;
481                 OUTPUT_THRESHOLDED_BIT (NTSC_LUMINANCE(rv,gv,bv));
482             }
483         } else
484             assert (0);
485     }
486     else if (g->inTraits.iBitsPerPixel == 48) {
487         if (g->wOutBitsPerPixel == 24) {
488             while (pIn < pInAfter) {
489                 *pOut++ = ((WORD*)pIn)[0] >> 8;
490                 *pOut++ = ((WORD*)pIn)[1] >> 8;
491                 *pOut++ = ((WORD*)pIn)[2] >> 8;
492                 pIn += 6;
493             }
494         } else if (g->wOutBitsPerPixel == 16) {
495             /* converting rgb color (48) to grayscale (16) */
496             while (pIn < pInAfter) {
497                 rv = ((WORD*)pIn)[0];
498                 gv = ((WORD*)pIn)[1];
499                 bv = ((WORD*)pIn)[2];
500                 *(WORD*)pOut = NTSC_LUMINANCE (rv, gv, bv);
501                 pIn  += 6;
502                 pOut += 2;
503             }
504         } else if (g->wOutBitsPerPixel == 8) {
505             /* converting rgb color (48) to grayscale (8) */
506             while (pIn < pInAfter) {
507                 rv = ((WORD*)pIn)[0];
508                 gv = ((WORD*)pIn)[1];
509                 bv = ((WORD*)pIn)[2];
510                 *pOut++ = NTSC_LUMINANCE (rv, gv, bv) >> 8;
511                 pIn += 6;
512             }
513         } else if (g->wOutBitsPerPixel == 1) {
514             /* converting rgb color (48) to bi-level */
515             while (pIn < pInAfter) {
516                 rv = ((WORD*)pIn)[0];
517                 gv = ((WORD*)pIn)[1];
518                 bv = ((WORD*)pIn)[2];
519                 OUTPUT_THRESHOLDED_BIT (NTSC_LUMINANCE(rv,gv,bv) >> 8);
520                 pIn += 6;
521             }
522         } else
523             assert (0);
524     }
525
526     if (g->inTraits.iBitsPerPixel>1 && g->wOutBitsPerPixel==1 && bMask!=(BYTE)0x80)
527         *pOut = bBilevel;   /* output any partially-filled byte */
528
529     *pdwInputUsed     = g->dwInRowBytes;
530     g->dwInNextPos   += g->dwInRowBytes;
531     *pdwInputNextPos  = g->dwInNextPos;
532
533     *pdwOutputUsed    = g->dwOutRowBytes;
534     *pdwOutputThisPos = g->dwOutNextPos;
535     g->dwOutNextPos  += g->dwOutRowBytes;
536
537     g->uRowsDone += 1;
538
539     return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
540
541     fatal_error:
542     return IP_FATAL_ERROR;
543 }
544
545
546
547 /*****************************************************************************\
548  *
549  * changeBPP_insertedData - client inserted into our output stream
550  *
551 \*****************************************************************************/
552
553 static WORD changeBPP_insertedData (
554     IP_XFORM_HANDLE hXform,
555     DWORD           dwNumBytes)
556 {
557     fatalBreakPoint ();
558     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
559 }
560
561
562
563 /*****************************************************************************\
564  *
565  * changeBPP_newPage - Tells us to flush this page, and start a new page
566  *
567 \*****************************************************************************/
568
569 static WORD changeBPP_newPage (
570     IP_XFORM_HANDLE hXform)
571 {
572     PCBPP_INST g;
573
574     HANDLE_TO_PTR (hXform, g);
575     /* todo: return fatal error if convert is called again? */
576     return IP_DONE;   /* can't insert page-breaks, so ignore this call */
577
578     fatal_error:
579     return IP_FATAL_ERROR;
580
581 }
582
583
584
585 /*****************************************************************************\
586  *
587  * changeBPP_closeXform - Destroys this instance
588  *
589 \*****************************************************************************/
590
591 static WORD changeBPP_closeXform (IP_XFORM_HANDLE hXform)
592 {
593     PCBPP_INST g;
594
595     HANDLE_TO_PTR (hXform, g);
596
597     g->dwValidChk = 0;
598     IP_MEM_FREE (g);       /* free memory for the instance */
599
600     return IP_DONE;
601
602     fatal_error:
603     return IP_FATAL_ERROR;
604 }
605
606
607
608 /*****************************************************************************\
609  *
610  * changeBPPTbl - Jump-table for xform
611  *
612 \*****************************************************************************/
613
614 IP_XFORM_TBL changeBPPTbl = {
615     changeBPP_openXform,
616     changeBPP_setDefaultInputTraits,
617     changeBPP_setXformSpec,
618     changeBPP_getHeaderBufSize,
619     changeBPP_getActualTraits,
620     changeBPP_getActualBufSizes,
621     changeBPP_convert,
622     changeBPP_newPage,
623     changeBPP_insertedData,
624     changeBPP_closeXform
625 };
626
627 /* End of File */