1 /* MiniDLNA media server
2 * Copyright (C) 2009 Justin Maggard
4 * This file is part of MiniDLNA.
6 * MiniDLNA is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * MiniDLNA is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
19 /* These functions are mostly based on code from other projects.
20 * There are function to effiently resize a JPEG image, and some utility functions.
21 * They are here to allow loading and saving JPEG data directly to or from memory with libjpeg.
22 * The standard functions only allow you to read from or write to a file.
24 * The reading code comes from the JpgAlleg library, at http://wiki.allegro.cc/index.php?title=Libjpeg
25 * The writing code was posted on a Google group from openjpeg, at http://groups.google.com/group/openjpeg/browse_thread/thread/331e6cf60f70797f
26 * The resize functions come from the resize_image project, at http://www.golac.fr/Image-Resizer
33 #include <sys/types.h>
38 #include "upnpreplyparse.h"
39 #include "image_utils.h"
42 #if __BYTE_ORDER == __LITTLE_ENDIAN
43 # define SWAP16(w) ( (((w) >> 8) & 0x00ff) | (((w) << 8) & 0xff00) )
45 # define SWAP16(w) (w)
48 #define JPEG_QUALITY 96
50 #define COL(red, green, blue) (((red) << 24) | ((green) << 16) | ((blue) << 8) | 0xFF)
51 #define COL_FULL(red, green, blue, alpha) (((red) << 24) | ((green) << 16) | ((blue) << 8) | (alpha))
52 #define COL_RED(col) (col >> 24)
53 #define COL_GREEN(col) ((col >> 16) & 0xFF)
54 #define COL_BLUE(col) ((col >> 8) & 0xFF)
55 #define COL_ALPHA(col) (col & 0xFF)
56 #define BLACK 0x000000FF
60 struct jpeg_destination_mgr jdst
;
67 /* Destination manager to store data in a buffer */
69 my_dst_mgr_init(j_compress_ptr cinfo
)
71 struct my_dst_mgr
*dst
= (void *)cinfo
->dest
;
74 dst
->sz
= cinfo
->image_width
76 * cinfo
->input_components
;
77 dst
->buf
= malloc(dst
->sz
* sizeof *dst
->buf
);
79 dst
->jdst
.next_output_byte
= dst
->off
;
80 dst
->jdst
.free_in_buffer
= dst
->sz
;
87 my_dst_mgr_empty(j_compress_ptr cinfo
)
89 struct my_dst_mgr
*dst
= (void *)cinfo
->dest
;
92 dst
->used
= dst
->off
- dst
->buf
;
93 dst
->buf
= realloc(dst
->buf
, dst
->sz
* sizeof *dst
->buf
);
94 dst
->off
= dst
->buf
+ dst
->used
;
95 dst
->jdst
.next_output_byte
= dst
->off
;
96 dst
->jdst
.free_in_buffer
= dst
->sz
- dst
->used
;
103 my_dst_mgr_term(j_compress_ptr cinfo
)
105 struct my_dst_mgr
*dst
= (void *)cinfo
->dest
;
107 dst
->used
+= dst
->sz
- dst
->jdst
.free_in_buffer
;
108 dst
->off
= dst
->buf
+ dst
->used
;
115 jpeg_memory_dest(j_compress_ptr cinfo
, struct my_dst_mgr
*dst
)
117 dst
->jdst
.init_destination
= my_dst_mgr_init
;
118 dst
->jdst
.empty_output_buffer
= my_dst_mgr_empty
;
119 dst
->jdst
.term_destination
= my_dst_mgr_term
;
120 cinfo
->dest
= (void *)dst
;
126 /* Source manager to read data from a buffer */
130 struct jpeg_source_mgr pub
;
131 JOCTET eoi_buffer
[2];
135 init_source(j_decompress_ptr cinfo
)
141 fill_input_buffer(j_decompress_ptr cinfo
)
143 struct my_src_mgr
*src
= (void *)cinfo
->src
;
145 /* Create a fake EOI marker */
146 src
->eoi_buffer
[0] = (JOCTET
) 0xFF;
147 src
->eoi_buffer
[1] = (JOCTET
) JPEG_EOI
;
148 src
->pub
.next_input_byte
= src
->eoi_buffer
;
149 src
->pub
.bytes_in_buffer
= 2;
155 skip_input_data(j_decompress_ptr cinfo
, long num_bytes
)
157 struct my_src_mgr
*src
= (void *)cinfo
->src
;
160 while (num_bytes
> (long)src
->pub
.bytes_in_buffer
)
162 num_bytes
-= (long)src
->pub
.bytes_in_buffer
;
163 fill_input_buffer(cinfo
);
166 src
->pub
.next_input_byte
+= num_bytes
;
167 src
->pub
.bytes_in_buffer
-= num_bytes
;
171 term_source(j_decompress_ptr cinfo
)
177 jpeg_memory_src(j_decompress_ptr cinfo
, const unsigned char * buffer
, size_t bufsize
)
179 struct my_src_mgr
*src
;
183 cinfo
->src
= (*cinfo
->mem
->alloc_small
)((void *)cinfo
, JPOOL_PERMANENT
, sizeof(struct my_src_mgr
));;
185 src
= (void *)cinfo
->src
;
186 src
->pub
.init_source
= init_source
;
187 src
->pub
.fill_input_buffer
= fill_input_buffer
;
188 src
->pub
.skip_input_data
= skip_input_data
;
189 src
->pub
.resync_to_restart
= jpeg_resync_to_restart
;
190 src
->pub
.term_source
= term_source
;
191 src
->pub
.next_input_byte
= buffer
;
192 src
->pub
.bytes_in_buffer
= bufsize
;
195 jmp_buf setjmp_buffer
;
196 /* Don't exit on error like libjpeg likes to do */
198 libjpeg_error_handler(j_common_ptr cinfo
)
200 cinfo
->err
->output_message(cinfo
);
201 longjmp(setjmp_buffer
, 1);
206 image_free(image_s
*pimage
)
213 get_pix(image_s
*pimage
, int32_t x
, int32_t y
)
215 if((x
>= 0) && (y
>= 0) && (x
< pimage
->width
) && (y
< pimage
->height
))
217 return(pimage
->buf
[(y
* pimage
->width
) + x
]);
227 put_pix_alpha_replace(image_s
*pimage
, int32_t x
, int32_t y
, pix col
)
229 if((x
>= 0) && (y
>= 0) && (x
< pimage
->width
) && (y
< pimage
->height
))
230 pimage
->buf
[(y
* pimage
->width
) + x
] = col
;
234 image_get_jpeg_resolution(const char * path
, int * width
, int * height
)
237 unsigned char buf
[8];
238 u_int16_t offset
, h
, w
;
243 img
= fopen(path
, "r");
247 fseek(img
, 0, SEEK_END
);
251 fread(&buf
, 2, 1, img
);
252 if( (buf
[0] != 0xFF) || (buf
[1] != 0xD8) )
257 memset(&buf
, 0, sizeof(buf
));
259 while( ftell(img
) < size
)
261 while( buf
[0] != 0xFF && !feof(img
) )
262 fread(&buf
, 1, 1, img
);
264 while( buf
[0] == 0xFF && !feof(img
) )
265 fread(&buf
, 1, 1, img
);
267 if( (buf
[0] >= 0xc0) && (buf
[0] <= 0xc3) )
269 fread(&buf
, 7, 1, img
);
272 memcpy(&h
, buf
+3, 2);
274 memcpy(&w
, buf
+5, 2);
282 fread(&buf
, 2, 1, img
);
283 memcpy(&offset
, buf
, 2);
284 offset
= SWAP16(offset
) - 2;
285 if( fseek(img
, offset
, SEEK_CUR
) == -1 )
294 image_get_jpeg_date_xmp(const char * path
, char ** date
)
297 unsigned char buf
[8];
298 char *data
= NULL
, *newdata
;
300 struct NameValueParserData xml
;
304 img
= fopen(path
, "r");
308 fread(&buf
, 2, 1, img
);
309 if( (buf
[0] != 0xFF) || (buf
[1] != 0xD8) )
314 memset(&buf
, 0, sizeof(buf
));
318 while( buf
[0] != 0xFF && !feof(img
) )
319 fread(&buf
, 1, 1, img
);
321 while( buf
[0] == 0xFF && !feof(img
) )
322 fread(&buf
, 1, 1, img
);
327 if( buf
[0] == 0xE1 ) // APP1 marker
330 fread(&buf
, 2, 1, img
);
331 memcpy(&offset
, buf
, 2);
332 offset
= SWAP16(offset
) - 2;
336 fseek(img
, offset
, SEEK_CUR
);
340 newdata
= realloc(data
, 30);
345 fread(data
, 29, 1, img
);
347 if( strcmp(data
, "http://ns.adobe.com/xap/1.0/") != 0 )
349 fseek(img
, offset
, SEEK_CUR
);
353 newdata
= realloc(data
, offset
+1);
357 fread(data
, offset
, 1, img
);
359 ParseNameValue(data
, offset
, &xml
);
360 exif
= GetValueFromNameValueList(&xml
, "DateTimeOriginal");
363 ClearNameValueList(&xml
);
366 *date
= realloc(*date
, strlen(exif
)+1);
368 ClearNameValueList(&xml
);
376 fread(&buf
, 2, 1, img
);
377 memcpy(&offset
, buf
, 2);
378 offset
= SWAP16(offset
) - 2;
379 fseek(img
, offset
, SEEK_CUR
);
389 image_new(int32_t width
, int32_t height
)
393 if((vimage
= (image_s
*)malloc(sizeof(image_s
))) == NULL
)
395 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
398 vimage
->width
= width
; vimage
->height
= height
;
400 if((vimage
->buf
= (pix
*)malloc(width
* height
* sizeof(pix
))) == NULL
)
402 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
410 image_new_from_jpeg(const char * path
, int is_file
, const char * buf
, int size
, int scale
)
414 struct jpeg_decompress_struct cinfo
;
415 unsigned char *line
[16], *ptr
;
416 int x
, y
, i
, w
, h
, ofs
;
418 struct jpeg_error_mgr pub
;
421 cinfo
.err
= jpeg_std_error(&pub
);
422 pub
.error_exit
= libjpeg_error_handler
;
423 jpeg_create_decompress(&cinfo
);
426 if( (file
= fopen(path
, "r")) == NULL
)
430 jpeg_stdio_src(&cinfo
, file
);
434 jpeg_memory_src(&cinfo
, (const unsigned char *)buf
, size
);
436 if( setjmp(setjmp_buffer
) )
438 jpeg_destroy_decompress(&cinfo
);
439 if( is_file
&& file
)
443 jpeg_read_header(&cinfo
, TRUE
);
444 cinfo
.scale_denom
= scale
;
445 cinfo
.do_fancy_upsampling
= FALSE
;
446 cinfo
.do_block_smoothing
= FALSE
;
447 jpeg_start_decompress(&cinfo
);
448 w
= cinfo
.output_width
;
449 h
= cinfo
.output_height
;
450 vimage
= image_new(w
, h
);
453 jpeg_destroy_decompress(&cinfo
);
459 if( setjmp(setjmp_buffer
) )
461 jpeg_destroy_decompress(&cinfo
);
462 if( is_file
&& file
)
473 if(cinfo
.rec_outbuf_height
> 16)
475 DPRINTF(E_WARN
, L_METADATA
, "ERROR image_from_jpeg : (image_from_jpeg.c) JPEG uses line buffers > 16. Cannot load.\n");
481 maxbuf
= vimage
->width
* vimage
->height
;
482 if(cinfo
.output_components
== 3)
485 if((ptr
= (unsigned char *)malloc(w
* 3 * cinfo
.rec_outbuf_height
+ 16)) == NULL
)
487 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
494 for(y
= 0; y
< h
; y
+= cinfo
.rec_outbuf_height
)
496 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
498 line
[i
] = ptr
+ (w
* 3 * i
);
500 jpeg_read_scanlines(&cinfo
, line
, cinfo
.rec_outbuf_height
);
501 for(x
= 0; x
< w
* cinfo
.rec_outbuf_height
; x
++)
505 vimage
->buf
[ofs
] = COL(ptr
[x
+ x
+ x
], ptr
[x
+ x
+ x
+ 1], ptr
[x
+ x
+ x
+ 2]);
512 else if(cinfo
.output_components
== 1)
515 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
517 if((line
[i
] = (unsigned char *)malloc(w
)) == NULL
)
521 for(t
= 0; t
< i
; t
++) free(line
[t
]);
522 jpeg_destroy_decompress(&cinfo
);
529 for(y
= 0; y
< h
; y
+= cinfo
.rec_outbuf_height
)
531 jpeg_read_scanlines(&cinfo
, line
, cinfo
.rec_outbuf_height
);
532 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
534 for(x
= 0; x
< w
; x
++)
536 vimage
->buf
[ofs
++] = COL(line
[i
][x
], line
[i
][x
], line
[i
][x
]);
540 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
545 jpeg_finish_decompress(&cinfo
);
546 jpeg_destroy_decompress(&cinfo
);
554 image_upsize(image_s
* pdest
, image_s
* psrc
, int32_t width
, int32_t height
)
557 #if !defined __i386__ && !defined __x86_64__
561 if((pdest
== NULL
) || (psrc
== NULL
))
564 for(vy
= 0; vy
< height
; vy
++)
566 for(vx
= 0; vx
< width
; vx
++)
568 rx
= ((vx
* psrc
->width
) / width
);
569 ry
= ((vy
* psrc
->height
) / height
);
570 vcol
= get_pix(psrc
, rx
, ry
);
572 pix vcol
,vcol1
,vcol2
,vcol3
,vcol4
;
574 float width_scale
, height_scale
;
575 float x_dist
, y_dist
;
577 width_scale
= (float)psrc
->width
/ (float)width
;
578 height_scale
= (float)psrc
->height
/ (float)height
;
580 for(vy
= 0;vy
< height
; vy
++)
582 for(vx
= 0;vx
< width
; vx
++)
584 rx
= vx
* width_scale
;
585 ry
= vy
* height_scale
;
586 vcol1
= get_pix(psrc
, (int32_t)rx
, (int32_t)ry
);
587 vcol2
= get_pix(psrc
, ((int32_t)rx
)+1, (int32_t)ry
);
588 vcol3
= get_pix(psrc
, (int32_t)rx
, ((int32_t)ry
)+1);
589 vcol4
= get_pix(psrc
, ((int32_t)rx
)+1, ((int32_t)ry
)+1);
591 x_dist
= rx
- ((float)((int32_t)rx
));
592 y_dist
= ry
- ((float)((int32_t)ry
));
593 vcol
= COL_FULL( (u_int8_t
)((COL_RED(vcol1
)*(1.0-x_dist
)
594 + COL_RED(vcol2
)*(x_dist
))*(1.0-y_dist
)
595 + (COL_RED(vcol3
)*(1.0-x_dist
)
596 + COL_RED(vcol4
)*(x_dist
))*(y_dist
)),
597 (u_int8_t
)((COL_GREEN(vcol1
)*(1.0-x_dist
)
598 + COL_GREEN(vcol2
)*(x_dist
))*(1.0-y_dist
)
599 + (COL_GREEN(vcol3
)*(1.0-x_dist
)
600 + COL_GREEN(vcol4
)*(x_dist
))*(y_dist
)),
601 (u_int8_t
)((COL_BLUE(vcol1
)*(1.0-x_dist
)
602 + COL_BLUE(vcol2
)*(x_dist
))*(1.0-y_dist
)
603 + (COL_BLUE(vcol3
)*(1.0-x_dist
)
604 + COL_BLUE(vcol4
)*(x_dist
))*(y_dist
)),
605 (u_int8_t
)((COL_ALPHA(vcol1
)*(1.0-x_dist
)
606 + COL_ALPHA(vcol2
)*(x_dist
))*(1.0-y_dist
)
607 + (COL_ALPHA(vcol3
)*(1.0-x_dist
)
608 + COL_ALPHA(vcol4
)*(x_dist
))*(y_dist
))
611 put_pix_alpha_replace(pdest
, vx
, vy
, vcol
);
617 image_downsize(image_s
* pdest
, image_s
* psrc
, int32_t width
, int32_t height
)
622 #if !defined __i386__ && !defined __x86_64__
623 int32_t rx
, ry
, rx_next
, ry_next
;
624 int red
, green
, blue
, alpha
;
627 if((pdest
== NULL
) || (psrc
== NULL
))
630 for(vy
= 0; vy
< height
; vy
++)
632 for(vx
= 0; vx
< width
; vx
++)
635 rx
= ((vx
* psrc
->width
) / width
);
636 ry
= ((vy
* psrc
->height
) / height
);
638 red
= green
= blue
= alpha
= 0;
640 rx_next
= rx
+ (psrc
->width
/ width
);
641 ry_next
= ry
+ (psrc
->width
/ width
);
644 for( j
= rx
; j
< rx_next
; j
++)
646 for( i
= ry
; i
< ry_next
; i
++)
649 vcol
= get_pix(psrc
, j
, i
);
651 red
+= COL_RED(vcol
);
652 green
+= COL_GREEN(vcol
);
653 blue
+= COL_BLUE(vcol
);
654 alpha
+= COL_ALPHA(vcol
);
663 /* on sature les valeurs */
664 red
= (red
> 255) ? 255 : ((red
< 0) ? 0 : red
);
665 green
= (green
> 255) ? 255 : ((green
< 0) ? 0 : green
);
666 blue
= (blue
> 255) ? 255 : ((blue
< 0) ? 0 : blue
);
667 alpha
= (alpha
> 255) ? 255 : ((alpha
< 0) ? 0 : alpha
);
670 float width_scale
, height_scale
;
671 float red
, green
, blue
, alpha
;
672 int32_t half_square_width
, half_square_height
;
673 float round_width
, round_height
;
675 if( (pdest
== NULL
) || (psrc
== NULL
) )
678 width_scale
= (float)psrc
->width
/ (float)width
;
679 height_scale
= (float)psrc
->height
/ (float)height
;
681 half_square_width
= (int32_t)(width_scale
/ 2.0);
682 half_square_height
= (int32_t)(height_scale
/ 2.0);
683 round_width
= (width_scale
/ 2.0) - (float)half_square_width
;
684 round_height
= (height_scale
/ 2.0) - (float)half_square_height
;
685 if(round_width
> 0.0)
689 if(round_height
> 0.0)
690 half_square_height
++;
694 for(vy
= 0;vy
< height
; vy
++)
696 for(vx
= 0;vx
< width
; vx
++)
698 rx
= vx
* width_scale
;
699 ry
= vy
* height_scale
;
700 vcol
= get_pix(psrc
, (int32_t)rx
, (int32_t)ry
);
702 red
= green
= blue
= alpha
= 0.0;
704 for(j
=0;j
<half_square_height
<<1;j
++)
706 for(i
=0;i
<half_square_width
<<1;i
++)
708 vcol
= get_pix(psrc
, ((int32_t)rx
)-half_square_width
+i
,
709 ((int32_t)ry
)-half_square_height
+j
);
711 if(((j
== 0) || (j
== (half_square_height
<<1)-1)) &&
712 ((i
== 0) || (i
== (half_square_width
<<1)-1)))
714 red
+= round_width
*round_height
*(float)COL_RED (vcol
);
715 green
+= round_width
*round_height
*(float)COL_GREEN(vcol
);
716 blue
+= round_width
*round_height
*(float)COL_BLUE (vcol
);
717 alpha
+= round_width
*round_height
*(float)COL_ALPHA(vcol
);
719 else if((j
== 0) || (j
== (half_square_height
<<1)-1))
721 red
+= round_height
*(float)COL_RED (vcol
);
722 green
+= round_height
*(float)COL_GREEN(vcol
);
723 blue
+= round_height
*(float)COL_BLUE (vcol
);
724 alpha
+= round_height
*(float)COL_ALPHA(vcol
);
726 else if((i
== 0) || (i
== (half_square_width
<<1)-1))
728 red
+= round_width
*(float)COL_RED (vcol
);
729 green
+= round_width
*(float)COL_GREEN(vcol
);
730 blue
+= round_width
*(float)COL_BLUE (vcol
);
731 alpha
+= round_width
*(float)COL_ALPHA(vcol
);
735 red
+= (float)COL_RED (vcol
);
736 green
+= (float)COL_GREEN(vcol
);
737 blue
+= (float)COL_BLUE (vcol
);
738 alpha
+= (float)COL_ALPHA(vcol
);
743 red
/= width_scale
*height_scale
;
744 green
/= width_scale
*height_scale
;
745 blue
/= width_scale
*height_scale
;
746 alpha
/= width_scale
*height_scale
;
748 /* on sature les valeurs */
749 red
= (red
> 255.0)? 255.0 : ((red
< 0.0)? 0.0:red
);
750 green
= (green
> 255.0)? 255.0 : ((green
< 0.0)? 0.0:green
);
751 blue
= (blue
> 255.0)? 255.0 : ((blue
< 0.0)? 0.0:blue
);
752 alpha
= (alpha
> 255.0)? 255.0 : ((alpha
< 0.0)? 0.0:alpha
);
754 put_pix_alpha_replace(pdest
, vx
, vy
,
755 COL_FULL((u_int8_t
)red
, (u_int8_t
)green
, (u_int8_t
)blue
, (u_int8_t
)alpha
));
761 image_resize(image_s
* src_image
, int32_t width
, int32_t height
)
765 dst_image
= image_new(width
, height
);
768 if( (src_image
->width
< width
) || (src_image
->height
< height
) )
769 image_upsize(dst_image
, src_image
, width
, height
);
771 image_downsize(dst_image
, src_image
, width
, height
);
778 image_save_to_jpeg_buf(image_s
* pimage
, int * size
)
780 struct jpeg_compress_struct cinfo
;
781 struct jpeg_error_mgr jerr
;
782 JSAMPROW row_pointer
[1];
786 struct my_dst_mgr dst
;
788 cinfo
.err
= jpeg_std_error(&jerr
);
789 jpeg_create_compress(&cinfo
);
790 jpeg_memory_dest(&cinfo
, &dst
);
791 cinfo
.image_width
= pimage
->width
;
792 cinfo
.image_height
= pimage
->height
;
793 cinfo
.input_components
= 3;
794 cinfo
.in_color_space
= JCS_RGB
;
795 jpeg_set_defaults(&cinfo
);
796 jpeg_set_quality(&cinfo
, JPEG_QUALITY
, TRUE
);
797 jpeg_start_compress(&cinfo
, TRUE
);
798 row_stride
= cinfo
.image_width
* 3;
799 if((data
= malloc(row_stride
)) == NULL
)
801 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
805 while(cinfo
.next_scanline
< cinfo
.image_height
)
807 for(x
= 0; x
< pimage
->width
; x
++)
809 data
[x
+ x
+ x
] = COL_RED(pimage
->buf
[i
]);
810 data
[x
+ x
+ x
+ 1] = COL_GREEN(pimage
->buf
[i
]);
811 data
[x
+ x
+ x
+ 2] = COL_BLUE(pimage
->buf
[i
]);
814 row_pointer
[0] = (unsigned char *)data
;
815 jpeg_write_scanlines(&cinfo
, row_pointer
, 1);
817 jpeg_finish_compress(&cinfo
);
820 jpeg_destroy_compress(&cinfo
);
826 image_save_to_jpeg_file(image_s
* pimage
, const char * path
)
828 int nwritten
, size
= 0;
832 buf
= image_save_to_jpeg_buf(pimage
, &size
);
835 dst_file
= fopen(path
, "w");
841 nwritten
= fwrite(buf
, 1, size
, dst_file
);
845 return (nwritten
==size
? 0 : 1);