1 /*
2  * Small jpeg decoder library
3  *
4  * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
5  * All rights reserved.
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * - Redistributions of source code must retain the above copyright notice,
10  *  this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright notice,
13  *  this list of conditions and the following disclaimer in the documentation
14  *  and/or other materials provided with the distribution.
15  *
16  * - Neither the name of the author nor the names of its contributors may be
17  *  used to endorse or promote products derived from this software without
18  *  specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 
34 /*
35  * yuv420p.c
36  */
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdint.h>
42 
43 #include "tinyjpeg.h"
44 #include "tinyjpeg-internal.h"
45 
46 /*******************************************************************************
47  *
48  * Colorspace conversion routine
49  *
50  *
51  * Note:
52  * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
53  * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
54  * The conversion equations to be implemented are therefore
55  *      R = Y                + 1.40200 * Cr
56  *      G = Y - 0.34414 * Cb - 0.71414 * Cr
57  *      B = Y + 1.77200 * Cb
58  *
59  ******************************************************************************/
60 
61 /**
62  *  YCrCb -> YUV420P (1x1)
63  *  .---.
64  *  | 1 |
65  *  `---'
66  */
YCrCB_to_YUV420P_1x1(struct jdec_private * priv,int sx,int sy)67 static void YCrCB_to_YUV420P_1x1(struct jdec_private *priv, int sx, int sy)
68 {
69   const unsigned char *s, *y;
70   unsigned char *p;
71   int i,j;
72 
73   p = priv->plane[0];
74   y = priv->Y;
75   for (i = sy; i > 0; i--)
76    {
77      memcpy(p, y, sx);
78      p += priv->bytes_per_row[0];
79      y += 8;
80    }
81 
82   p = priv->plane[1];
83   s = priv->Cb;
84   for (i = sy; i > 0; i--)
85    {
86      for (j = sx; j >= 0; j -= 2) {
87        *p++ = *s;
88        s += 2;
89      }
90      s += 8; /* Skip one line */
91      p += priv->bytes_per_row[1] - 4;
92    }
93 
94   p = priv->plane[2];
95   s = priv->Cr;
96   for (i=0; i<8; i+=2)
97    {
98      for (j = sx; j >= 0; j -= 2) {
99        *p++ = *s;
100        s += 2;
101      }
102      s += 8; /* Skip one line */
103      p += priv->bytes_per_row[2] - 4;
104    }
105 }
106 
107 /**
108  *  YCrCb -> YUV420P (2x1)
109  *  .-------.
110  *  | 1 | 2 |
111  *  `-------'
112  */
YCrCB_to_YUV420P_2x1(struct jdec_private * priv,int sx,int sy)113 static void YCrCB_to_YUV420P_2x1(struct jdec_private *priv, int sx, int sy)
114 {
115   unsigned char *p;
116   const unsigned char *s, *y1;
117   unsigned int i;
118 
119   p = priv->plane[0];
120   y1 = priv->Y;
121   for (i = sy; i > 0; i--)
122    {
123      memcpy(p, y1, sx);
124      p += priv->bytes_per_row[0];
125      y1 += 16;
126    }
127 
128   sx = (sx+1) >> 1;
129 
130   p = priv->plane[1];
131   s = priv->Cb;
132   for (i = sy; i > 0; i -= 2)
133    {
134      memcpy(p, s, sx);
135      s += 16; /* Skip one line */
136      p += priv->bytes_per_row[1];
137    }
138 
139   p = priv->plane[2];
140   s = priv->Cr;
141   for (i = sy; i > 0; i -= 2)
142    {
143      memcpy(p, s, sx);
144      s += 16; /* Skip one line */
145      p += priv->bytes_per_row[2];
146    }
147 }
148 
149 
150 /**
151  *  YCrCb -> YUV420P (1x2)
152  *  .---.
153  *  | 1 |
154  *  |---|
155  *  | 2 |
156  *  `---'
157  */
YCrCB_to_YUV420P_1x2(struct jdec_private * priv,int sx,int sy)158 static void YCrCB_to_YUV420P_1x2(struct jdec_private *priv, int sx, int sy)
159 {
160   const unsigned char *s, *y;
161   unsigned char *p, *pr;
162   int i,j;
163 
164   p = priv->plane[0];
165   y = priv->Y;
166   for (i = sy; i > 0; i++)
167    {
168      memcpy(p, y, sx);
169      p+=priv->bytes_per_row[0];
170      y+=8;
171    }
172 
173   pr = priv->plane[1];
174   s = priv->Cb;
175   for (i = sy; i > 0; i -= 2)
176    {
177      p = pr;
178      for (j = sx; j > 0; j -= 2) {
179        *p++ = *s;
180        s += 2;
181      }
182      pr += priv->bytes_per_row[1];
183    }
184 
185   pr = priv->plane[2];
186   s = priv->Cr;
187   for (i=0; i<8; i++)
188    {
189      p = pr;
190      for (j = sx; j > 0; j -= 2) {
191        *p++ = *s;
192        s += 2;
193      }
194      pr += priv->bytes_per_row[2] - 4;
195    }
196 }
197 
198 /**
199  *  YCrCb -> YUV420P (2x2)
200  *  .-------.
201  *  | 1 | 2 |
202  *  |---+---|
203  *  | 3 | 4 |
204  *  `-------'
205  */
YCrCB_to_YUV420P_2x2(struct jdec_private * priv,int sx,int sy)206 static void YCrCB_to_YUV420P_2x2(struct jdec_private *priv, int sx, int sy)
207 {
208   unsigned char *p;
209   const unsigned char *s, *y1;
210   unsigned int i;
211 
212   p = priv->plane[0];
213   y1 = priv->Y;
214   for (i = sy; i > 0; i--)
215    {
216      memcpy(p, y1, sx);
217      p += priv->bytes_per_row[0];
218      y1 += 16;
219    }
220 
221   sx = (sx+1) >> 1;
222 
223   p = priv->plane[1];
224   s = priv->Cb;
225   for (i = sy; i > 0; i -= 2)
226    {
227      memcpy(p, s, sx);
228      s += 8;
229      p += priv->bytes_per_row[1];
230    }
231 
232   p = priv->plane[2];
233   s = priv->Cr;
234   for (i = sy; i > 0; i -= 2)
235    {
236      memcpy(p, s, sx);
237      s += 8;
238      p += priv->bytes_per_row[2];
239    }
240 }
241 
initialize_yuv420p(struct jdec_private * priv,unsigned int * bytes_per_blocklines,unsigned int * bytes_per_mcu)242 static int initialize_yuv420p(struct jdec_private *priv,
243 			      unsigned int *bytes_per_blocklines,
244 			      unsigned int *bytes_per_mcu)
245 {
246   int half_height = (priv->height + 1) >> 2;
247   int half_width  = (priv->width  + 1) >> 2;
248 
249   if (!priv->bytes_per_row[0])
250     priv->bytes_per_row[0] = priv->width;
251   if (!priv->components[0])
252     priv->components[0] = malloc(priv->height * priv->bytes_per_row[0]);
253 
254   if (!priv->bytes_per_row[1])
255     priv->bytes_per_row[1] = half_width;
256   if (!priv->components[1])
257     priv->components[1] = malloc(half_height * priv->bytes_per_row[1]);
258 
259   if (!priv->bytes_per_row[2])
260     priv->bytes_per_row[2] = half_width;
261   if (!priv->components[2])
262     priv->components[2] = malloc(half_height * priv->bytes_per_row[2]);
263 
264   bytes_per_mcu[0] = 8;
265   bytes_per_mcu[1] = 4;
266   bytes_per_mcu[2] = 4;
267 
268   bytes_per_blocklines[0] = priv->width << 3;
269   bytes_per_blocklines[1] = half_width << 2;
270   bytes_per_blocklines[2] = half_width << 2;
271 
272   /* Return nonzero on failure */
273   return !priv->components[0] || !priv->components[1] || !priv->components[2];
274 }
275 
276 static const struct tinyjpeg_colorspace format_yuv420p =
277   {
278     {
279       YCrCB_to_YUV420P_1x1,
280       YCrCB_to_YUV420P_1x2,
281       YCrCB_to_YUV420P_2x1,
282       YCrCB_to_YUV420P_2x2,
283     },
284     tinyjpeg_decode_mcu_3comp_table,
285     initialize_yuv420p
286   };
287 
288 const tinyjpeg_colorspace_t TINYJPEG_FMT_YUV420P = &format_yuv420p;
289