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
*pimage
)
213 get_pix(image
*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
*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];
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 data
= realloc(data
, 30);
341 fread(data
, 29, 1, img
);
343 if( strcmp(data
, "http://ns.adobe.com/xap/1.0/") != 0 )
345 fseek(img
, offset
, SEEK_CUR
);
349 data
= realloc(data
, offset
+1);
350 fread(data
, offset
, 1, img
);
352 ParseNameValue(data
, offset
, &xml
);
353 exif
= GetValueFromNameValueList(&xml
, "DateTimeOriginal");
356 ClearNameValueList(&xml
);
359 *date
= realloc(*date
, strlen(exif
)+1);
361 ClearNameValueList(&xml
);
369 fread(&buf
, 2, 1, img
);
370 memcpy(&offset
, buf
, 2);
371 offset
= SWAP16(offset
) - 2;
372 fseek(img
, offset
, SEEK_CUR
);
382 image_new(int32_t width
, int32_t height
)
386 if((vimage
= (image
*)malloc(sizeof(image
))) == NULL
)
388 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
391 vimage
->width
= width
; vimage
->height
= height
;
393 if((vimage
->buf
= (pix
*)malloc(width
* height
* sizeof(pix
))) == NULL
)
395 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
403 image_new_from_jpeg(const char * path
, int is_file
, const char * buf
, int size
, int scale
)
407 struct jpeg_decompress_struct cinfo
;
408 unsigned char *line
[16], *ptr
;
409 int x
, y
, i
, w
, h
, ofs
;
411 struct jpeg_error_mgr pub
;
414 cinfo
.err
= jpeg_std_error(&pub
);
415 pub
.error_exit
= libjpeg_error_handler
;
416 jpeg_create_decompress(&cinfo
);
419 if( (file
= fopen(path
, "r")) == NULL
)
423 jpeg_stdio_src(&cinfo
, file
);
427 jpeg_memory_src(&cinfo
, (const unsigned char *)buf
, size
);
429 if( setjmp(setjmp_buffer
) )
431 jpeg_destroy_decompress(&cinfo
);
432 if( is_file
&& file
)
436 jpeg_read_header(&cinfo
, TRUE
);
437 cinfo
.scale_denom
= scale
;
438 cinfo
.do_fancy_upsampling
= FALSE
;
439 cinfo
.do_block_smoothing
= FALSE
;
440 jpeg_start_decompress(&cinfo
);
441 w
= cinfo
.output_width
;
442 h
= cinfo
.output_height
;
443 vimage
= image_new(w
, h
);
446 jpeg_destroy_decompress(&cinfo
);
452 if( setjmp(setjmp_buffer
) )
454 jpeg_destroy_decompress(&cinfo
);
455 if( is_file
&& file
)
466 if(cinfo
.rec_outbuf_height
> 16)
468 DPRINTF(E_WARN
, L_METADATA
, "ERROR image_from_jpeg : (image_from_jpeg.c) JPEG uses line buffers > 16. Cannot load.\n");
474 maxbuf
= vimage
->width
* vimage
->height
;
475 if(cinfo
.output_components
== 3)
478 if((ptr
= (unsigned char *)malloc(w
* 3 * cinfo
.rec_outbuf_height
)) == NULL
)
480 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
484 for(y
= 0; y
< h
; y
+= cinfo
.rec_outbuf_height
)
486 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
488 line
[i
] = ptr
+ (w
* 3 * i
);
490 jpeg_read_scanlines(&cinfo
, line
, cinfo
.rec_outbuf_height
);
491 for(x
= 0; x
< w
* cinfo
.rec_outbuf_height
; x
++)
495 vimage
->buf
[ofs
] = COL(ptr
[x
+ x
+ x
], ptr
[x
+ x
+ x
+ 1], ptr
[x
+ x
+ x
+ 2]);
502 else if(cinfo
.output_components
== 1)
505 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
507 if((line
[i
] = (unsigned char *)malloc(w
)) == NULL
)
511 for(t
= 0; t
< i
; t
++) free(line
[t
]);
512 jpeg_destroy_decompress(&cinfo
);
519 for(y
= 0; y
< h
; y
+= cinfo
.rec_outbuf_height
)
521 jpeg_read_scanlines(&cinfo
, line
, cinfo
.rec_outbuf_height
);
522 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
524 for(x
= 0; x
< w
; x
++)
526 vimage
->buf
[ofs
++] = COL(line
[i
][x
], line
[i
][x
], line
[i
][x
]);
530 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
535 jpeg_finish_decompress(&cinfo
);
536 jpeg_destroy_decompress(&cinfo
);
544 image_upsize(image
* pdest
, image
* psrc
, int32_t width
, int32_t height
)
547 #if !defined __i386__ && !defined __x86_64__
551 if((pdest
== NULL
) || (psrc
== NULL
))
554 for(vy
= 0; vy
< height
; vy
++)
556 for(vx
= 0; vx
< width
; vx
++)
558 rx
= ((vx
* psrc
->width
) / width
);
559 ry
= ((vy
* psrc
->height
) / height
);
560 vcol
= get_pix(psrc
, rx
, ry
);
562 pix vcol
,vcol1
,vcol2
,vcol3
,vcol4
;
564 float width_scale
, height_scale
;
565 float x_dist
, y_dist
;
567 width_scale
= (float)psrc
->width
/ (float)width
;
568 height_scale
= (float)psrc
->height
/ (float)height
;
570 for(vy
= 0;vy
< height
; vy
++)
572 for(vx
= 0;vx
< width
; vx
++)
574 rx
= vx
* width_scale
;
575 ry
= vy
* height_scale
;
576 vcol1
= get_pix(psrc
, (int32_t)rx
, (int32_t)ry
);
577 vcol2
= get_pix(psrc
, ((int32_t)rx
)+1, (int32_t)ry
);
578 vcol3
= get_pix(psrc
, (int32_t)rx
, ((int32_t)ry
)+1);
579 vcol4
= get_pix(psrc
, ((int32_t)rx
)+1, ((int32_t)ry
)+1);
581 x_dist
= rx
- ((float)((int32_t)rx
));
582 y_dist
= ry
- ((float)((int32_t)ry
));
583 vcol
= COL_FULL( (u_int8_t
)((COL_RED(vcol1
)*(1.0-x_dist
)
584 + COL_RED(vcol2
)*(x_dist
))*(1.0-y_dist
)
585 + (COL_RED(vcol3
)*(1.0-x_dist
)
586 + COL_RED(vcol4
)*(x_dist
))*(y_dist
)),
587 (u_int8_t
)((COL_GREEN(vcol1
)*(1.0-x_dist
)
588 + COL_GREEN(vcol2
)*(x_dist
))*(1.0-y_dist
)
589 + (COL_GREEN(vcol3
)*(1.0-x_dist
)
590 + COL_GREEN(vcol4
)*(x_dist
))*(y_dist
)),
591 (u_int8_t
)((COL_BLUE(vcol1
)*(1.0-x_dist
)
592 + COL_BLUE(vcol2
)*(x_dist
))*(1.0-y_dist
)
593 + (COL_BLUE(vcol3
)*(1.0-x_dist
)
594 + COL_BLUE(vcol4
)*(x_dist
))*(y_dist
)),
595 (u_int8_t
)((COL_ALPHA(vcol1
)*(1.0-x_dist
)
596 + COL_ALPHA(vcol2
)*(x_dist
))*(1.0-y_dist
)
597 + (COL_ALPHA(vcol3
)*(1.0-x_dist
)
598 + COL_ALPHA(vcol4
)*(x_dist
))*(y_dist
))
601 put_pix_alpha_replace(pdest
, vx
, vy
, vcol
);
607 image_downsize(image
* pdest
, image
* psrc
, int32_t width
, int32_t height
)
612 #if !defined __i386__ && !defined __x86_64__
613 int32_t rx
, ry
, rx_next
, ry_next
;
614 int red
, green
, blue
, alpha
;
617 if((pdest
== NULL
) || (psrc
== NULL
))
620 for(vy
= 0; vy
< height
; vy
++)
622 for(vx
= 0; vx
< width
; vx
++)
625 rx
= ((vx
* psrc
->width
) / width
);
626 ry
= ((vy
* psrc
->height
) / height
);
628 red
= green
= blue
= alpha
= 0;
630 rx_next
= rx
+ (psrc
->width
/ width
);
631 ry_next
= ry
+ (psrc
->width
/ width
);
634 for( j
= rx
; j
< rx_next
; j
++)
636 for( i
= ry
; i
< ry_next
; i
++)
639 vcol
= get_pix(psrc
, j
, i
);
641 red
+= COL_RED(vcol
);
642 green
+= COL_GREEN(vcol
);
643 blue
+= COL_BLUE(vcol
);
644 alpha
+= COL_ALPHA(vcol
);
653 /* on sature les valeurs */
654 red
= (red
> 255) ? 255 : ((red
< 0) ? 0 : red
);
655 green
= (green
> 255) ? 255 : ((green
< 0) ? 0 : green
);
656 blue
= (blue
> 255) ? 255 : ((blue
< 0) ? 0 : blue
);
657 alpha
= (alpha
> 255) ? 255 : ((alpha
< 0) ? 0 : alpha
);
660 float width_scale
, height_scale
;
661 float red
, green
, blue
, alpha
;
662 int32_t half_square_width
, half_square_height
;
663 float round_width
, round_height
;
665 if( (pdest
== NULL
) || (psrc
== NULL
) )
668 width_scale
= (float)psrc
->width
/ (float)width
;
669 height_scale
= (float)psrc
->height
/ (float)height
;
671 half_square_width
= (int32_t)(width_scale
/ 2.0);
672 half_square_height
= (int32_t)(height_scale
/ 2.0);
673 round_width
= (width_scale
/ 2.0) - (float)half_square_width
;
674 round_height
= (height_scale
/ 2.0) - (float)half_square_height
;
675 if(round_width
> 0.0)
679 if(round_height
> 0.0)
680 half_square_height
++;
684 for(vy
= 0;vy
< height
; vy
++)
686 for(vx
= 0;vx
< width
; vx
++)
688 rx
= vx
* width_scale
;
689 ry
= vy
* height_scale
;
690 vcol
= get_pix(psrc
, (int32_t)rx
, (int32_t)ry
);
692 red
= green
= blue
= alpha
= 0.0;
694 for(j
=0;j
<half_square_height
<<1;j
++)
696 for(i
=0;i
<half_square_width
<<1;i
++)
698 vcol
= get_pix(psrc
, ((int32_t)rx
)-half_square_width
+i
,
699 ((int32_t)ry
)-half_square_height
+j
);
701 if(((j
== 0) || (j
== (half_square_height
<<1)-1)) &&
702 ((i
== 0) || (i
== (half_square_width
<<1)-1)))
704 red
+= round_width
*round_height
*(float)COL_RED (vcol
);
705 green
+= round_width
*round_height
*(float)COL_GREEN(vcol
);
706 blue
+= round_width
*round_height
*(float)COL_BLUE (vcol
);
707 alpha
+= round_width
*round_height
*(float)COL_ALPHA(vcol
);
709 else if((j
== 0) || (j
== (half_square_height
<<1)-1))
711 red
+= round_height
*(float)COL_RED (vcol
);
712 green
+= round_height
*(float)COL_GREEN(vcol
);
713 blue
+= round_height
*(float)COL_BLUE (vcol
);
714 alpha
+= round_height
*(float)COL_ALPHA(vcol
);
716 else if((i
== 0) || (i
== (half_square_width
<<1)-1))
718 red
+= round_width
*(float)COL_RED (vcol
);
719 green
+= round_width
*(float)COL_GREEN(vcol
);
720 blue
+= round_width
*(float)COL_BLUE (vcol
);
721 alpha
+= round_width
*(float)COL_ALPHA(vcol
);
725 red
+= (float)COL_RED (vcol
);
726 green
+= (float)COL_GREEN(vcol
);
727 blue
+= (float)COL_BLUE (vcol
);
728 alpha
+= (float)COL_ALPHA(vcol
);
733 red
/= width_scale
*height_scale
;
734 green
/= width_scale
*height_scale
;
735 blue
/= width_scale
*height_scale
;
736 alpha
/= width_scale
*height_scale
;
738 /* on sature les valeurs */
739 red
= (red
> 255.0)? 255.0 : ((red
< 0.0)? 0.0:red
);
740 green
= (green
> 255.0)? 255.0 : ((green
< 0.0)? 0.0:green
);
741 blue
= (blue
> 255.0)? 255.0 : ((blue
< 0.0)? 0.0:blue
);
742 alpha
= (alpha
> 255.0)? 255.0 : ((alpha
< 0.0)? 0.0:alpha
);
744 put_pix_alpha_replace(pdest
, vx
, vy
,
745 COL_FULL((u_int8_t
)red
, (u_int8_t
)green
, (u_int8_t
)blue
, (u_int8_t
)alpha
));
751 image_resize(image
* src_image
, int32_t width
, int32_t height
)
755 dst_image
= image_new(width
, height
);
758 if( (src_image
->width
< width
) || (src_image
->height
< height
) )
759 image_upsize(dst_image
, src_image
, width
, height
);
761 image_downsize(dst_image
, src_image
, width
, height
);
768 image_save_to_jpeg_buf(image
* pimage
, int * size
)
770 struct jpeg_compress_struct cinfo
;
771 struct jpeg_error_mgr jerr
;
772 JSAMPROW row_pointer
[1];
776 struct my_dst_mgr dst
;
778 cinfo
.err
= jpeg_std_error(&jerr
);
779 jpeg_create_compress(&cinfo
);
780 jpeg_memory_dest(&cinfo
, &dst
);
781 cinfo
.image_width
= pimage
->width
;
782 cinfo
.image_height
= pimage
->height
;
783 cinfo
.input_components
= 3;
784 cinfo
.in_color_space
= JCS_RGB
;
785 jpeg_set_defaults(&cinfo
);
786 jpeg_set_quality(&cinfo
, JPEG_QUALITY
, TRUE
);
787 jpeg_start_compress(&cinfo
, TRUE
);
788 row_stride
= cinfo
.image_width
* 3;
789 if((data
= malloc(row_stride
)) == NULL
)
791 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
795 while(cinfo
.next_scanline
< cinfo
.image_height
)
797 for(x
= 0; x
< pimage
->width
; x
++)
799 data
[x
+ x
+ x
] = COL_RED(pimage
->buf
[i
]);
800 data
[x
+ x
+ x
+ 1] = COL_GREEN(pimage
->buf
[i
]);
801 data
[x
+ x
+ x
+ 2] = COL_BLUE(pimage
->buf
[i
]);
804 row_pointer
[0] = (unsigned char *)data
;
805 jpeg_write_scanlines(&cinfo
, row_pointer
, 1);
807 jpeg_finish_compress(&cinfo
);
810 jpeg_destroy_compress(&cinfo
);
816 image_save_to_jpeg_file(image
* pimage
, const char * path
)
818 int nwritten
, size
= 0;
822 buf
= image_save_to_jpeg_buf(pimage
, &size
);
825 dst_file
= fopen(path
, "w");
831 nwritten
= fwrite(buf
, 1, size
, dst_file
);
835 return (nwritten
==size
? 0 : 1);