Add ability to unpack JPEG
[phoros.git] / imread.c
blob9e8e4b9e06f8be41f32c56ce3312fb423db2613b
1 /* PHOROS -- Photogrammetric Road Survey */
2 /* Copyright (C) 2016, 2017 Bert Burgemeister */
4 /* This program is free software; you can redistribute it and/or modify */
5 /* it under the terms of the GNU General Public License as published by */
6 /* the Free Software Foundation; either version 2 of the License, or */
7 /* (at your option) any later version. */
9 /* This program is distributed in the hope that it will be useful, */
10 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
11 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
12 /* GNU General Public License for more details. */
14 /* You should have received a copy of the GNU General Public License along */
15 /* with this program; if not, write to the Free Software Foundation, Inc., */
16 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
18 #include <malloc.h>
19 #include <math.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
24 #include <png.h>
25 #include <jpeglib.h>
27 void
28 cplt_horiz(unsigned char *rawp, png_bytep row, int y, int x, int color, int width)
30 row[3 * x + color] = (rawp[-1] + rawp[1]) / 2;
33 void
34 cplt_vert(unsigned char *rawp, png_bytep row, int y, int x, int color, int width)
36 row[3 * x + color] = (rawp[-width] + rawp[width]) / 2;
39 void
40 cplt_squ(unsigned char *rawp, png_bytep row, int y, int x, int color, int width)
42 row[3 * x + color] = (rawp[-1] + rawp[1] + rawp[-width] + rawp[width]) / 4;
45 void
46 cplt_diag(unsigned char *rawp, png_bytep row, int y, int x, int color, int width)
48 row[3 * x + color] = (rawp[-width - 1] + rawp[-width + 1] +
49 rawp[width - 1] + rawp[width + 1]) / 4;
52 void
53 cplt_g_on_r(unsigned char *rawp, png_bytep row, int y, int x, int width)
55 cplt_horiz(rawp, row, y, x, 0, width);
56 cplt_vert(rawp, row, y, x, 2, width);
59 void
60 cplt_g_on_b(unsigned char *rawp, png_bytep row, int y, int x, int width)
62 cplt_horiz(rawp, row, y, x, 2, width);
63 cplt_vert(rawp, row, y, x, 0, width);
66 void
67 cplt_r(unsigned char *rawp, png_bytep row, int y, int x, int width)
69 cplt_squ(rawp, row, y, x, 1, width);
70 cplt_diag(rawp, row, y, x, 2, width);
73 void
74 cplt_b(unsigned char *rawp, png_bytep row, int y, int x, int width)
76 cplt_squ(rawp, row, y, x, 1, width);
77 cplt_diag(rawp, row, y, x, 0, width);
80 void
81 colrz_r(unsigned char *rawp, png_bytep row, int y, int x)
83 row[3 * x + 0] = rawp[0];
86 void
87 colrz_g(unsigned char *rawp, png_bytep row, int y, int x)
89 row[3 * x + 1] = rawp[0];
92 void
93 colrz_b(unsigned char *rawp, png_bytep row, int y, int x)
95 row[3 * x + 2] = rawp[0];
98 void
99 raise_color(png_bytep row, int x, double *colr_raisr)
101 int i, val;
103 for (i = 0; i < 3; i++) {
104 val = round(row[3 * x + i] * colr_raisr[i]);
105 if (val > 255)
106 val = 255;
107 row[3 * x + i] = val;
111 void
112 raise_noop(png_bytep row, int x, double *colr_raisr)
116 /* structure to store in-memory PNG in */
117 struct mem_encode
119 char *buffer;
120 size_t size;
123 void
124 write_png_data(png_structp png_ptr, png_bytep data, png_size_t length)
126 struct mem_encode *p = (struct mem_encode *)png_get_io_ptr(png_ptr);
127 size_t nsize = p->size + length;
128 /* allocate or grow buffer */
129 if (p->buffer)
130 p->buffer = realloc(p->buffer, nsize);
131 else
132 p->buffer = malloc(nsize);
133 if (!p->buffer)
134 png_error(png_ptr, "Write Error");
135 /* copy new bytes to end of buffer */
136 memcpy(p->buffer + p->size, data, length);
137 p->size += length;
140 void
141 flush_png(png_structp png_ptr)
146 uncompressed2png(struct mem_encode *mem_png, int width, int height, int channels,
147 int *bayerpat, double *color_raiser, unsigned char *uncompressed)
149 int retval = 0;
150 png_structp png_ptr = NULL;
151 png_infop info_ptr = NULL;
152 png_bytep row = NULL;
153 void (*colrz_ev_ev)(unsigned char *, png_bytep, int, int) = NULL;
154 void (*colrz_ev_od)(unsigned char *, png_bytep, int, int) = NULL;
155 void (*colrz_od_ev)(unsigned char *, png_bytep, int, int) = NULL;
156 void (*colrz_od_od)(unsigned char *, png_bytep, int, int) = NULL;
157 void (*cplt_ev_ev)(unsigned char *, png_bytep, int, int, int) = NULL;
158 void (*cplt_ev_od)(unsigned char *, png_bytep, int, int, int) = NULL;
159 void (*cplt_od_ev)(unsigned char *, png_bytep, int, int, int) = NULL;
160 void (*cplt_od_od)(unsigned char *, png_bytep, int, int, int) = NULL;
161 void (*raise)(unsigned char *, int, double *) = raise_noop;
162 int x, y, x_ev, x_od, y_ev, y_od;
163 int i;
165 for (i = 0; i < 3; i++)
166 if (fabs(color_raiser[i] - 1) > 0.00001)
167 raise = raise_color;
168 if (channels == 3) {
169 if (bayerpat[0] == 0x0000ff) { /* red */
170 colrz_ev_ev = colrz_r;
171 colrz_ev_od = colrz_g;
172 colrz_od_ev = colrz_g;
173 colrz_od_od = colrz_b;
174 cplt_ev_ev = cplt_r;
175 cplt_ev_od = cplt_g_on_r;
176 cplt_od_ev = cplt_g_on_b;
177 cplt_od_od = cplt_b;
178 } else if (bayerpat[0] == 0xff0000) { /* blue */
179 colrz_ev_ev = colrz_b;
180 colrz_ev_od = colrz_g;
181 colrz_od_ev = colrz_g;
182 colrz_od_od = colrz_r;
183 cplt_ev_ev = cplt_b;
184 cplt_ev_od = cplt_g_on_b;
185 cplt_od_ev = cplt_g_on_r;
186 cplt_od_od = cplt_b;
187 } else if (bayerpat[0] == 0x00ff00) { /* green */
188 if (bayerpat[1] == 0x0000ff) { /* red */
189 colrz_ev_ev = colrz_g;
190 colrz_ev_od = colrz_r;
191 colrz_od_ev = colrz_b;
192 colrz_od_od = colrz_g;
193 cplt_ev_ev = cplt_g_on_r;
194 cplt_ev_od = cplt_r;
195 cplt_od_ev = cplt_b;
196 cplt_od_od = cplt_g_on_b;
197 } else if (bayerpat[1] == 0xff0000) { /* blue */
198 colrz_ev_ev = colrz_g;
199 colrz_ev_od = colrz_b;
200 colrz_od_ev = colrz_r;
201 colrz_od_od = colrz_g;
202 cplt_ev_ev = cplt_g_on_b;
203 cplt_ev_od = cplt_b;
204 cplt_od_ev = cplt_r;
205 cplt_od_od = cplt_g_on_r;
206 } else {
207 retval = 2; /* all green is not a Bayer pattern */
208 goto finalize;
210 } else {
211 retval = 3; /* first byte neither 0x00 nor 0xff */
212 goto finalize;
215 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
216 if (png_ptr == NULL) {
217 retval = 11; /* Could not allocate write struct */
218 goto finalize;
220 info_ptr = png_create_info_struct(png_ptr);
221 if (info_ptr == NULL) {
222 retval = 12; /* Could not allocate info struct */
223 goto finalize;
225 if (setjmp(png_jmpbuf(png_ptr))) {
226 retval = 13; /* Error during png creation */
227 goto finalize;
229 mem_png->buffer = NULL;
230 mem_png->size = 0;
231 png_set_write_fn(png_ptr, mem_png, write_png_data, flush_png);
232 row = malloc(channels * width * sizeof(png_byte));
233 if (row == NULL) {
234 retval = 21;
235 goto finalize;
237 if (channels == 3) {
238 png_set_IHDR(png_ptr, info_ptr, width, height,
239 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
240 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
241 png_write_info(png_ptr, info_ptr);
242 for (y_ev = 0, y_od = 1;
243 y_ev < height && y_od < height;
244 y_ev += 2, y_od += 2) {
245 for (x_ev = 0, x_od = 1;
246 x_ev < width && x_od < width;
247 x_ev += 2, x_od += 2) {
248 colrz_ev_ev(uncompressed + y_ev * width + x_ev,
249 row, y_ev, x_ev);
250 colrz_ev_od(uncompressed + y_ev * width + x_od,
251 row, y_ev, x_od);
252 if (y_ev > 0 && y_ev < height - 1) {
253 cplt_ev_ev(uncompressed + y_ev * width + x_ev,
254 row, y_ev, x_ev, width);
255 cplt_ev_od(uncompressed + y_ev * width + x_od,
256 row, y_ev, x_od, width);
258 raise(row, x_ev, color_raiser);
259 raise(row, x_od, color_raiser);
261 png_write_row(png_ptr, row);
262 for (x_ev = 0, x_od = 1;
263 x_ev < width && x_od < width;
264 x_ev += 2, x_od += 2) {
265 colrz_od_ev(uncompressed + y_od * width + x_ev,
266 row, y_od, x_ev);
267 colrz_od_od(uncompressed + y_od * width + x_od,
268 row, y_od, x_od);
269 if (y_od < height - 1) {
270 cplt_od_ev(uncompressed + y_od * width + x_ev,
271 row, y_od, x_ev, width);
272 cplt_od_od(uncompressed + y_od * width + x_od,
273 row, y_od, x_od, width);
275 raise(row, x_ev, color_raiser);
276 raise(row, x_od, color_raiser);
278 png_write_row(png_ptr, row);
280 } else if (channels == 1) {
281 png_set_IHDR(png_ptr, info_ptr, width, height,
282 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
283 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
284 png_write_info(png_ptr, info_ptr);
285 for (y = 0; y < height; y++) {
286 for (x = 0; x < width; x++) {
287 row[x] = uncompressed[y * width + x];
289 png_write_row(png_ptr, row);
291 } else {
292 retval = 6; /* wrong number of channels */
293 goto finalize;
295 png_write_end(png_ptr, NULL);
296 finalize:
297 if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
298 if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, NULL);
299 if (row != NULL) free(row);
300 return retval;
304 uncompressedjpeg2png(struct mem_encode *mem_png, int width, int height,
305 int channels, double *color_raiser,
306 unsigned char *uncompressed)
308 int retval = 0;
309 png_structp png_ptr = NULL;
310 png_infop info_ptr = NULL;
311 void (*raise)(unsigned char *, int, double *) = raise_noop;
312 int y;
313 int i;
315 for (i = 0; i < 3; i++)
316 if (fabs(color_raiser[i] - 1) > 0.00001)
317 raise = raise_color;
318 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
319 if (png_ptr == NULL) {
320 retval = 11; /* Could not allocate write struct */
321 goto finalize;
323 info_ptr = png_create_info_struct(png_ptr);
324 if (info_ptr == NULL) {
325 retval = 12; /* Could not allocate info struct */
326 goto finalize;
328 if (setjmp(png_jmpbuf(png_ptr))) {
329 retval = 13; /* Error during png creation */
330 goto finalize;
332 mem_png->buffer = NULL;
333 mem_png->size = 0;
334 png_set_write_fn(png_ptr, mem_png, write_png_data, flush_png);
335 if (channels == 3) {
336 for (i = 0; i < width * height; i++)
337 raise(uncompressed, i, color_raiser);
338 png_set_IHDR(png_ptr, info_ptr, width, height,
339 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
340 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
341 } else if (channels == 1) {
342 png_set_IHDR(png_ptr, info_ptr, width, height,
343 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
344 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
345 } else {
346 retval = 6; /* wrong number of channels */
347 goto finalize;
349 png_write_info(png_ptr, info_ptr);
350 for (y = 0; y < height; y++)
351 png_write_row(png_ptr, uncompressed + y * width * channels);
352 png_write_end(png_ptr, NULL);
353 finalize:
354 if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
355 if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, NULL);
356 return retval;
360 huffdecode(int width, int height, unsigned char *uncompressed,
361 unsigned char hcode[static 4 * 511], unsigned char hlen[static 511],
362 unsigned char *compressed)
364 int i, j, m;
365 int maxlen = 0;
366 int code;
367 struct huffval {
368 int val;
369 int len;
370 } *htable;
371 int row, column, cidx;
372 uint64_t hc_mask;
373 unsigned int rowhead;
375 for (i = 0; i < 511; i++)
376 if (hlen[i] > maxlen)
377 maxlen = hlen[i];
378 if ((htable = malloc((1 << maxlen) * sizeof(struct huffval))) == NULL)
379 return 31;
380 /* htable may well become too big to fit into memory. Maybe
381 we should act a bit smarter and handle longer huffman codes
382 differently. */
383 for (i = 0; i < 511; i++) {
384 if (hlen[i] > 0) {
385 code = hcode[4 * i] << 24 | hcode[4 * i + 1] << 16 |
386 hcode[4 * i + 2] << 8 | hcode[4 * i + 3];
387 code <<= maxlen - hlen[i];
388 htable[code].val = i - 255;
389 htable[code].len = hlen[i];
390 for (j = 0; j < (1 << maxlen - hlen[i]); j++) {
391 htable[code | j].val = i - 255;
392 htable[code | j].len = hlen[i];
396 hc_mask = 0;
397 for (i = 0, m = 1; i < maxlen; i++, m <<= 1)
398 hc_mask |= m;
399 cidx = 0;
400 for (row = 0; row < height; row++) {
401 rowhead = compressed[cidx / 8] << 16;
402 cidx += 8;
403 rowhead |= compressed[cidx / 8] << 8;
404 cidx += 8;
405 rowhead |= compressed[cidx / 8];
406 rowhead >>= 8 - cidx % 8;
407 uncompressed[width * row] = (rowhead >> 8) & 0xff;
408 uncompressed[width * row + 1] = rowhead & 0xff;
409 for (column = 2; column < width; column++) {
410 div_t cidx_d, maxlen_d;
411 int rem_bits, r;
412 uint64_t hc;
414 cidx_d = div(cidx, 8);
415 rem_bits = maxlen - (8 - cidx_d.rem);
416 cidx += 8 - cidx_d.rem;
417 maxlen_d = div(maxlen, 8);
418 hc = compressed[cidx_d.quot];
419 for (i = rem_bits; i > 0; i -= 8, cidx += 8) {
420 hc <<= 8;
421 hc |= compressed[cidx / 8];
423 if ((r = rem_bits % 8) > 0) {
424 hc >>= 8 - r;
425 cidx -= 8 - r;
427 hc &= hc_mask;
428 uncompressed[width * row + column] =
429 uncompressed[width * row + column - 2] - htable[hc].val;
430 cidx -= maxlen - htable[hc].len;
433 free(htable);
434 return 0;
437 void
438 reverse(unsigned char *base, size_t size)
440 int i, j;
441 char tmp;
443 for (i = 0, j = size - 1; i < j; i++, j--) {
444 tmp = base[i];
445 base[i] = base[j];
446 base[j] = tmp;
450 void
451 brighten(unsigned char *base, size_t size)
453 size_t i;
454 unsigned char min = UCHAR_MAX, max = 0, range;
456 for (i = 0; i < size; i++) {
457 if (base[i] < min)
458 min = base[i];
459 if (base[i] > max)
460 max = base[i];
462 range = max - min;
463 if (max < 200)
464 for (i = 0; i < size; i++)
465 base[i] = (base[i] - min) * UCHAR_MAX / range;
468 struct imread_jpeg_error_mgr {
469 struct jpeg_error_mgr pub;
470 jmp_buf setjmp_buffer;
473 typedef struct imread_jpeg_error_mgr *imread_jpeg_error_ptr;
475 METHODDEF(void)
476 imread_jpeg_error_exit (j_common_ptr cinfo)
478 imread_jpeg_error_ptr myerr = (imread_jpeg_error_ptr) cinfo->err;
479 (*cinfo->err->output_message) (cinfo);
480 longjmp(myerr->setjmp_buffer, 1);
484 png2mem(char *path, int start, int len, int width, int height,
485 int channels, int *bayer_pattern, int compr_mode,
486 unsigned char *uncompressed, unsigned char *compressed,
487 struct mem_encode *mem_png,
488 int reversep, int brightenp, double *color_raiser)
490 FILE *in;
491 unsigned char hlen[511], hcode[511 * 4];
492 int htblsize = 511 * (1 + 4);
493 int retval;
495 if ((in = fopen(path, "r")) == NULL)
496 return 1;
497 fseek(in, start, SEEK_CUR);
498 if (compr_mode == 1 || compr_mode == 2) {
499 fread(hcode, sizeof(hcode[0]), 511 * 4, in);
500 fread(hlen, sizeof(hlen[0]), 511, in);
501 fread(compressed, sizeof(compressed[0]), len - htblsize, in);
502 fclose(in);
503 if ((retval = huffdecode(width, height, uncompressed, hcode,
504 hlen, compressed)) != 0)
505 return retval;
506 if (reversep)
507 reverse(uncompressed, width * height);
508 if (brightenp)
509 brighten(uncompressed, width * height);
510 if ((retval = uncompressed2png(mem_png, width, height, channels,
511 bayer_pattern, color_raiser,
512 uncompressed)) != 0)
513 return retval;
514 return 0;
515 } else if (compr_mode == 3) { /* JPEG */
516 struct jpeg_decompress_struct cinfo;
517 struct imread_jpeg_error_mgr jerr;
518 unsigned char *next_line;
519 int nsamples;
521 cinfo.err = jpeg_std_error(&jerr.pub);
522 jerr.pub.error_exit = imread_jpeg_error_exit;
523 if (setjmp(jerr.setjmp_buffer)) {
524 jpeg_destroy_decompress(&cinfo);
525 return 71; /* JPEG decompression error */
527 jpeg_create_decompress(&cinfo);
528 fread(compressed, sizeof(compressed[0]), len, in);
529 fclose(in);
530 jpeg_mem_src(&cinfo, compressed, len);
531 jpeg_read_header(&cinfo, TRUE);
532 if (cinfo.image_width * cinfo.image_height * cinfo.num_components >
533 width * height * channels) {
534 return 72; /* JPEG bigger than expected */
535 jpeg_destroy_decompress(&cinfo);
537 jpeg_start_decompress(&cinfo);
538 next_line = uncompressed;
539 while (cinfo.output_scanline < cinfo.output_height) {
540 nsamples = jpeg_read_scanlines(&cinfo, (JSAMPARRAY)&next_line, 1);
541 next_line += nsamples * cinfo.image_width * cinfo.num_components;
543 jpeg_finish_decompress(&cinfo);
544 jpeg_destroy_decompress(&cinfo);
545 if (reversep)
546 return 73; /* JPEG reversing not implemented */
547 if (brightenp)
548 return 74; /* JPEG brightening not implemented */
549 if ((retval = uncompressedjpeg2png(
550 mem_png, cinfo.image_width, cinfo.image_height,
551 cinfo.num_components, color_raiser,
552 uncompressed)) != 0)
553 return retval;
554 return 0;
555 } else if (compr_mode == 0) { /* untested */
556 fread(uncompressed, sizeof(uncompressed[0]), width * height, in);
557 fclose(in);
558 if (reversep)
559 reverse(uncompressed, width * height);
560 if (brightenp)
561 brighten(uncompressed, width * height);
562 if ((retval = uncompressed2png(mem_png, width, height, channels,
563 bayer_pattern, color_raiser,
564 uncompressed)) != 0)
565 return retval;
566 return 0;
567 } else {
568 fclose(in);
569 return 5;
574 ping(int n) {
575 return n;
579 main(int argc, char *argv[])
581 FILE *fp;
582 unsigned char compressed[1390353];
583 unsigned char uncompressed[1700 * 1500];
584 int width = 1700, height = 1500;
585 struct mem_encode mp;
587 setvbuf(stdout, NULL, _IONBF, 0);
589 png2mem("mitsa005_CCD_Front_PULNIX_13.pictures", 2247 + 17, 1390353, width, height, 3, (int[2]){0x00ff00, 0x0000ff}, 2, uncompressed, compressed, &mp, 0, 0, (double[3]){1, 1, 1});
590 fp = fopen("o0.png", "wb");
591 if (fp == NULL) {
592 fprintf(stderr, "Could not open file %s for writing\n", "o0.png");
594 fwrite(mp.buffer, mp.size, sizeof(mp.buffer[0]), fp);
596 png2mem("mitsa005_CCD_Front_PULNIX_13.pictures", 2247 + 17, 1390353, width, height, 3, (int[2]){0x00ff00, 0x0000ff}, 2, uncompressed, compressed, &mp, 0, 1, (double[3]){1, 2.5, 1.5});
597 fp = fopen("o1.png", "wb");
598 if (fp == NULL) {
599 fprintf(stderr, "Could not open file %s for writing\n", "o1.png");
601 fwrite(mp.buffer, mp.size, sizeof(mp.buffer[0]), fp);
602 if(mp.buffer)
603 free(mp.buffer);