1 
2 
3 #include "trop.h"
4 
5 // TnzCore includes
6 #include "tpixelgr.h"
7 #include "trandom.h"
8 #include "tpixelutils.h"
9 
10 //******************************************************************
11 //    Conversion functions
12 //******************************************************************
13 
do_convert(const TRaster64P & dst,const TRaster32P & src)14 static void do_convert(const TRaster64P &dst, const TRaster32P &src) {
15   assert(dst->getSize() == src->getSize());
16   int lx = src->getLx();
17   for (int y = 0; y < src->getLy(); y++) {
18     TPixel64 *outPix   = dst->pixels(y);
19     TPixel32 *inPix    = src->pixels(y);
20     TPixel32 *inEndPix = inPix + lx;
21     for (; inPix < inEndPix; ++outPix, ++inPix) {
22       outPix->r = ushortFromByte(inPix->r);
23       outPix->g = ushortFromByte(inPix->g);
24       outPix->b = ushortFromByte(inPix->b);
25       outPix->m = ushortFromByte(inPix->m);
26     }
27   }
28 }
29 
30 //-----------------------------------------------------------------------------
31 
do_convert(const TRasterGR8P & dst,const TRaster32P & src)32 static void do_convert(const TRasterGR8P &dst, const TRaster32P &src) {
33   assert(dst->getSize() == src->getSize());
34 
35   int lx = src->getLx();
36 
37   for (int y = 0; y < src->getLy(); ++y) {
38     TPixelGR8 *outPix = dst->pixels(y);
39     TPixel32 *inPix = src->pixels(y), *inEndPix = inPix + lx;
40 
41     for (; inPix < inEndPix; ++outPix, ++inPix)
42       *outPix = TPixelGR8::from(overPix(TPixel32::White, *inPix));
43   }
44 }
45 
46 //-----------------------------------------------------------------------------
47 
do_convert(const TRasterGR16P & dst,const TRaster32P & src)48 static void do_convert(const TRasterGR16P &dst, const TRaster32P &src) {
49   assert(dst->getSize() == src->getSize());
50 
51   int lx = src->getLx();
52 
53   for (int y = 0; y < src->getLy(); ++y) {
54     TPixelGR16 *outPix = dst->pixels(y);
55     TPixel32 *inPix = src->pixels(y), *inEndPix = inPix + lx;
56 
57     for (; inPix < inEndPix; ++outPix, ++inPix)
58       outPix->value =
59           257 * (TPixelGR8::from(overPix(TPixel32::White, *inPix))).value;
60   }
61 }
62 
63 //-----------------------------------------------------------------------------
64 
do_convert(const TRasterGR16P & dst,const TRaster64P & src)65 static void do_convert(const TRasterGR16P &dst, const TRaster64P &src) {
66   assert(dst->getSize() == src->getSize());
67   int lx = src->getLx();
68   for (int y = 0; y < src->getLy(); y++) {
69     TPixelGR16 *outPix = dst->pixels(y);
70     TPixel64 *inPix    = src->pixels(y);
71     TPixel64 *inEndPix = inPix + lx;
72     while (inPix < inEndPix) {
73       outPix->value = (inPix->r + 2 * inPix->g + inPix->b) >> 2;
74       outPix++;
75       inPix++;
76     }
77   }
78 }
79 
80 //-----------------------------------------------------------------------------
81 
do_convert(const TRaster32P & dst,const TRasterGR8P & src)82 static void do_convert(const TRaster32P &dst, const TRasterGR8P &src) {
83   assert(dst->getSize() == src->getSize());
84   int lx = src->getLx();
85   for (int y = 0; y < src->getLy(); y++) {
86     TPixel32 *outPix    = dst->pixels(y);
87     TPixelGR8 *inPix    = src->pixels(y);
88     TPixelGR8 *inEndPix = inPix + lx;
89     while (inPix < inEndPix) {
90       outPix->r = inPix->value;
91       outPix->g = inPix->value;
92       outPix->b = inPix->value;
93       outPix->m = 0xff;
94       outPix++;
95       inPix++;
96     }
97   }
98 }
99 
100 //-----------------------------------------------------------------------------
101 
102 #define USHORT2BYTE_MAGICFAC (256U * 255U + 1U)
103 
ditherUcharFromUshort(USHORT in,UINT rndNum)104 inline UCHAR ditherUcharFromUshort(USHORT in, UINT rndNum) {
105   return ((((in * USHORT2BYTE_MAGICFAC) - ((in * USHORT2BYTE_MAGICFAC) >> 24)) +
106            rndNum) >>
107           24);
108 }
109 
ditherRgbmFromRgbm64(TPixel32 & out,const TPixel64 & in,TRandom & rnd)110 inline void ditherRgbmFromRgbm64(TPixel32 &out, const TPixel64 &in,
111                                  TRandom &rnd) {
112   UINT randomRound;
113   randomRound = rnd.getUInt() & ((1U << 24) - 1);
114 
115   out.r = ditherUcharFromUshort(in.r, randomRound);
116   out.g = ditherUcharFromUshort(in.g, randomRound);
117   out.b = ditherUcharFromUshort(in.b, randomRound);
118   out.m = ditherUcharFromUshort(in.m, randomRound);
119 }
120 
121 //-----------------------------------------------------------------------------
122 
ditherConvert(TRaster64P inRas,TRaster32P outRas)123 inline void ditherConvert(TRaster64P inRas, TRaster32P outRas) {
124   int inWrap  = inRas->getWrap();
125   int outWrap = outRas->getWrap();
126 
127   TPixel64 *inPix = 0, *inRow = inRas->pixels();
128   TPixel32 *outPix, *outRow   = outRas->pixels();
129   TPixel64 *endPix;
130   int inLx          = inRas->getLx();
131   TPixel64 *lastPix = inRow + inWrap * (inRas->getLy() - 1) + inLx;
132 
133   TRandom rnd(130266);
134 
135   while (inPix < lastPix) {
136     inPix  = inRow;
137     outPix = outRow;
138     endPix = inPix + inLx;
139     while (inPix < endPix) {
140       ditherRgbmFromRgbm64(*outPix, *inPix, rnd);
141       inPix++;
142       outPix++;
143     }
144     inRow += inWrap;
145     outRow += outWrap;
146   }
147 }
148 
149 //******************************************************************
150 //    Obsolete conversion functions
151 //******************************************************************
152 
do_convert(const TRasterCM32P & dst,const TRasterGR8P & src)153 static void do_convert(const TRasterCM32P &dst, const TRasterGR8P &src) {
154   assert(dst->getSize() == src->getSize());
155   TPixelCM32 bg = TPixelCM32(0, 0, TPixelCM32::getMaxTone());
156 
157   int lx = src->getLx();
158   for (int y = 0; y < src->getLy(); y++) {
159     TPixelCM32 *outPix  = dst->pixels(y);
160     TPixelGR8 *inPix    = src->pixels(y);
161     TPixelGR8 *inEndPix = inPix + lx;
162     while (inPix < inEndPix) {
163       *outPix = (inPix->value == 255) ? bg : TPixelCM32(1, 0, inPix->value);
164       outPix++;
165       inPix++;
166     }
167   }
168 }
169 
170 //-----------------------------------------------------------------------------
171 
do_convert(const TRasterCM32P & dst,const TRaster32P & src)172 static void do_convert(const TRasterCM32P &dst, const TRaster32P &src) {
173   assert(dst->getSize() == src->getSize());
174   TPixelCM32 bg = TPixelCM32(0, 0, TPixelCM32::getMaxTone());
175 
176   int lx = src->getLx();
177 
178   bool isOverlay = false;
179 
180   for (int y = 0; y < src->getLy(); y++)  // if it is an overlay, I use the
181                                           // matte value for inks, otherwise I
182                                           // use the brightness.
183   {
184     TPixel32 *inPix    = src->pixels(y);
185     TPixel32 *inEndPix = inPix + lx;
186     while (inPix < inEndPix) {
187       if (inPix->m != 255) {
188         isOverlay = true;
189         break;
190       }
191       inPix++;
192     }
193     if (isOverlay) break;
194   }
195 
196   if (isOverlay)
197     for (int y = 0; y < src->getLy(); y++) {
198       TPixelCM32 *outPix = dst->pixels(y);
199       TPixel32 *inPix    = src->pixels(y);
200       TPixel32 *inEndPix = inPix + lx;
201       while (inPix < inEndPix) {
202         *outPix = (inPix->m == 0) ? bg : TPixelCM32(1, 0, 255 - inPix->m);
203         outPix++;
204         inPix++;
205       }
206     }
207   else
208     for (int y = 0; y < src->getLy(); y++) {
209       TPixelCM32 *outPix = dst->pixels(y);
210       TPixel32 *inPix    = src->pixels(y);
211       TPixel32 *inEndPix = inPix + lx;
212       while (inPix < inEndPix) {
213         UCHAR val = TPixelGR8::from(*inPix).value;
214         *outPix   = (val == 255) ? bg : TPixelCM32(1, 0, val);
215         outPix++;
216         inPix++;
217       }
218     }
219 }
220 
221 //-----------------------------------------------------------------------------
222 
do_convert(const TRasterYUV422P & dst,const TRaster32P & src)223 static void do_convert(const TRasterYUV422P &dst, const TRaster32P &src) {
224   assert(src->getLx() & 0);
225   long y1, y2, u, v, u1, u2, v1, v2;
226   TPixel32 *pix     = (TPixel32 *)src->pixels();
227   TPixel32 *lastPix = &(src->pixels(src->getLy() - 1)[src->getLx() - 1]);
228 
229   UCHAR *out = dst->getRawData();
230 
231   while (pix < lastPix) {
232     /* first pixel gives Y and 0.5 of chroma */
233 
234     y1 = 16829 * pix->r + 33039 * pix->g + 6416 * pix->b;
235     u1 = -4831 * pix->r + -9488 * pix->g + 14319 * pix->b;
236     v1 = 14322 * pix->r + -11992 * pix->g + -2330 * pix->b;
237 
238     /* second pixel gives Y and 0.5 of chroma */
239     ++pix;
240 
241     y2 = 16829 * pix->r + 33039 * pix->g + 6416 * pix->b;
242     u2 = -4831 * pix->r + -9488 * pix->g + 14319 * pix->b;
243     v2 = 14322 * pix->r + -11992 * pix->g + -2330 * pix->b;
244 
245     /* average the chroma */
246     u = u1 + u2;
247     v = v1 + v2;
248 
249     /* round the chroma */
250     u1 = (u + 0x008000) >> 16;
251     v1 = (v + 0x008000) >> 16;
252 
253     /* limit the chroma */
254     if (u1 < -112) u1 = -112;
255     if (u1 > 111) u1  = 111;
256     if (v1 < -112) v1 = -112;
257     if (v1 > 111) v1  = 111;
258 
259     /* limit the lum */
260     if (y1 > 0x00dbffff) y1 = 0x00dbffff;
261     if (y2 > 0x00dbffff) y2 = 0x00dbffff;
262 
263     /* save the results */
264     *out++ = (UCHAR)(u1 + 128);
265     *out++ = (UCHAR)((y1 >> 16) + 16);
266     *out++ = (UCHAR)(v1 + 128);
267     *out++ = (UCHAR)((y2 >> 16) + 16);
268     ++pix;
269   }
270 }
271 
272 //-----------------------------------------------------------------------------
273 
do_convert(const TRaster32P & dst,const TRasterYUV422P & src)274 static void do_convert(const TRaster32P &dst, const TRasterYUV422P &src) {
275   int long r, g, b, y1, y2, u, v;
276   TPixel32 *buf     = dst->pixels();
277   const UCHAR *in   = src->getRawData();
278   const UCHAR *last = in + src->getRowSize() * src->getLy() - 1;
279 
280   while (in < last) {
281     u = *in;
282     u -= 128;
283     in++;
284     y1 = *in;
285     y1 -= 16;
286     in++;
287     v = *in;
288     v -= 128;
289     in++;
290     y2 = *in;
291     y2 -= 16;
292     in++;
293 
294     r                   = 76310 * y1 + 104635 * v;
295     if (r > 0xFFFFFF) r = 0xFFFFFF;
296     if (r <= 0xFFFF) r  = 0;
297 
298     g                   = 76310 * y1 + -25690 * u + -53294 * v;
299     if (g > 0xFFFFFF) g = 0xFFFFFF;
300     if (g <= 0xFFFF) g  = 0;
301 
302     b                   = 76310 * y1 + 132278 * u;
303     if (b > 0xFFFFFF) b = 0xFFFFFF;
304     if (b <= 0xFFFF) b  = 0;
305 
306     buf->r = (UCHAR)(r >> 16);
307     buf->g = (UCHAR)(g >> 16);
308     buf->b = (UCHAR)(b >> 16);
309     buf->m = (UCHAR)255;
310     buf++;
311 
312     r                   = 76310 * y2 + 104635 * v;
313     if (r > 0xFFFFFF) r = 0xFFFFFF;
314     if (r <= 0xFFFF) r  = 0;
315 
316     g                   = 76310 * y2 + -25690 * u + -53294 * v;
317     if (g > 0xFFFFFF) g = 0xFFFFFF;
318     if (g <= 0xFFFF) g  = 0;
319 
320     b                   = 76310 * y2 + 132278 * u;
321     if (b > 0xFFFFFF) b = 0xFFFFFF;
322     if (b <= 0xFFFF) b  = 0;
323 
324     buf->r = (UCHAR)(r >> 16);
325     buf->g = (UCHAR)(g >> 16);
326     buf->b = (UCHAR)(b >> 16);
327     buf->m = (UCHAR)255;
328     buf++;
329   }
330 }
331 
332 //******************************************************************
333 //    Main conversion function
334 //******************************************************************
335 
convert(TRasterP dst,const TRasterP & src)336 void TRop::convert(TRasterP dst, const TRasterP &src) {
337   if (dst->getSize() != src->getSize())
338     throw TRopException("convert: size mismatch");
339 
340   TRaster32P dst32   = dst;
341   TRasterGR8P dst8   = dst;
342   TRasterGR16P dst16 = dst;
343   TRaster64P dst64   = dst;
344   TRasterCM32P dstCm = dst;
345 
346   TRaster32P src32      = src;
347   TRasterGR8P src8      = src;
348   TRaster64P src64      = src;
349   TRasterYUV422P srcYUV = src;
350   TRasterYUV422P dstYUV = dst;
351 
352   src->lock();
353   dst->lock();
354 
355   if (dst64 && src32)
356     do_convert(dst64, src32);
357   else if (dst8 && src32)
358     do_convert(dst8, src32);
359   else if (dst16 && src32)
360     do_convert(dst16, src32);
361   else if (dst32 && src64)
362     ditherConvert(src64, dst32);
363   else if (dst16 && src64)
364     do_convert(dst16, src64);
365   else if (dst32 && src8)
366     do_convert(dst32, src8);
367   else if (dstYUV && src32)
368     do_convert(dstYUV, src32);  // Obsolete conversions
369   else if (dst32 && srcYUV)
370     do_convert(dst32, srcYUV);  //
371   else if (dstCm && src32)
372     do_convert(dstCm, src32);  //
373   else if (dstCm && src8)
374     do_convert(dstCm, src8);  //
375   else {
376     dst->unlock();
377     src->unlock();
378 
379     throw TRopException("unsupported pixel type");
380   }
381 
382   dst->unlock();
383   src->unlock();
384 }
385