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