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
36 #ifdef HAVE_MACHINE_ENDIAN_H
37 #include <machine/endian.h>
42 #include "upnpreplyparse.h"
43 #include "image_utils.h"
46 #if __BYTE_ORDER == __LITTLE_ENDIAN
47 # define SWAP16(w) ( (((w) >> 8) & 0x00ff) | (((w) << 8) & 0xff00) )
49 # define SWAP16(w) (w)
52 #define JPEG_QUALITY 96
54 #define COL(red, green, blue) (((red) << 24) | ((green) << 16) | ((blue) << 8) | 0xFF)
55 #define COL_FULL(red, green, blue, alpha) (((red) << 24) | ((green) << 16) | ((blue) << 8) | (alpha))
56 #define COL_RED(col) (col >> 24)
57 #define COL_GREEN(col) ((col >> 16) & 0xFF)
58 #define COL_BLUE(col) ((col >> 8) & 0xFF)
59 #define COL_ALPHA(col) (col & 0xFF)
60 #define BLACK 0x000000FF
64 struct jpeg_destination_mgr jdst
;
71 /* Destination manager to store data in a buffer */
73 my_dst_mgr_init(j_compress_ptr cinfo
)
75 struct my_dst_mgr
*dst
= (void *)cinfo
->dest
;
78 dst
->sz
= cinfo
->image_width
80 * cinfo
->input_components
;
81 dst
->buf
= malloc(dst
->sz
* sizeof *dst
->buf
);
83 dst
->jdst
.next_output_byte
= dst
->off
;
84 dst
->jdst
.free_in_buffer
= dst
->sz
;
90 my_dst_mgr_empty(j_compress_ptr cinfo
)
92 struct my_dst_mgr
*dst
= (void *)cinfo
->dest
;
95 dst
->used
= dst
->off
- dst
->buf
;
96 dst
->buf
= realloc(dst
->buf
, dst
->sz
* sizeof *dst
->buf
);
97 dst
->off
= dst
->buf
+ dst
->used
;
98 dst
->jdst
.next_output_byte
= dst
->off
;
99 dst
->jdst
.free_in_buffer
= dst
->sz
- dst
->used
;
105 my_dst_mgr_term(j_compress_ptr cinfo
)
107 struct my_dst_mgr
*dst
= (void *)cinfo
->dest
;
109 dst
->used
+= dst
->sz
- dst
->jdst
.free_in_buffer
;
110 dst
->off
= dst
->buf
+ dst
->used
;
116 jpeg_memory_dest(j_compress_ptr cinfo
, struct my_dst_mgr
*dst
)
118 dst
->jdst
.init_destination
= my_dst_mgr_init
;
119 dst
->jdst
.empty_output_buffer
= my_dst_mgr_empty
;
120 dst
->jdst
.term_destination
= my_dst_mgr_term
;
121 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
;
182 cinfo
->src
= (*cinfo
->mem
->alloc_small
)((void *)cinfo
, JPOOL_PERMANENT
, sizeof(struct my_src_mgr
));;
183 src
= (void *)cinfo
->src
;
184 src
->pub
.init_source
= init_source
;
185 src
->pub
.fill_input_buffer
= fill_input_buffer
;
186 src
->pub
.skip_input_data
= skip_input_data
;
187 src
->pub
.resync_to_restart
= jpeg_resync_to_restart
;
188 src
->pub
.term_source
= term_source
;
189 src
->pub
.next_input_byte
= buffer
;
190 src
->pub
.bytes_in_buffer
= bufsize
;
193 jmp_buf setjmp_buffer
;
194 /* Don't exit on error like libjpeg likes to do */
196 libjpeg_error_handler(j_common_ptr cinfo
)
198 cinfo
->err
->output_message(cinfo
);
199 longjmp(setjmp_buffer
, 1);
204 image_free(image_s
*pimage
)
211 get_pix(image_s
*pimage
, int32_t x
, int32_t y
)
215 else if (x
>= pimage
->width
)
216 x
= pimage
->width
- 1;
220 else if (y
>= pimage
->height
)
221 y
= pimage
->height
- 1;
223 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 uint16_t offset
, h
, w
;
244 img
= fopen(path
, "r");
248 fseek(img
, 0, SEEK_END
);
252 nread
= fread(&buf
, 2, 1, img
);
253 if( (nread
< 1) || (buf
[0] != 0xFF) || (buf
[1] != 0xD8) )
258 memset(&buf
, 0, sizeof(buf
));
260 while( ftell(img
) < size
)
262 while( nread
> 0 && buf
[0] != 0xFF && !feof(img
) )
263 nread
= fread(&buf
, 1, 1, img
);
265 while( nread
> 0 && buf
[0] == 0xFF && !feof(img
) )
266 nread
= fread(&buf
, 1, 1, img
);
268 if( (buf
[0] >= 0xc0) && (buf
[0] <= 0xc3) )
270 nread
= fread(&buf
, 7, 1, img
);
275 memcpy(&h
, buf
+3, 2);
277 memcpy(&w
, buf
+5, 2);
285 nread
= fread(&buf
, 2, 1, img
);
288 memcpy(&offset
, buf
, 2);
289 offset
= SWAP16(offset
) - 2;
290 if( fseek(img
, offset
, SEEK_CUR
) == -1 )
299 image_get_jpeg_date_xmp(const char * path
, char ** date
)
302 unsigned char buf
[8];
303 char *data
= NULL
, *newdata
;
305 struct NameValueParserData xml
;
310 img
= fopen(path
, "r");
314 nread
= fread(&buf
, 2, 1, img
);
315 if( (nread
< 1) || (buf
[0] != 0xFF) || (buf
[1] != 0xD8) )
320 memset(&buf
, 0, sizeof(buf
));
324 while( nread
> 0 && buf
[0] != 0xFF && !feof(img
) )
325 nread
= fread(&buf
, 1, 1, img
);
327 while( nread
> 0 && buf
[0] == 0xFF && !feof(img
) )
328 nread
= fread(&buf
, 1, 1, img
);
333 if( buf
[0] == 0xE1 ) // APP1 marker
336 nread
= fread(&buf
, 2, 1, img
);
339 memcpy(&offset
, buf
, 2);
340 offset
= SWAP16(offset
) - 2;
344 fseek(img
, offset
, SEEK_CUR
);
348 newdata
= realloc(data
, 30);
353 nread
= fread(data
, 29, 1, img
);
357 if( strcmp(data
, "http://ns.adobe.com/xap/1.0/") != 0 )
359 fseek(img
, offset
, SEEK_CUR
);
363 newdata
= realloc(data
, offset
+1);
367 nread
= fread(data
, offset
, 1, img
);
371 ParseNameValue(data
, offset
, &xml
, 0);
372 exif
= GetValueFromNameValueList(&xml
, "DateTimeOriginal");
375 ClearNameValueList(&xml
);
378 *date
= realloc(*date
, strlen(exif
)+1);
380 ClearNameValueList(&xml
);
388 nread
= fread(&buf
, 2, 1, img
);
391 memcpy(&offset
, buf
, 2);
392 offset
= SWAP16(offset
) - 2;
393 fseek(img
, offset
, SEEK_CUR
);
402 image_new(int32_t width
, int32_t height
)
406 if((vimage
= (image_s
*)malloc(sizeof(image_s
))) == NULL
)
408 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
411 vimage
->width
= width
; vimage
->height
= height
;
413 if((vimage
->buf
= (pix
*)malloc(width
* height
* sizeof(pix
))) == NULL
)
415 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
423 image_new_from_jpeg(const char *path
, int is_file
, const uint8_t *buf
, int size
, int scale
, int rotate
)
427 struct jpeg_decompress_struct cinfo
;
428 unsigned char *line
[16], *ptr
;
429 int x
, y
, i
, w
, h
, ofs
;
431 struct jpeg_error_mgr pub
;
433 cinfo
.err
= jpeg_std_error(&pub
);
434 pub
.error_exit
= libjpeg_error_handler
;
435 jpeg_create_decompress(&cinfo
);
438 if( (file
= fopen(path
, "r")) == NULL
)
442 jpeg_stdio_src(&cinfo
, file
);
446 jpeg_memory_src(&cinfo
, buf
, size
);
448 if( setjmp(setjmp_buffer
) )
450 jpeg_destroy_decompress(&cinfo
);
451 if( is_file
&& file
)
455 jpeg_read_header(&cinfo
, TRUE
);
456 cinfo
.scale_denom
= scale
;
457 cinfo
.do_fancy_upsampling
= FALSE
;
458 cinfo
.do_block_smoothing
= FALSE
;
459 cinfo
.dct_method
= JDCT_IFAST
;
460 jpeg_start_decompress(&cinfo
);
461 w
= cinfo
.output_width
;
462 h
= cinfo
.output_height
;
463 vimage
= (rotate
& (ROTATE_90
|ROTATE_270
)) ? image_new(h
, w
) : image_new(w
, h
);
466 jpeg_destroy_decompress(&cinfo
);
472 if( setjmp(setjmp_buffer
) )
474 jpeg_destroy_decompress(&cinfo
);
475 if( is_file
&& file
)
485 if(cinfo
.rec_outbuf_height
> 16)
487 DPRINTF(E_WARN
, L_METADATA
, "ERROR image_from_jpeg : (image_from_jpeg.c) JPEG uses line buffers > 16. Cannot load.\n");
488 jpeg_destroy_decompress(&cinfo
);
494 maxbuf
= vimage
->width
* vimage
->height
;
495 if(cinfo
.output_components
== 3)
499 if((ptr
= malloc(w
* 3 * cinfo
.rec_outbuf_height
+ 16)) == NULL
)
501 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
502 jpeg_destroy_decompress(&cinfo
);
509 for(y
= 0; y
< h
; y
+= cinfo
.rec_outbuf_height
)
511 ry
= (rotate
& (ROTATE_90
|ROTATE_180
)) ? (y
- h
+ 1) * -1 : y
;
512 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
514 line
[i
] = ptr
+ (w
* 3 * i
);
516 jpeg_read_scanlines(&cinfo
, line
, cinfo
.rec_outbuf_height
);
517 for(x
= 0; x
< w
* cinfo
.rec_outbuf_height
; x
++)
519 rx
= (rotate
& (ROTATE_180
|ROTATE_270
)) ? (x
- w
+ 1) * -1 : x
;
520 ofs
= (rotate
& (ROTATE_90
|ROTATE_270
)) ? ry
+ (rx
* h
) : rx
+ (ry
* w
);
522 vimage
->buf
[ofs
] = COL(ptr
[x
+ x
+ x
], ptr
[x
+ x
+ x
+ 1], ptr
[x
+ x
+ x
+ 2]);
527 else if(cinfo
.output_components
== 1)
531 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
533 if((line
[i
] = malloc(w
)) == NULL
)
537 for(t
= 0; t
< i
; t
++) free(line
[t
]);
538 jpeg_destroy_decompress(&cinfo
);
545 for(y
= 0; y
< h
; y
+= cinfo
.rec_outbuf_height
)
547 ry
= (rotate
& (ROTATE_90
|ROTATE_180
)) ? (y
- h
+ 1) * -1 : y
;
548 jpeg_read_scanlines(&cinfo
, line
, cinfo
.rec_outbuf_height
);
549 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
551 for(x
= 0; x
< w
; x
++)
553 rx
= (rotate
& (ROTATE_180
|ROTATE_270
)) ?
554 (x
- w
+ 1) * -1 : x
;
555 ofs
= (rotate
& (ROTATE_90
|ROTATE_270
)) ?
556 ry
+ (rx
* h
) : rx
+ (ry
* w
);
559 COL(line
[i
][x
], line
[i
][x
], line
[i
][x
]);
563 for(i
= 0; i
< cinfo
.rec_outbuf_height
; i
++)
568 jpeg_finish_decompress(&cinfo
);
569 jpeg_destroy_decompress(&cinfo
);
577 image_upsize(image_s
* pdest
, image_s
* psrc
, int32_t width
, int32_t height
)
580 #if !defined __i386__ && !defined __x86_64__
584 if((pdest
== NULL
) || (psrc
== NULL
))
587 for(vy
= 0; vy
< height
; vy
++)
589 for(vx
= 0; vx
< width
; vx
++)
591 rx
= ((vx
* psrc
->width
) / width
);
592 ry
= ((vy
* psrc
->height
) / height
);
593 vcol
= get_pix(psrc
, rx
, ry
);
595 pix vcol
,vcol1
,vcol2
,vcol3
,vcol4
;
597 float width_scale
, height_scale
;
598 float x_dist
, y_dist
;
600 width_scale
= (float)psrc
->width
/ (float)width
;
601 height_scale
= (float)psrc
->height
/ (float)height
;
603 for(vy
= 0;vy
< height
; vy
++)
605 for(vx
= 0;vx
< width
; vx
++)
607 rx
= vx
* width_scale
;
608 ry
= vy
* height_scale
;
609 vcol1
= get_pix(psrc
, (int32_t)rx
, (int32_t)ry
);
610 vcol2
= get_pix(psrc
, ((int32_t)rx
)+1, (int32_t)ry
);
611 vcol3
= get_pix(psrc
, (int32_t)rx
, ((int32_t)ry
)+1);
612 vcol4
= get_pix(psrc
, ((int32_t)rx
)+1, ((int32_t)ry
)+1);
614 x_dist
= rx
- ((float)((int32_t)rx
));
615 y_dist
= ry
- ((float)((int32_t)ry
));
616 vcol
= COL_FULL( (uint8_t)((COL_RED(vcol1
)*(1.0-x_dist
)
617 + COL_RED(vcol2
)*(x_dist
))*(1.0-y_dist
)
618 + (COL_RED(vcol3
)*(1.0-x_dist
)
619 + COL_RED(vcol4
)*(x_dist
))*(y_dist
)),
620 (uint8_t)((COL_GREEN(vcol1
)*(1.0-x_dist
)
621 + COL_GREEN(vcol2
)*(x_dist
))*(1.0-y_dist
)
622 + (COL_GREEN(vcol3
)*(1.0-x_dist
)
623 + COL_GREEN(vcol4
)*(x_dist
))*(y_dist
)),
624 (uint8_t)((COL_BLUE(vcol1
)*(1.0-x_dist
)
625 + COL_BLUE(vcol2
)*(x_dist
))*(1.0-y_dist
)
626 + (COL_BLUE(vcol3
)*(1.0-x_dist
)
627 + COL_BLUE(vcol4
)*(x_dist
))*(y_dist
)),
628 (uint8_t)((COL_ALPHA(vcol1
)*(1.0-x_dist
)
629 + COL_ALPHA(vcol2
)*(x_dist
))*(1.0-y_dist
)
630 + (COL_ALPHA(vcol3
)*(1.0-x_dist
)
631 + COL_ALPHA(vcol4
)*(x_dist
))*(y_dist
))
634 put_pix_alpha_replace(pdest
, vx
, vy
, vcol
);
640 image_downsize(image_s
* pdest
, image_s
* psrc
, int32_t width
, int32_t height
)
645 #if !defined __i386__ && !defined __x86_64__
646 int32_t rx
, ry
, rx_next
, ry_next
;
647 int red
, green
, blue
, alpha
;
650 if((pdest
== NULL
) || (psrc
== NULL
))
653 for(vy
= 0; vy
< height
; vy
++)
655 for(vx
= 0; vx
< width
; vx
++)
658 rx
= ((vx
* psrc
->width
) / width
);
659 ry
= ((vy
* psrc
->height
) / height
);
661 red
= green
= blue
= alpha
= 0;
663 rx_next
= rx
+ (psrc
->width
/ width
);
664 ry_next
= ry
+ (psrc
->width
/ width
);
667 for( j
= rx
; j
< rx_next
; j
++)
669 for( i
= ry
; i
< ry_next
; i
++)
672 vcol
= get_pix(psrc
, j
, i
);
674 red
+= COL_RED(vcol
);
675 green
+= COL_GREEN(vcol
);
676 blue
+= COL_BLUE(vcol
);
677 alpha
+= COL_ALPHA(vcol
);
686 /* on sature les valeurs */
687 red
= (red
> 255) ? 255 : ((red
< 0) ? 0 : red
);
688 green
= (green
> 255) ? 255 : ((green
< 0) ? 0 : green
);
689 blue
= (blue
> 255) ? 255 : ((blue
< 0) ? 0 : blue
);
690 alpha
= (alpha
> 255) ? 255 : ((alpha
< 0) ? 0 : alpha
);
693 float width_scale
, height_scale
;
694 float red
, green
, blue
, alpha
;
695 int32_t half_square_width
, half_square_height
;
696 float round_width
, round_height
;
698 if( (pdest
== NULL
) || (psrc
== NULL
) )
701 width_scale
= (float)psrc
->width
/ (float)width
;
702 height_scale
= (float)psrc
->height
/ (float)height
;
704 half_square_width
= (int32_t)(width_scale
/ 2.0);
705 half_square_height
= (int32_t)(height_scale
/ 2.0);
706 round_width
= (width_scale
/ 2.0) - (float)half_square_width
;
707 round_height
= (height_scale
/ 2.0) - (float)half_square_height
;
708 if(round_width
> 0.0)
712 if(round_height
> 0.0)
713 half_square_height
++;
717 for(vy
= 0;vy
< height
; vy
++)
719 for(vx
= 0;vx
< width
; vx
++)
721 rx
= vx
* width_scale
;
722 ry
= vy
* height_scale
;
723 vcol
= get_pix(psrc
, (int32_t)rx
, (int32_t)ry
);
725 red
= green
= blue
= alpha
= 0.0;
727 for(j
=0;j
<half_square_height
<<1;j
++)
729 for(i
=0;i
<half_square_width
<<1;i
++)
731 vcol
= get_pix(psrc
, ((int32_t)rx
)-half_square_width
+i
,
732 ((int32_t)ry
)-half_square_height
+j
);
734 if(((j
== 0) || (j
== (half_square_height
<<1)-1)) &&
735 ((i
== 0) || (i
== (half_square_width
<<1)-1)))
737 red
+= round_width
*round_height
*(float)COL_RED (vcol
);
738 green
+= round_width
*round_height
*(float)COL_GREEN(vcol
);
739 blue
+= round_width
*round_height
*(float)COL_BLUE (vcol
);
740 alpha
+= round_width
*round_height
*(float)COL_ALPHA(vcol
);
742 else if((j
== 0) || (j
== (half_square_height
<<1)-1))
744 red
+= round_height
*(float)COL_RED (vcol
);
745 green
+= round_height
*(float)COL_GREEN(vcol
);
746 blue
+= round_height
*(float)COL_BLUE (vcol
);
747 alpha
+= round_height
*(float)COL_ALPHA(vcol
);
749 else if((i
== 0) || (i
== (half_square_width
<<1)-1))
751 red
+= round_width
*(float)COL_RED (vcol
);
752 green
+= round_width
*(float)COL_GREEN(vcol
);
753 blue
+= round_width
*(float)COL_BLUE (vcol
);
754 alpha
+= round_width
*(float)COL_ALPHA(vcol
);
758 red
+= (float)COL_RED (vcol
);
759 green
+= (float)COL_GREEN(vcol
);
760 blue
+= (float)COL_BLUE (vcol
);
761 alpha
+= (float)COL_ALPHA(vcol
);
766 red
/= width_scale
*height_scale
;
767 green
/= width_scale
*height_scale
;
768 blue
/= width_scale
*height_scale
;
769 alpha
/= width_scale
*height_scale
;
771 /* on sature les valeurs */
772 red
= (red
> 255.0)? 255.0 : ((red
< 0.0)? 0.0:red
);
773 green
= (green
> 255.0)? 255.0 : ((green
< 0.0)? 0.0:green
);
774 blue
= (blue
> 255.0)? 255.0 : ((blue
< 0.0)? 0.0:blue
);
775 alpha
= (alpha
> 255.0)? 255.0 : ((alpha
< 0.0)? 0.0:alpha
);
777 put_pix_alpha_replace(pdest
, vx
, vy
,
778 COL_FULL((uint8_t)red
, (uint8_t)green
, (uint8_t)blue
, (uint8_t)alpha
));
784 image_resize(image_s
* src_image
, int32_t width
, int32_t height
)
788 dst_image
= image_new(width
, height
);
791 if( (src_image
->width
< width
) || (src_image
->height
< height
) )
792 image_upsize(dst_image
, src_image
, width
, height
);
794 image_downsize(dst_image
, src_image
, width
, height
);
801 image_save_to_jpeg_buf(image_s
* pimage
, int * size
)
803 struct jpeg_compress_struct cinfo
;
804 struct jpeg_error_mgr jerr
;
805 JSAMPROW row_pointer
[1];
809 struct my_dst_mgr dst
;
811 cinfo
.err
= jpeg_std_error(&jerr
);
812 jpeg_create_compress(&cinfo
);
813 jpeg_memory_dest(&cinfo
, &dst
);
814 cinfo
.image_width
= pimage
->width
;
815 cinfo
.image_height
= pimage
->height
;
816 cinfo
.input_components
= 3;
817 cinfo
.in_color_space
= JCS_RGB
;
818 jpeg_set_defaults(&cinfo
);
819 jpeg_set_quality(&cinfo
, JPEG_QUALITY
, TRUE
);
820 jpeg_start_compress(&cinfo
, TRUE
);
821 row_stride
= cinfo
.image_width
* 3;
822 if((data
= malloc(row_stride
)) == NULL
)
824 DPRINTF(E_WARN
, L_METADATA
, "malloc failed\n");
826 jpeg_destroy_compress(&cinfo
);
830 while(cinfo
.next_scanline
< cinfo
.image_height
)
832 for(x
= 0; x
< pimage
->width
; x
++)
834 data
[x
* 3] = COL_RED(pimage
->buf
[i
]);
835 data
[x
* 3 + 1] = COL_GREEN(pimage
->buf
[i
]);
836 data
[x
* 3 + 2] = COL_BLUE(pimage
->buf
[i
]);
839 row_pointer
[0] = (unsigned char *)data
;
840 jpeg_write_scanlines(&cinfo
, row_pointer
, 1);
842 jpeg_finish_compress(&cinfo
);
845 jpeg_destroy_compress(&cinfo
);
851 image_save_to_jpeg_file(image_s
* pimage
, char * path
)
853 int nwritten
, size
= 0;
857 buf
= image_save_to_jpeg_buf(pimage
, &size
);
860 dst_file
= fopen(path
, "w");
866 nwritten
= fwrite(buf
, 1, size
, dst_file
);
870 return (nwritten
== size
) ? path
: NULL
;