/home/liu/actions-runner/_work/ccv/ccv/lib/io/_ccv_io_libjpeg.inc
Line | Count | Source |
1 | | #include <setjmp.h> |
2 | | |
3 | | typedef struct ccv_jpeg_error_mgr_t |
4 | | { |
5 | | struct jpeg_error_mgr pub; |
6 | | jmp_buf setjmp_buffer; |
7 | | } ccv_jpeg_error_mgr_t; |
8 | | |
9 | | METHODDEF(void) error_exit(j_common_ptr cinfo) |
10 | 1 | { |
11 | 1 | ccv_jpeg_error_mgr_t* err_mgr = (ccv_jpeg_error_mgr_t*)(cinfo->err); |
12 | | |
13 | | /* Return control to the setjmp point */ |
14 | 1 | longjmp(err_mgr->setjmp_buffer, 1); |
15 | 1 | } |
16 | | |
17 | | /*************************************************************************** |
18 | | * following code is for supporting MJPEG image files |
19 | | * based on a message of Laurent Pinchart on the video4linux mailing list |
20 | | ***************************************************************************/ |
21 | | |
22 | | /* JPEG DHT Segment for YCrCb omitted from MJPEG data */ |
23 | | static |
24 | | unsigned char _ccv_jpeg_odml_dht[0x1a4] = { |
25 | | 0xff, 0xc4, 0x01, 0xa2, |
26 | | |
27 | | 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, |
28 | | 0x00, 0x00, 0x00, 0x00, 0x00, |
29 | | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, |
30 | | |
31 | | 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
32 | | 0x00, 0x00, 0x00, 0x00, 0x00, |
33 | | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, |
34 | | |
35 | | 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, |
36 | | 0x04, 0x00, 0x00, 0x01, 0x7d, |
37 | | 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, |
38 | | 0x13, 0x51, 0x61, 0x07, |
39 | | 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, |
40 | | 0x15, 0x52, 0xd1, 0xf0, |
41 | | 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, |
42 | | 0x25, 0x26, 0x27, 0x28, |
43 | | 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, |
44 | | 0x46, 0x47, 0x48, 0x49, |
45 | | 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, |
46 | | 0x66, 0x67, 0x68, 0x69, |
47 | | 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, |
48 | | 0x86, 0x87, 0x88, 0x89, |
49 | | 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, |
50 | | 0xa4, 0xa5, 0xa6, 0xa7, |
51 | | 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, |
52 | | 0xc2, 0xc3, 0xc4, 0xc5, |
53 | | 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, |
54 | | 0xd9, 0xda, 0xe1, 0xe2, |
55 | | 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, |
56 | | 0xf5, 0xf6, 0xf7, 0xf8, |
57 | | 0xf9, 0xfa, |
58 | | |
59 | | 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, |
60 | | 0x04, 0x00, 0x01, 0x02, 0x77, |
61 | | 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, |
62 | | 0x51, 0x07, 0x61, 0x71, |
63 | | 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, |
64 | | 0x23, 0x33, 0x52, 0xf0, |
65 | | 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, |
66 | | 0x18, 0x19, 0x1a, 0x26, |
67 | | 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, |
68 | | 0x45, 0x46, 0x47, 0x48, |
69 | | 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, |
70 | | 0x65, 0x66, 0x67, 0x68, |
71 | | 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, |
72 | | 0x84, 0x85, 0x86, 0x87, |
73 | | 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, |
74 | | 0xa2, 0xa3, 0xa4, 0xa5, |
75 | | 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, |
76 | | 0xb9, 0xba, 0xc2, 0xc3, |
77 | | 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, |
78 | | 0xd7, 0xd8, 0xd9, 0xda, |
79 | | 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, |
80 | | 0xf5, 0xf6, 0xf7, 0xf8, |
81 | | 0xf9, 0xfa |
82 | | }; |
83 | | |
84 | | /* |
85 | | * Parse the DHT table. |
86 | | * This code comes from jpeg6b (jdmarker.c). |
87 | | */ |
88 | | static int _ccv_jpeg_load_dht(struct jpeg_decompress_struct *info, unsigned char *dht, JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[]) |
89 | 0 | { |
90 | 0 | unsigned int length = (dht[2] << 8) + dht[3] - 2; |
91 | 0 | unsigned int pos = 4; |
92 | 0 | unsigned int count, i; |
93 | 0 | int index; |
94 | |
|
95 | 0 | JHUFF_TBL **hufftbl; |
96 | 0 | unsigned char bits[17]; |
97 | 0 | unsigned char huffval[256]; |
98 | |
|
99 | 0 | while (length > 16) |
100 | 0 | { |
101 | 0 | bits[0] = 0; |
102 | 0 | index = dht[pos++]; |
103 | 0 | count = 0; |
104 | 0 | for (i = 1; i <= 16; ++i) |
105 | 0 | { |
106 | 0 | bits[i] = dht[pos++]; |
107 | 0 | count += bits[i]; |
108 | 0 | } |
109 | 0 | length -= 17; |
110 | |
|
111 | 0 | if (count > 256 || count > length) |
112 | 0 | return -1; |
113 | | |
114 | 0 | for (i = 0; i < count; ++i) |
115 | 0 | huffval[i] = dht[pos++]; |
116 | 0 | length -= count; |
117 | |
|
118 | 0 | if (index & 0x10) |
119 | 0 | { |
120 | 0 | index -= 0x10; |
121 | 0 | hufftbl = &ac_tables[index]; |
122 | 0 | } |
123 | 0 | else |
124 | 0 | hufftbl = &dc_tables[index]; |
125 | |
|
126 | 0 | if (index < 0 || index >= NUM_HUFF_TBLS) |
127 | 0 | return -1; |
128 | | |
129 | 0 | if (*hufftbl == 0) |
130 | 0 | *hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info); |
131 | 0 | if (*hufftbl == 0) |
132 | 0 | return -1; |
133 | | |
134 | 0 | memcpy((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits); |
135 | 0 | memcpy((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval); |
136 | 0 | } |
137 | | |
138 | 0 | if (length != 0) |
139 | 0 | return -1; |
140 | | |
141 | 0 | return 0; |
142 | 0 | } |
143 | | |
144 | | /*************************************************************************** |
145 | | * end of code for supportting MJPEG image files |
146 | | * based on a message of Laurent Pinchart on the video4linux mailing list |
147 | | ***************************************************************************/ |
148 | | |
149 | | static void _ccv_read_jpeg_fd(FILE* in, ccv_dense_matrix_t** x, int type) |
150 | 4 | { |
151 | 4 | struct jpeg_decompress_struct cinfo; |
152 | 4 | struct ccv_jpeg_error_mgr_t jerr; |
153 | 4 | JSAMPARRAY buffer; |
154 | 4 | int row_stride; |
155 | 4 | cinfo.err = jpeg_std_error(&jerr.pub); |
156 | 4 | jerr.pub.error_exit = error_exit; |
157 | 4 | if (setjmp(jerr.setjmp_buffer)) |
158 | 0 | { |
159 | 0 | jpeg_destroy_decompress(&cinfo); |
160 | 0 | return; |
161 | 0 | } |
162 | 4 | jpeg_create_decompress(&cinfo); |
163 | | |
164 | 4 | jpeg_stdio_src(&cinfo, in); |
165 | | |
166 | 4 | jpeg_read_header(&cinfo, TRUE); |
167 | | |
168 | 4 | ccv_dense_matrix_t* im = *x; |
169 | 4 | if (im == 0) |
170 | 4 | *x = im = ccv_dense_matrix_new(cinfo.image_height, cinfo.image_width, (type) ? type0 : CCV_8U | ((cinfo.num_components > 1) ? CCV_C3 : CCV_C10 ), 0, 0); |
171 | | |
172 | | /* yes, this is a mjpeg image format, so load the correct huffman table */ |
173 | 4 | if (cinfo.ac_huff_tbl_ptrs[0] == 0 && cinfo.ac_huff_tbl_ptrs[1] == 00 && cinfo.dc_huff_tbl_ptrs[0] == 00 && cinfo.dc_huff_tbl_ptrs[1] == 00 ) |
174 | 0 | _ccv_jpeg_load_dht(&cinfo, _ccv_jpeg_odml_dht, cinfo.ac_huff_tbl_ptrs, cinfo.dc_huff_tbl_ptrs); |
175 | | |
176 | 4 | if(cinfo.num_components != 4) |
177 | 2 | { |
178 | 2 | if (cinfo.num_components > 1) |
179 | 2 | { |
180 | 2 | cinfo.out_color_space = JCS_RGB; |
181 | 2 | cinfo.out_color_components = 3; |
182 | 2 | } else { |
183 | 0 | cinfo.out_color_space = JCS_GRAYSCALE; |
184 | 0 | cinfo.out_color_components = 1; |
185 | 0 | } |
186 | 2 | } else { |
187 | 2 | cinfo.out_color_space = JCS_CMYK; |
188 | 2 | cinfo.out_color_components = 4; |
189 | 2 | } |
190 | | |
191 | 4 | jpeg_start_decompress(&cinfo); |
192 | 4 | row_stride = cinfo.output_width * 4; |
193 | 4 | buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); |
194 | | |
195 | 4 | unsigned char* ptr = im->data.u8; |
196 | 4 | int i; |
197 | 4 | int ch = CCV_GET_CHANNEL(im->type); |
198 | 4 | if(cinfo.num_components != 4) |
199 | 2 | { |
200 | 2 | if ((cinfo.num_components > 1 && ch == CCV_C3) || (0 cinfo.num_components == 10 && ch == CCV_C10 )) |
201 | 2 | { |
202 | | /* no format coversion, direct copy */ |
203 | 2 | if (im->cols * ch < im->step) |
204 | 0 | { |
205 | 0 | size_t extra = im->step - im->cols * ch; |
206 | | // empty the padding |
207 | 0 | while (cinfo.output_scanline < cinfo.output_height) |
208 | 0 | { |
209 | 0 | jpeg_read_scanlines(&cinfo, buffer, 1); |
210 | 0 | memcpy(ptr, buffer[0], im->step); |
211 | 0 | memset(ptr + im->cols * ch, 0, extra); |
212 | 0 | ptr += im->step; |
213 | 0 | } |
214 | 2 | } else { |
215 | 1.20k | while (cinfo.output_scanline < cinfo.output_height) |
216 | 1.20k | { |
217 | 1.20k | jpeg_read_scanlines(&cinfo, buffer, 1); |
218 | 1.20k | memcpy(ptr, buffer[0], im->step); |
219 | 1.20k | ptr += im->step; |
220 | 1.20k | } |
221 | 2 | } |
222 | 2 | } else { |
223 | 0 | if (cinfo.num_components > 1 && CCV_GET_CHANNEL(im->type) == CCV_C1) |
224 | 0 | { |
225 | | /* RGB to gray */ |
226 | 0 | while (cinfo.output_scanline < cinfo.output_height) |
227 | 0 | { |
228 | 0 | jpeg_read_scanlines(&cinfo, buffer, 1); |
229 | 0 | unsigned char* g = ptr; |
230 | 0 | unsigned char* rgb = (unsigned char*)buffer[0]; |
231 | 0 | for(i = 0; i < im->cols; i++, rgb += 3, g++) |
232 | 0 | *g = (unsigned char)((rgb[0] * 6969 + rgb[1] * 23434 + rgb[2] * 2365) >> 15); |
233 | 0 | ptr += im->step; |
234 | 0 | } |
235 | 0 | } else if (cinfo.num_components == 1 && CCV_GET_CHANNEL(im->type) == CCV_C3) { |
236 | | /* gray to RGB */ |
237 | 0 | while (cinfo.output_scanline < cinfo.output_height) |
238 | 0 | { |
239 | 0 | jpeg_read_scanlines(&cinfo, buffer, 1); |
240 | 0 | unsigned char* g = (unsigned char*)buffer[0]; |
241 | 0 | unsigned char* rgb = ptr; |
242 | 0 | for(i = 0; i < im->cols; i++, rgb += 3, g++) |
243 | 0 | rgb[0] = rgb[1] = rgb[2] = *g; |
244 | 0 | ptr += im->step; |
245 | 0 | } |
246 | 0 | } |
247 | | // empty out the padding |
248 | 0 | if (im->cols * ch < im->step) |
249 | 0 | { |
250 | 0 | size_t extra = im->step - im->cols * ch; |
251 | 0 | unsigned char* ptr = im->data.u8 + im->cols * ch; |
252 | 0 | for (i = 0; i < im->rows; i++, ptr += im->step) |
253 | 0 | memset(ptr, 0, extra); |
254 | 0 | } |
255 | 0 | } |
256 | 2 | } else { |
257 | 2 | if (CCV_GET_CHANNEL(im->type) == CCV_C1) |
258 | 0 | { |
259 | | /* CMYK to gray */ |
260 | 0 | while (cinfo.output_scanline < cinfo.output_height) |
261 | 0 | { |
262 | 0 | jpeg_read_scanlines(&cinfo, buffer, 1); |
263 | 0 | unsigned char* cmyk = (unsigned char*)buffer[0]; |
264 | 0 | unsigned char* g = ptr; |
265 | 0 | for(i = 0; i < im->cols; i++, g++, cmyk += 4) |
266 | 0 | { |
267 | 0 | int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3]; |
268 | 0 | c = k - ((255 - c) * k >> 8); |
269 | 0 | m = k - ((255 - m) * k >> 8); |
270 | 0 | y = k - ((255 - y) * k >> 8); |
271 | 0 | *g = (unsigned char)((c * 6969 + m * 23434 + y * 2365) >> 15); |
272 | 0 | } |
273 | 0 | ptr += im->step; |
274 | 0 | } |
275 | 2 | } else if (CCV_GET_CHANNEL(im->type) == CCV_C3) { |
276 | | /* CMYK to RGB */ |
277 | 3.49k | while (cinfo.output_scanline < cinfo.output_height) |
278 | 3.49k | { |
279 | 3.49k | jpeg_read_scanlines(&cinfo, buffer, 1); |
280 | 3.49k | unsigned char* cmyk = (unsigned char*)buffer[0]; |
281 | 3.49k | unsigned char* rgb = ptr; |
282 | 8.37M | for(i = 0; i < im->cols; i++, rgb += 3, cmyk += 48.37M ) |
283 | 8.37M | { |
284 | 8.37M | int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3]; |
285 | 8.37M | c = k - ((255 - c) * k >> 8); |
286 | 8.37M | m = k - ((255 - m) * k >> 8); |
287 | 8.37M | y = k - ((255 - y) * k >> 8); |
288 | 8.37M | rgb[0] = (unsigned char)c; |
289 | 8.37M | rgb[1] = (unsigned char)m; |
290 | 8.37M | rgb[2] = (unsigned char)y; |
291 | 8.37M | } |
292 | 3.49k | ptr += im->step; |
293 | 3.49k | } |
294 | 2 | } |
295 | | // empty out the padding |
296 | 2 | if (im->cols * ch < im->step) |
297 | 0 | { |
298 | 0 | size_t extra = im->step - im->cols * ch; |
299 | 0 | unsigned char* ptr = im->data.u8 + im->cols * ch; |
300 | 0 | for (i = 0; i < im->rows; i++, ptr += im->step) |
301 | 0 | memset(ptr, 0, extra); |
302 | 0 | } |
303 | 2 | } |
304 | | |
305 | 4 | jpeg_finish_decompress(&cinfo); |
306 | 4 | jpeg_destroy_decompress(&cinfo); |
307 | 4 | } |
308 | | |
309 | | static int _ccv_write_jpeg_fd(ccv_dense_matrix_t* mat, FILE* fd, void* conf) |
310 | 3 | { |
311 | 3 | struct jpeg_compress_struct cinfo; |
312 | 3 | struct ccv_jpeg_error_mgr_t jerr; |
313 | 3 | jpeg_create_compress(&cinfo); |
314 | 3 | cinfo.err = jpeg_std_error(&jerr.pub); |
315 | 3 | jerr.pub.error_exit = error_exit; |
316 | 3 | jpeg_stdio_dest(&cinfo, fd); |
317 | 3 | if (setjmp(jerr.setjmp_buffer)) |
318 | 1 | { |
319 | 1 | jpeg_destroy_compress(&cinfo); |
320 | 1 | return -1; |
321 | 1 | } |
322 | 2 | cinfo.image_width = mat->cols; |
323 | 2 | cinfo.image_height = mat->rows; |
324 | 2 | cinfo.input_components = (CCV_GET_CHANNEL(mat->type) == CCV_C1) ? 10 : 3; |
325 | 2 | cinfo.in_color_space = (CCV_GET_CHANNEL(mat->type) == CCV_C1) ? JCS_GRAYSCALE0 : JCS_RGB; |
326 | 2 | jpeg_set_defaults(&cinfo); |
327 | 2 | if (conf == 0) |
328 | 3 | jpeg_set_quality(&cinfo, 95, TRUE); |
329 | 18.4E | else |
330 | 18.4E | jpeg_set_quality(&cinfo, *(int*)conf, TRUE); |
331 | 2 | jpeg_start_compress(&cinfo, TRUE); |
332 | 2 | int i; |
333 | 2 | unsigned char* ptr = mat->data.u8; |
334 | 1.25k | for (i = 0; i < mat->rows; i++1.24k ) |
335 | 1.24k | { |
336 | 1.24k | jpeg_write_scanlines(&cinfo, &ptr, 1); |
337 | 1.24k | ptr += mat->step; |
338 | 1.24k | } |
339 | 2 | jpeg_finish_compress(&cinfo); |
340 | 2 | jpeg_destroy_compress(&cinfo); |
341 | 2 | return 0; |
342 | 3 | } |