Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpcups / ColorMatcher.cpp
1 /*****************************************************************************\
2   colormatch.cpp : Implimentation for the ColorMatcher class
3
4   Copyright (c) 1996 - 2001, Hewlett-Packard Co.
5   All rights reserved.
6
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10   1. Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15   3. Neither the name of Hewlett-Packard nor the names of its
16      contributors may be used to endorse or promote products derived
17      from this software without specific prior written permission.
18
19   THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
22   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24   TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25   OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \*****************************************************************************/
30
31 #include "CommonDefinitions.h"
32 #include "Processor.h"
33 #include "ColorMatcher.h"
34
35 ColorMatcher::ColorMatcher
36 (
37     ColorMap cm,
38     unsigned int DyeCount,
39     unsigned int iInputWidth
40 ) : ColorPlaneCount(DyeCount),
41     InputWidth(iInputWidth),
42     cmap(cm)
43 {
44     constructor_error = NO_ERROR;
45     ASSERT((cmap.ulMap1 != NULL || cmap.ulMap3 != NULL));
46     StartPlane = K;       // most common case
47
48     if (ColorPlaneCount == 3)     // CMY pen
49     {
50         StartPlane = C;
51     }
52
53     EndPlane = Y;         // most common case
54     if (ColorPlaneCount == 6)
55     {
56         EndPlane = Mlight;
57     }
58     if (ColorPlaneCount == 1)
59     {
60         EndPlane = K;
61     }
62
63     Contone = (BYTE *) new BYTE[InputWidth * ColorPlaneCount];
64     if (Contone == NULL)
65     {
66         goto MemoryError;
67     }
68
69     Restart();  // this zeroes buffers and sets nextraster counter
70
71     return;
72
73 MemoryError:
74     constructor_error=ALLOCMEM_ERROR;
75
76     FreeBuffers();
77     return;
78 } //ColorMatcher
79
80 ColorMatcher::~ColorMatcher()
81 {
82     FreeBuffers();
83 } //~ColorMatcher
84
85
86 void ColorMatcher::Restart()
87 // also reset cache when we have one
88 {
89     memset(Contone, 0, InputWidth*ColorPlaneCount);
90
91     started = false;
92 }
93
94 void ColorMatcher::Flush()
95 // needed to reset cache
96 {
97     if (!started)
98     {
99         return;
100     }
101     Restart();
102 }
103
104 void ColorMatcher::FreeBuffers()
105 {
106     delete [] Contone;
107 }
108
109 bool ColorMatcher::NextOutputRaster(RASTERDATA &next_raster)
110 {
111     if (iRastersReady == 0)
112         return false;
113
114     iRastersReady--;
115     iRastersDelivered++;
116     if (raster.rasterdata[COLORTYPE_COLOR] != NULL)
117     {
118         next_raster.rastersize[COLORTYPE_COLOR] = raster.rastersize[COLORTYPE_COLOR];
119         next_raster.rasterdata[COLORTYPE_COLOR] = Contone;
120     }
121     else
122     {
123         next_raster.rastersize[COLORTYPE_COLOR] = 0;
124         next_raster.rasterdata[COLORTYPE_COLOR] = raster.rasterdata[COLORTYPE_COLOR];
125     }
126     next_raster.rastersize[COLORTYPE_BLACK] = raster.rastersize[COLORTYPE_BLACK];
127     next_raster.rasterdata[COLORTYPE_BLACK] = raster.rasterdata[COLORTYPE_BLACK];
128     return true;
129 }
130
131
132 unsigned int ColorMatcher::GetMaxOutputWidth()
133 {
134     if (myplane == COLORTYPE_COLOR)
135     {
136         if (raster.rasterdata[myplane] == NULL)
137             return 0;
138         else
139             return InputWidth*ColorPlaneCount;
140     }
141     else
142     {
143         return raster.rastersize[myplane];
144     }
145 } //GetMaxOutPutWidth
146
147 void ColorMatcher::ColorMatch
148 (
149     unsigned long width,
150     const uint32_t *map,
151     unsigned char *rgb,
152     unsigned char *kplane,
153     unsigned char *cplane,
154     unsigned char *mplane,
155     unsigned char *yplane
156 )
157 {
158     static      uint32_t    prev_red = 255, prev_green = 255, prev_blue = 255;
159     static      BYTE        bcyan, bmagenta, byellow, bblack;
160
161     uint32_t    r;
162     uint32_t    g;
163     uint32_t    b;
164
165     for (unsigned long i = 0; i < width; i++)
166     {
167         r = *rgb++;
168         g = *rgb++;
169         b = *rgb++;
170
171         if(i == 0 || ( (prev_red != r) || (prev_green != g) || (prev_blue != b) ))
172         {
173             prev_red =   r;
174             prev_green = g;
175             prev_blue =  b;
176
177             Interpolate(map, (BYTE)r, (BYTE)g,(BYTE)b, &bblack, &bcyan, &bmagenta, &byellow);
178         }
179         if (kplane)
180             *(kplane + i) = bblack;
181         if (cplane)
182             *(cplane + i) = bcyan;
183         if (mplane)
184             *(mplane + i) = bmagenta;
185         if (yplane)
186             *(yplane + i) = byellow;
187
188     }
189
190 } //ColorMatch
191
192 void ColorMatcher::ColorMatch
193 (
194     unsigned long width,
195     const unsigned char *map,
196     unsigned char *rgb,
197     unsigned char *kplane,
198     unsigned char *cplane,
199     unsigned char *mplane,
200     unsigned char *yplane
201 )
202 {
203     static      BYTE        prev_red = 255, prev_green = 255, prev_blue = 255;
204     static      BYTE        bcyan, bmagenta, byellow, bblack;
205
206     BYTE    r;
207     BYTE    g;
208     BYTE    b;
209
210     for (unsigned long i = 0; i < width; i++)
211     {
212         r = *rgb++;
213         g = *rgb++;
214         b = *rgb++;
215         if(i == 0 || ( (prev_red != r) || (prev_green != g) || (prev_blue != b) ))
216         {
217             prev_red =   r;
218             prev_green = g;
219             prev_blue =  b;
220
221             Interpolate(map, (BYTE)r, (BYTE)g,(BYTE)b, &bblack, &bcyan, &bmagenta, &byellow);
222         }
223         if (kplane)
224             *(kplane + i) = bblack;
225         if (cplane)
226             *(cplane + i) = bcyan;
227         if (mplane)
228             *(mplane + i) = bmagenta;
229         if (yplane)
230             *(yplane + i) = byellow;
231
232     }
233
234 } //ColorMatch
235
236 uint32_t Packed(unsigned int k,unsigned int c,unsigned int m,unsigned int y)
237 {
238     uint32_t p = y;
239     p = p << 8;
240     p += m;
241     p = p << 8;
242     p += c;
243     p = p << 8;
244     p += k;
245     return p;
246 } //Packed
247
248
249 DRIVER_ERROR ColorMatcher::MakeGrayMap(const uint32_t *colormap, uint32_t* graymap)
250 {
251     unsigned long   ul_MapPtr;
252     for (unsigned int r = 0; r < 9; r++)
253     {
254         unsigned long ul_RedMapPtr = r * 9 * 9;
255         for (unsigned int g = 0; g < 9; g++)
256         {
257             unsigned long ul_GreenMapPtr = g * 9;
258             for (unsigned int b = 0; b < 9; b++)
259             {
260                 unsigned long mapptr = b + (g * 9) + (r * 9 * 9);       // get address in map
261                 ul_MapPtr = b + ul_GreenMapPtr + ul_RedMapPtr;
262                 ASSERT(mapptr == ul_MapPtr);
263                 // put r,g,b in monitor range
264                 unsigned int oldR = r * 255 >> 3;
265                 unsigned int oldG = g * 255 >> 3;
266                 unsigned int oldB = b * 255 >> 3;
267
268                 // calculate gray equivalence
269                 unsigned int gray = ((30 * oldR + 59 * oldG + 11 * oldB + 50) / 100);
270
271                 uint32_t *start;
272                 start = (uint32_t *)
273                         ( ((gray & 0xE0) <<1) + ((gray & 0xE0)>>1) + (gray>>5) +
274                           ((gray & 0xE0) >>2) + (gray>>5) + (gray>>5) + colormap);
275
276                  BYTE k,c,m,y;
277                  Interpolate(start, gray, gray, gray, &k, &c, &m, &y);
278
279                 // second interpolate if Clight/Mlight
280
281                 *(graymap + mapptr) = Packed(k, c, m, y);
282             }
283         }
284     }
285     return NO_ERROR;
286 } //MakeGrayMap
287
288
289 bool ColorMatcher::Process(RASTERDATA* pbyInputKRGBRaster)
290 {
291     if (pbyInputKRGBRaster == NULL || (pbyInputKRGBRaster->rasterdata[COLORTYPE_BLACK] == NULL && pbyInputKRGBRaster->rasterdata[COLORTYPE_COLOR] == NULL))
292     {
293         Restart();
294         return false;   // no output
295     }
296     started=true;
297
298     if (pbyInputKRGBRaster->rasterdata[COLORTYPE_COLOR])
299     {
300         BYTE* buff1 = NULL;
301         BYTE* buff2 = NULL;
302         BYTE* buff3 = NULL;
303         BYTE* buff4 = NULL;
304
305         if (StartPlane == K)
306         {
307             buff1 = Contone;
308             if (EndPlane>K)
309             {
310                 buff2 = buff1 + InputWidth;
311                 buff3 = buff2 + InputWidth;
312                 buff4 = buff3 + InputWidth;
313             }
314         }
315         else
316         {
317             buff2 = Contone;
318             buff3 = buff2 + InputWidth;
319             buff4 = buff3 + InputWidth;
320         }
321
322         if (cmap.ulMap3)
323         {
324             ColorMatch( InputWidth, // ASSUMES ALL INPUTWIDTHS EQUAL
325                 (const unsigned char *) cmap.ulMap3,
326                 pbyInputKRGBRaster->rasterdata[COLORTYPE_COLOR],
327                 buff1,
328                 buff2,
329                 buff3,
330                 buff4
331             );
332         }
333         if (cmap.ulMap1)
334         {
335             // colormatching -- can only handle 4 planes at a time
336             ColorMatch( InputWidth, // ASSUMES ALL INPUTWIDTHS EQUAL
337                 (const uint32_t *) cmap.ulMap1,
338                 pbyInputKRGBRaster->rasterdata[COLORTYPE_COLOR],
339                 buff1,
340                 buff2,
341                 buff3,
342                 buff4
343             );
344         }
345
346         if (EndPlane > Y && cmap.ulMap2)
347         {
348             BYTE* buff5 = buff4 + InputWidth;
349             BYTE* buff6 = buff5 + InputWidth;
350
351             ColorMatch( InputWidth,
352                 (const uint32_t *) cmap.ulMap2,    // 2nd map is for lighter inks
353                 pbyInputKRGBRaster->rasterdata[COLORTYPE_COLOR],
354                 NULL,           // don't need black again
355                 buff5,buff6,
356                 NULL            // don't need yellow again
357             );
358         }
359     }
360
361     iRastersReady = 1;
362     iRastersDelivered = 0;
363     return true;   // one raster in, one raster out
364 }
365
366 #define INTERPOLATE_5_BITS(a, b, d)     a + ( ( ( (long)b - (long)a ) * d) >> 5)
367 #define INTERPOLATE_4_BITS(a, b, d)     a + ( ( ( (long)b - (long)a ) * d) >> 4)
368
369 // Spatial Interpolation
370 #define INTERPOLATE_CUBE(r,g,b, cube, DOCALC) \
371     DOCALC( (DOCALC( (DOCALC( cube[0], cube[4], (r))), \
372                     (DOCALC( cube[2], cube[6], (r))), (g))), \
373             (DOCALC( (DOCALC( cube[1], cube[5], (r))), \
374                     (DOCALC( cube[3], cube[7], (r))), (g))), \
375             (b))
376
377 void ColorMatcher::Interpolate
378 (
379     const uint32_t *map,
380     BYTE r,
381     BYTE g,
382     BYTE b,
383     BYTE *blackout,
384     BYTE *cyanout,
385     BYTE *magentaout,
386     BYTE *yellowout
387 )
388 {
389     static int cube_location[]  = {0, 1,  9, 10,  81,  82,  90,  91 };
390     const uint32_t *start;
391
392     BYTE    cyan[8], magenta[8],yellow[8],black[8];
393     start = (const uint32_t *)
394         (((r & 0xE0) << 1) + ((r & 0xE0) >> 1) + (r >> 5) +
395         ((g & 0xE0) >> 2) + (g >> 5) + (b >> 5) + map);
396
397     uint32_t    cValue;
398     for (int j = 0; j < 8; j++)
399     {
400         cValue = *(start + cube_location[j]);
401         cyan[j]    = GetCyanValue (cValue);
402         magenta[j] = GetMagentaValue (cValue);
403         yellow[j]  = GetYellowValue (cValue);
404         black[j]   = GetBlackValue (cValue);
405     }
406
407     ////////////////this is the 8 bit 9cube operation /////////////
408     BYTE diff_red   = r & 0x1f;
409     BYTE diff_green = g & 0x1f;
410     BYTE diff_blue  = b & 0x1f;
411
412     *cyanout    = INTERPOLATE_CUBE(diff_red,diff_green,diff_blue, cyan, INTERPOLATE_5_BITS );
413     *magentaout = INTERPOLATE_CUBE(diff_red,diff_green,diff_blue, magenta, INTERPOLATE_5_BITS );
414     *yellowout  = INTERPOLATE_CUBE(diff_red,diff_green,diff_blue, yellow, INTERPOLATE_5_BITS );
415     *blackout   = INTERPOLATE_CUBE(diff_red,diff_green,diff_blue, black, INTERPOLATE_5_BITS );
416 }
417
418 void ColorMatcher::Interpolate
419 (
420     const unsigned char *map,
421     BYTE r,
422     BYTE g,
423     BYTE b,
424     BYTE *blackout,
425     BYTE *cyanout,
426     BYTE *magentaout,
427     BYTE *yellowout
428 )
429 {
430     BYTE    cyan[8], magenta[8],yellow[8],black[8];
431
432 //  static int cube_location[]  = {0, 1, 17, 18, 289, 290, 306, 307};
433     static int cube_location[]  = {0, 4, 68, 72, 1156, 1160, 1224, 1228};
434     const   BYTE    *start;
435
436     BYTE *node_ptr;
437
438     start = (const unsigned char *)
439         ((((r & 0xF0) << 4) + ((r & 0xF0) << 1) + (r >> 4) +
440         ((g & 0xF0)) + (g >> 4) + (b >> 4)) * 4 + map);
441
442     // use (start) to determine the surrounding cube values
443     for (int j = 0; j < 8; ++j )
444     {
445         node_ptr = (BYTE *) (start + cube_location[j]);
446         black[j]   = *node_ptr++;
447         cyan[j]    = *node_ptr++;
448         magenta[j] = *node_ptr++;
449         yellow[j]  = *node_ptr;
450     }
451
452
453     // interpolate using the 4 LSBs
454     BYTE diff_red   = r & 0x0f;
455     BYTE diff_green = g & 0x0f;
456     BYTE diff_blue  = b & 0x0f;
457
458     *cyanout    = INTERPOLATE_CUBE(diff_red,diff_green,diff_blue, cyan, INTERPOLATE_4_BITS );
459     *magentaout = INTERPOLATE_CUBE(diff_red,diff_green,diff_blue, magenta, INTERPOLATE_4_BITS );
460     *yellowout  = INTERPOLATE_CUBE(diff_red,diff_green,diff_blue, yellow, INTERPOLATE_4_BITS );
461     *blackout   = INTERPOLATE_CUBE(diff_red,diff_green,diff_blue, black, INTERPOLATE_4_BITS );
462 }
463