Fasttrack: handle DNS-related condition
[phoros.git] / imread.c
blob8147a32327e8c0a3babf228e0d7636a39f96e30a
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 "imread.h"
20 enum color {RED, GREEN, BLUE};
23 Set one particular color cell to the value of an adjacent pixel/to
24 the average of the values in the surrounding pixels found in rawp
26 static void
27 cplt_horiz_fast(unsigned char *rawp, png_bytep cell, int color, int width)
29 (void) width;
30 cell[color] = rawp[1];
33 static void
34 cplt_horiz_slow(unsigned char *rawp, png_bytep cell, int color, int width)
36 (void) width;
37 cell[color] = (rawp[-1] + rawp[1]) / 2;
40 static void
41 cplt_vert_fast(unsigned char *rawp, png_bytep cell, int color, int width)
43 cell[color] = rawp[width];
46 static void
47 cplt_vert_slow(unsigned char *rawp, png_bytep cell, int color, int width)
49 cell[color] = (rawp[-width] + rawp[width]) / 2;
52 static void
53 cplt_squ_fast(unsigned char *rawp, png_bytep cell, int color, int width)
55 (void) width;
56 cell[color] = rawp[1];
59 static void
60 cplt_squ_slow(unsigned char *rawp, png_bytep cell, int color, int width)
62 cell[color] = (rawp[-1] + rawp[1] + rawp[-width] + rawp[width]) / 4;
65 static void
66 cplt_diag_fast(unsigned char *rawp, png_bytep cell, int color, int width)
68 cell[color] = rawp[width + 1];
71 static void
72 cplt_diag_slow(unsigned char *rawp, png_bytep cell, int color, int width)
74 cell[color] = (rawp[-width - 1] + rawp[-width + 1] +
75 rawp[width - 1] + rawp[width + 1]) / 4;
78 typedef void (*GeometricCompleter)(unsigned char *, png_bytep, int, int);
80 GeometricCompleter cplt_horiz, cplt_vert, cplt_squ, cplt_diag;
83 Add missing colors to a green cell in a red and green row
85 static void
86 cplt_g_on_r(unsigned char *rawp, png_bytep cell, int width)
88 cplt_horiz(rawp, cell, RED, width);
89 cplt_vert(rawp, cell, BLUE, width);
93 Add missing colors to a green cell in a blue and green row
95 static void
96 cplt_g_on_b(unsigned char *rawp, png_bytep cell, int width)
98 cplt_horiz(rawp, cell, BLUE, width);
99 cplt_vert(rawp, cell, RED, width);
103 Add missing colors to a red cell
105 static void
106 cplt_r(unsigned char *rawp, png_bytep cell, int width)
108 cplt_squ(rawp, cell, GREEN, width);
109 cplt_diag(rawp, cell, BLUE, width);
113 Add missing colors to a blue cell
115 static void
116 cplt_b(unsigned char *rawp, png_bytep cell, int width)
118 cplt_squ(rawp, cell, GREEN, width);
119 cplt_diag(rawp, cell, RED, width);
122 typedef void (*Completer)(unsigned char *, png_bytep, int);
125 Set one particular color of cell the value found in rawp
127 static void
128 colrz_r(unsigned char *rawp, png_bytep cell)
130 cell[RED] = rawp[0];
133 static void
134 colrz_g(unsigned char *rawp, png_bytep cell)
136 cell[GREEN] = rawp[0];
139 static void
140 colrz_b(unsigned char *rawp, png_bytep cell)
142 cell[BLUE] = rawp[0];
145 typedef void (*Colorizer)(unsigned char *, png_bytep);
147 static void
148 raise_color(png_bytep cell, double *colr_raisr)
150 int i, val;
152 for (i = 0; i < 3; i++) {
153 val = round(cell[i] * colr_raisr[i]);
154 if (val > 255)
155 val = 255;
156 cell[i] = val;
160 static void
161 raise_noop(png_bytep cell, double *colr_raisr)
163 (void) cell;
164 (void) colr_raisr;
167 typedef void (*ColorRaiser)(unsigned char *, double *);
169 static void
170 write_png_data(png_structp png_ptr, png_bytep data, png_size_t length)
172 struct png_store *p = (struct png_store *)png_get_io_ptr(png_ptr);
173 size_t nsize = p->size + length;
174 /* allocate or grow buffer */
175 if (p->buffer)
176 p->buffer = realloc(p->buffer, nsize);
177 else
178 p->buffer = malloc(nsize);
179 if (!p->buffer)
180 png_error(png_ptr, "Write Error");
181 /* copy new bytes to end of buffer */
182 memcpy(p->buffer + p->size, data, length);
183 p->size += length;
186 static void
187 flush_png(png_structp png_ptr)
189 (void) png_ptr;
192 static int
193 raw_img2png(struct png_store *png, int width, int height, int channels,
194 int *bayerpat, double *color_raiser, unsigned char *raw_img,
195 bool demosaic_fast)
197 int retval = 0;
198 png_structp png_ptr = NULL;
199 png_infop info_ptr = NULL;
200 png_bytep ev_row = NULL, od_row = NULL;
201 Colorizer colrz_ev_ev, colrz_ev_od, colrz_od_ev, colrz_od_od;
202 Completer cplt_ev_ev, cplt_ev_od, cplt_od_ev, cplt_od_od;
203 int i, x, y, x_od, y_od;
205 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
206 if (png_ptr == NULL) {
207 retval = 11; /* Could not allocate write struct */
208 goto finalize;
210 info_ptr = png_create_info_struct(png_ptr);
211 if (info_ptr == NULL) {
212 retval = 12; /* Could not allocate info struct */
213 goto finalize;
215 if (setjmp(png_jmpbuf(png_ptr))) {
216 retval = 13; /* Error during png creation */
217 goto finalize;
219 png->buffer = NULL;
220 png->size = 0;
221 png_set_write_fn(png_ptr, png, write_png_data, flush_png);
222 if (((ev_row = malloc(channels * width * sizeof(png_byte))) == NULL) ||
223 ((od_row = malloc(channels * width * sizeof(png_byte))) == NULL)) {
224 retval = 21; /* Error while writing PNG row */
225 goto finalize;
227 if (channels == 3) {
228 ColorRaiser raise = raise_noop;
230 if (demosaic_fast) {
231 cplt_horiz = cplt_horiz_fast;
232 cplt_vert = cplt_vert_fast;
233 cplt_squ = cplt_squ_fast;
234 cplt_diag = cplt_diag_fast;
235 } else {
236 cplt_horiz = cplt_horiz_slow;
237 cplt_vert = cplt_vert_slow;
238 cplt_squ = cplt_squ_slow;
239 cplt_diag = cplt_diag_slow;
241 for (i = 0; i < 3; i++)
242 if (fabs(color_raiser[i] - 1) > 0.00001)
243 raise = raise_color;
244 if (bayerpat[0] == 0x0000ff) { /* red */
245 colrz_ev_ev = colrz_r;
246 colrz_ev_od = colrz_g;
247 colrz_od_ev = colrz_g;
248 colrz_od_od = colrz_b;
249 cplt_ev_ev = cplt_r;
250 cplt_ev_od = cplt_g_on_r;
251 cplt_od_ev = cplt_g_on_b;
252 cplt_od_od = cplt_b;
253 } else if (bayerpat[0] == 0xff0000) { /* blue */
254 colrz_ev_ev = colrz_b;
255 colrz_ev_od = colrz_g;
256 colrz_od_ev = colrz_g;
257 colrz_od_od = colrz_r;
258 cplt_ev_ev = cplt_b;
259 cplt_ev_od = cplt_g_on_b;
260 cplt_od_ev = cplt_g_on_r;
261 cplt_od_od = cplt_b;
262 } else if (bayerpat[0] == 0x00ff00) { /* green */
263 if (bayerpat[1] == 0x0000ff) { /* red */
264 colrz_ev_ev = colrz_g;
265 colrz_ev_od = colrz_r;
266 colrz_od_ev = colrz_b;
267 colrz_od_od = colrz_g;
268 cplt_ev_ev = cplt_g_on_r;
269 cplt_ev_od = cplt_r;
270 cplt_od_ev = cplt_b;
271 cplt_od_od = cplt_g_on_b;
272 } else if (bayerpat[1] == 0xff0000) { /* blue */
273 colrz_ev_ev = colrz_g;
274 colrz_ev_od = colrz_b;
275 colrz_od_ev = colrz_r;
276 colrz_od_od = colrz_g;
277 cplt_ev_ev = cplt_g_on_b;
278 cplt_ev_od = cplt_b;
279 cplt_od_ev = cplt_r;
280 cplt_od_od = cplt_g_on_r;
281 } else {
282 retval = 2; /* all green is not a Bayer pattern */
283 goto finalize;
285 } else {
286 retval = 3; /* first byte neither 0x00 nor 0xff */
287 goto finalize;
289 png_set_IHDR(png_ptr, info_ptr, width, height,
290 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
291 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
292 png_write_info(png_ptr, info_ptr);
293 for (y_od = 1; y_od <= height; y_od += 2) {
294 /* neglecting bottom row if height is even */
295 int y_ev = y_od - 1;
296 unsigned char *ev_1stcol = raw_img + y_ev * width;
297 unsigned char *od_1stcol = raw_img + y_od * width;
299 for (x_od = 1; x_od < width; x_od += 2) {
300 int x_ev = x_od - 1;
301 int ev_xpos = 3 * x_ev;
302 int od_xpos = 3 * x_od;
304 colrz_ev_ev(ev_1stcol + x_ev, ev_row + ev_xpos);
305 colrz_ev_od(ev_1stcol + x_od, ev_row + od_xpos);
306 colrz_od_ev(od_1stcol + x_ev, od_row + ev_xpos);
307 colrz_od_od(od_1stcol + x_od, od_row + od_xpos);
308 if (y_od > 1 && y_od < height - 1) {
309 /* neglecting bottom row if height is odd */
310 cplt_ev_ev(ev_1stcol + x_ev,
311 ev_row + ev_xpos, width);
312 cplt_ev_od(ev_1stcol + x_od,
313 ev_row + od_xpos, width);
314 cplt_od_ev(od_1stcol + x_ev,
315 od_row + ev_xpos, width);
316 cplt_od_od(od_1stcol + x_od,
317 od_row + od_xpos, width);
319 raise(ev_row + ev_xpos, color_raiser);
320 raise(ev_row + od_xpos, color_raiser);
321 raise(od_row + ev_xpos, color_raiser);
322 raise(od_row + od_xpos, color_raiser);
324 png_write_row(png_ptr, ev_row);
325 png_write_row(png_ptr, od_row);
327 } else if (channels == 1) {
328 png_set_IHDR(png_ptr, info_ptr, width, height,
329 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
330 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
331 png_write_info(png_ptr, info_ptr);
332 for (y = 0; y < height; y++) {
333 for (x = 0; x < width; x++) {
334 ev_row[x] = raw_img[y * width + x];
336 png_write_row(png_ptr, ev_row);
338 } else {
339 retval = 6; /* wrong number of channels */
340 goto finalize;
342 png_write_end(png_ptr, NULL);
343 finalize:
344 if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
345 if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, NULL);
346 if (ev_row != NULL) free(ev_row);
347 if (od_row != NULL) free(od_row);
348 return retval;
351 static int
352 raw_jpeg2png(struct png_store *png, int width, int height,
353 int channels, double *color_raiser,
354 unsigned char *raw_jpeg)
356 int retval = 0;
357 png_structp png_ptr = NULL;
358 png_infop info_ptr = NULL;
359 int y;
360 int i;
362 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
363 if (png_ptr == NULL) {
364 retval = 11; /* Could not allocate write struct */
365 goto finalize;
367 info_ptr = png_create_info_struct(png_ptr);
368 if (info_ptr == NULL) {
369 retval = 12; /* Could not allocate info struct */
370 goto finalize;
372 if (setjmp(png_jmpbuf(png_ptr))) {
373 retval = 13; /* Error during png creation */
374 goto finalize;
376 png->buffer = NULL;
377 png->size = 0;
378 png_set_write_fn(png_ptr, png, write_png_data, flush_png);
379 if (channels == 3) {
380 ColorRaiser raise = raise_noop;
382 for (i = 0; i < 3; i++)
383 if (fabs(color_raiser[i] - 1) > 0.00001)
384 raise = raise_color;
385 for (i = 0; i < 3 * width * height; i += 3)
386 raise(raw_jpeg + i, color_raiser);
387 png_set_IHDR(png_ptr, info_ptr, width, height,
388 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
389 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
390 } else if (channels == 1) {
391 png_set_IHDR(png_ptr, info_ptr, width, height,
392 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
393 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
394 } else {
395 retval = 6; /* wrong number of channels */
396 goto finalize;
398 png_write_info(png_ptr, info_ptr);
399 for (y = 0; y < height; y++)
400 png_write_row(png_ptr, raw_jpeg + y * width * channels);
401 png_write_end(png_ptr, NULL);
402 finalize:
403 if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
404 if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, NULL);
405 return retval;
409 Huffman decoder. The size of compressed must exceed its contents
410 by 8 bytes.
412 static int
413 huffdecode(int width, int height, unsigned char *uncompressed,
414 uint8_t hcode[static 4 * 511], uint8_t hlen[static 511],
415 unsigned char *compressed, size_t compressed_size)
417 int i, i4, j, maxlen = 0, code, retval = 0, row, column;
418 uint64_t hc_mask;
419 uint32_t rowhead;
420 size_t cidx = 0, max_cidx = (compressed_size + 8) * 8;
421 struct huffval {
422 int16_t val;
423 uint8_t len;
424 } *htable;
426 for (i = 0; i < 511; i++)
427 if (hlen[i] > maxlen)
428 maxlen = hlen[i];
429 if ((htable = malloc((1 << maxlen) * sizeof(struct huffval))) == NULL)
430 return 31; /* Couldn't allocate memory for huffman table */
431 /* htable may well become too big to fit into memory. Maybe
432 we should act a bit smarter and handle longer huffman codes
433 differently. */
434 for (i = 0, i4 = 0; i < 511; i++, i4 += 4) {
435 if (hlen[i] > 0) {
436 code = hcode[i4] << 24 | hcode[i4 + 1] << 16 |
437 hcode[i4 + 2] << 8 | hcode[i4 + 3];
438 code <<= maxlen - hlen[i];
439 /* one entry for each number of width maxlen
440 that starts with code: */
441 for (j = 0; j < (1 << (maxlen - hlen[i])); j++) {
442 htable[code | j].val = i - 255;
443 htable[code | j].len = hlen[i];
447 hc_mask = (1 << maxlen) - 1;
448 for (row = 0; row < height; row++) {
449 /* Columns one and two of each row aren't compressed */
450 rowhead = compressed[cidx / 8] << 16;
451 cidx += 8;
452 rowhead |= compressed[cidx / 8] << 8;
453 cidx += 8;
454 rowhead |= compressed[cidx / 8];
455 rowhead >>= 8 - cidx % 8;
456 uncompressed[width * row] = (rowhead >> 8) & 0xff;
457 uncompressed[width * row + 1] = rowhead & 0xff;
458 for (column = 2; column < width; column++) {
459 div_t cidx_d;
460 int bits_to_read;
461 uint64_t hc;
463 cidx_d = div(cidx, 8);
464 cidx = cidx_d.quot * 8;
465 bits_to_read = maxlen + cidx_d.rem;
466 hc = 0;
467 for (i = bits_to_read; i > 0; i -= 8) {
468 hc <<= 8;
469 hc |= compressed[cidx / 8];
470 cidx += 8;
472 hc >>= -i; /* i <= 0 */
473 if ((cidx += i) > max_cidx) {
474 retval = 32; /* Huffman decoder out of step */
475 goto cleanup;
477 hc &= hc_mask;
478 uncompressed[width * row + column] =
479 uncompressed[width * row + column - 2] - htable[hc].val;
480 cidx -= maxlen - htable[hc].len;
483 cleanup:
484 free(htable);
485 return retval;
488 static void
489 reverse(unsigned char *base, size_t size)
491 int i, j;
492 char tmp;
494 for (i = 0, j = size - 1; i < j; i++, j--) {
495 tmp = base[i];
496 base[i] = base[j];
497 base[j] = tmp;
501 static void
502 brighten(unsigned char *base, size_t size)
504 size_t i;
505 unsigned char min = UCHAR_MAX, max = 0, range;
507 for (i = 0; i < size; i++) {
508 if (base[i] < min)
509 min = base[i];
510 if (base[i] > max)
511 max = base[i];
513 range = max - min;
514 if (max < 200)
515 for (i = 0; i < size; i++)
516 base[i] = (base[i] - min) * UCHAR_MAX / range;
519 struct imread_jpeg_error_mgr {
520 struct jpeg_error_mgr pub;
521 jmp_buf setjmp_buffer;
524 typedef struct imread_jpeg_error_mgr *imread_jpeg_error_ptr;
526 METHODDEF(void)
527 imread_jpeg_error_exit (j_common_ptr cinfo)
529 imread_jpeg_error_ptr myerr = (imread_jpeg_error_ptr) cinfo->err;
530 (*cinfo->err->output_message) (cinfo);
531 longjmp(myerr->setjmp_buffer, 1);
535 png2mem(char *path, long long int start, int len, unsigned int width, unsigned int height,
536 unsigned int channels, int *bayer_pattern, bool demosaic_fast, int compr_mode,
537 struct png_store *png, bool reversep, bool brightenp, double *color_raiser)
539 FILE *in;
540 unsigned char hlen[511], hcode[511 * 4];
541 int htblsize = 511 * (1 + 4);
542 int retval = 0xFFFF; /* will change */
544 if ((in = fopen(path, "rb")) == NULL)
545 return 1; /* File not found */
546 fseek(in, start, SEEK_CUR);
547 if (compr_mode == 1 || compr_mode == 2) {
548 unsigned char *in_buf, *raw_img;
550 fread(hcode, sizeof(hcode[0]), 511 * 4, in);
551 fread(hlen, sizeof(hlen[0]), 511, in);
552 if ((in_buf = malloc(len + 8)) == NULL)
553 return 76; /* Couldn't allocate buffer for image data input */
554 fread(in_buf, sizeof(in_buf[0]), len - htblsize, in);
555 fclose(in);
556 if ((raw_img = malloc(width * height)) == NULL) {
557 free(in_buf);
558 return 75; /* Couldn't allocate memory for uncompressed image */
560 if ((retval = huffdecode(width, height, raw_img, hcode,
561 hlen, in_buf, len - htblsize)) == 0) {
562 if (reversep)
563 reverse(raw_img, width * height);
564 if (brightenp)
565 brighten(raw_img, width * height);
566 retval = raw_img2png(png, width, height, channels,
567 bayer_pattern, color_raiser, raw_img,
568 demosaic_fast);
570 free(raw_img);
571 free(in_buf);
572 return retval;
574 if (compr_mode == 3) { /* JPEG */
575 struct jpeg_decompress_struct cinfo;
576 struct imread_jpeg_error_mgr jerr;
577 unsigned char *in_buf, *raw_img, *next_line;
578 int nsamples;
580 if (reversep)
581 return 73; /* JPEG reversing not implemented */
582 if (brightenp)
583 return 74; /* JPEG brightening not implemented */
584 cinfo.err = jpeg_std_error(&jerr.pub);
585 jerr.pub.error_exit = imread_jpeg_error_exit;
586 if (setjmp(jerr.setjmp_buffer)) {
587 jpeg_destroy_decompress(&cinfo);
588 return 71; /* JPEG decompression error */
590 jpeg_create_decompress(&cinfo);
591 if ((in_buf = malloc(len)) == NULL)
592 return 76;
593 fread(in_buf, sizeof(in_buf[0]), len, in);
594 fclose(in);
595 jpeg_mem_src(&cinfo, in_buf, len);
596 jpeg_read_header(&cinfo, TRUE);
597 if (cinfo.image_width * cinfo.image_height * cinfo.num_components >
598 width * height * channels) {
599 jpeg_destroy_decompress(&cinfo);
600 return 72; /* JPEG bigger than expected */
602 jpeg_start_decompress(&cinfo);
603 if ((raw_img = malloc(width * height * channels)) == NULL) {
604 free(in_buf);
605 return 75;
607 next_line = raw_img;
608 while (cinfo.output_scanline < cinfo.output_height) {
609 nsamples = jpeg_read_scanlines(&cinfo, (JSAMPARRAY)&next_line, 1);
610 next_line += nsamples * cinfo.image_width * cinfo.num_components;
612 jpeg_finish_decompress(&cinfo);
613 jpeg_destroy_decompress(&cinfo);
614 retval = raw_jpeg2png(png, cinfo.image_width, cinfo.image_height,
615 cinfo.num_components, color_raiser,
616 raw_img);
617 free(raw_img);
618 free(in_buf);
619 return retval;
621 if (compr_mode == 0) { /* untested */
622 unsigned char *raw_img;
624 if ((raw_img = malloc(width * height)) == NULL)
625 return 75;
626 fread(raw_img, sizeof(raw_img[0]), width * height, in);
627 fclose(in);
628 if (reversep)
629 reverse(raw_img, width * height);
630 if (brightenp)
631 brighten(raw_img, width * height);
632 retval = raw_img2png(png, width, height, channels,
633 bayer_pattern, color_raiser, raw_img,
634 demosaic_fast);
635 free(raw_img);
636 return retval;
638 fclose(in);
639 return 5; /* Unknown compression mode */
643 ping(int n) {
644 return n;