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. */
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
27 cplt_horiz_fast(unsigned char *rawp
, png_bytep cell
, int color
, int width
)
30 cell
[color
] = rawp
[1];
34 cplt_horiz_slow(unsigned char *rawp
, png_bytep cell
, int color
, int width
)
37 cell
[color
] = (rawp
[-1] + rawp
[1]) / 2;
41 cplt_vert_fast(unsigned char *rawp
, png_bytep cell
, int color
, int width
)
43 cell
[color
] = rawp
[width
];
47 cplt_vert_slow(unsigned char *rawp
, png_bytep cell
, int color
, int width
)
49 cell
[color
] = (rawp
[-width
] + rawp
[width
]) / 2;
53 cplt_squ_fast(unsigned char *rawp
, png_bytep cell
, int color
, int width
)
56 cell
[color
] = rawp
[1];
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;
66 cplt_diag_fast(unsigned char *rawp
, png_bytep cell
, int color
, int width
)
68 cell
[color
] = rawp
[width
+ 1];
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
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
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
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
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
128 colrz_r(unsigned char *rawp
, png_bytep cell
)
134 colrz_g(unsigned char *rawp
, png_bytep cell
)
136 cell
[GREEN
] = rawp
[0];
140 colrz_b(unsigned char *rawp
, png_bytep cell
)
142 cell
[BLUE
] = rawp
[0];
145 typedef void (*Colorizer
)(unsigned char *, png_bytep
);
148 raise_color(png_bytep cell
, double *colr_raisr
)
152 for (i
= 0; i
< 3; i
++) {
153 val
= round(cell
[i
] * colr_raisr
[i
]);
161 raise_noop(png_bytep cell
, double *colr_raisr
)
167 typedef void (*ColorRaiser
)(unsigned char *, double *);
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 */
176 p
->buffer
= realloc(p
->buffer
, nsize
);
178 p
->buffer
= malloc(nsize
);
180 png_error(png_ptr
, "Write Error");
181 /* copy new bytes to end of buffer */
182 memcpy(p
->buffer
+ p
->size
, data
, length
);
187 flush_png(png_structp png_ptr
)
193 raw_img2png(struct png_store
*png
, int width
, int height
, int channels
,
194 int *bayerpat
, double *color_raiser
, unsigned char *raw_img
,
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 */
210 info_ptr
= png_create_info_struct(png_ptr
);
211 if (info_ptr
== NULL
) {
212 retval
= 12; /* Could not allocate info struct */
215 if (setjmp(png_jmpbuf(png_ptr
))) {
216 retval
= 13; /* Error during png creation */
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 */
228 ColorRaiser raise
= raise_noop
;
231 cplt_horiz
= cplt_horiz_fast
;
232 cplt_vert
= cplt_vert_fast
;
233 cplt_squ
= cplt_squ_fast
;
234 cplt_diag
= cplt_diag_fast
;
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)
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
;
250 cplt_ev_od
= cplt_g_on_r
;
251 cplt_od_ev
= cplt_g_on_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
;
259 cplt_ev_od
= cplt_g_on_b
;
260 cplt_od_ev
= cplt_g_on_r
;
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
;
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
;
280 cplt_od_od
= cplt_g_on_r
;
282 retval
= 2; /* all green is not a Bayer pattern */
286 retval
= 3; /* first byte neither 0x00 nor 0xff */
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 */
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) {
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
);
339 retval
= 6; /* wrong number of channels */
342 png_write_end(png_ptr
, NULL
);
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
);
352 raw_jpeg2png(struct png_store
*png
, int width
, int height
,
353 int channels
, double *color_raiser
,
354 unsigned char *raw_jpeg
)
357 png_structp png_ptr
= NULL
;
358 png_infop info_ptr
= NULL
;
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 */
367 info_ptr
= png_create_info_struct(png_ptr
);
368 if (info_ptr
== NULL
) {
369 retval
= 12; /* Could not allocate info struct */
372 if (setjmp(png_jmpbuf(png_ptr
))) {
373 retval
= 13; /* Error during png creation */
378 png_set_write_fn(png_ptr
, png
, write_png_data
, flush_png
);
380 ColorRaiser raise
= raise_noop
;
382 for (i
= 0; i
< 3; i
++)
383 if (fabs(color_raiser
[i
] - 1) > 0.00001)
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
);
395 retval
= 6; /* wrong number of channels */
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
);
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
);
409 Huffman decoder. The size of compressed must exceed its contents
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
;
420 size_t cidx
= 0, max_cidx
= (compressed_size
+ 8) * 8;
426 for (i
= 0; i
< 511; i
++)
427 if (hlen
[i
] > maxlen
)
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
434 for (i
= 0, i4
= 0; i
< 511; i
++, i4
+= 4) {
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;
452 rowhead
|= compressed
[cidx
/ 8] << 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
++) {
463 cidx_d
= div(cidx
, 8);
464 cidx
= cidx_d
.quot
* 8;
465 bits_to_read
= maxlen
+ cidx_d
.rem
;
467 for (i
= bits_to_read
; i
> 0; i
-= 8) {
469 hc
|= compressed
[cidx
/ 8];
472 hc
>>= -i
; /* i <= 0 */
473 if ((cidx
+= i
) > max_cidx
) {
474 retval
= 32; /* Huffman decoder out of step */
478 uncompressed
[width
* row
+ column
] =
479 uncompressed
[width
* row
+ column
- 2] - htable
[hc
].val
;
480 cidx
-= maxlen
- htable
[hc
].len
;
489 reverse(unsigned char *base
, size_t size
)
494 for (i
= 0, j
= size
- 1; i
< j
; i
++, j
--) {
502 brighten(unsigned char *base
, size_t size
)
505 unsigned char min
= UCHAR_MAX
, max
= 0, range
;
507 for (i
= 0; i
< size
; i
++) {
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
;
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
)
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
);
556 if ((raw_img
= malloc(width
* height
)) == NULL
) {
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) {
563 reverse(raw_img
, width
* height
);
565 brighten(raw_img
, width
* height
);
566 retval
= raw_img2png(png
, width
, height
, channels
,
567 bayer_pattern
, color_raiser
, raw_img
,
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
;
581 return 73; /* JPEG reversing not implemented */
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
)
593 fread(in_buf
, sizeof(in_buf
[0]), len
, 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
) {
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
,
621 if (compr_mode
== 0) { /* untested */
622 unsigned char *raw_img
;
624 if ((raw_img
= malloc(width
* height
)) == NULL
)
626 fread(raw_img
, sizeof(raw_img
[0]), width
* height
, in
);
629 reverse(raw_img
, width
* height
);
631 brighten(raw_img
, width
* height
);
632 retval
= raw_img2png(png
, width
, height
, channels
,
633 bayer_pattern
, color_raiser
, raw_img
,
639 return 5; /* Unknown compression mode */