1/* MiniDLNA media server 2 * Copyright (C) 2009 Justin Maggard 3 * 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. 8 * 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. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 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. 23 * 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 27 */ 28 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <unistd.h> 33#include <sys/types.h> 34#include <setjmp.h> 35#include <jpeglib.h> 36#include <endian.h> 37 38#include "upnpreplyparse.h" 39#include "image_utils.h" 40#include "log.h" 41 42#if __BYTE_ORDER == __LITTLE_ENDIAN 43# define SWAP16(w) ( (((w) >> 8) & 0x00ff) | (((w) << 8) & 0xff00) ) 44#else 45# define SWAP16(w) (w) 46#endif 47 48#define JPEG_QUALITY 96 49 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 57 58 59struct my_dst_mgr { 60 struct jpeg_destination_mgr jdst; 61 JOCTET *buf; 62 JOCTET *off; 63 size_t sz; 64 size_t used; 65}; 66 67/* Destination manager to store data in a buffer */ 68static void 69my_dst_mgr_init(j_compress_ptr cinfo) 70{ 71 struct my_dst_mgr *dst = (void *)cinfo->dest; 72 73 dst->used = 0; 74 dst->sz = cinfo->image_width 75 * cinfo->image_height 76 * cinfo->input_components; 77 dst->buf = malloc(dst->sz * sizeof *dst->buf); 78 dst->off = dst->buf; 79 dst->jdst.next_output_byte = dst->off; 80 dst->jdst.free_in_buffer = dst->sz; 81 82 return; 83 84} 85 86static boolean 87my_dst_mgr_empty(j_compress_ptr cinfo) 88{ 89 struct my_dst_mgr *dst = (void *)cinfo->dest; 90 91 dst->sz *= 2; 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; 97 98 return TRUE; 99 100} 101 102static void 103my_dst_mgr_term(j_compress_ptr cinfo) 104{ 105 struct my_dst_mgr *dst = (void *)cinfo->dest; 106 107 dst->used += dst->sz - dst->jdst.free_in_buffer; 108 dst->off = dst->buf + dst->used; 109 110 return; 111 112} 113 114static void 115jpeg_memory_dest(j_compress_ptr cinfo, struct my_dst_mgr *dst) 116{ 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; 121 122 return; 123 124} 125 126/* Source manager to read data from a buffer */ 127struct 128my_src_mgr 129{ 130 struct jpeg_source_mgr pub; 131 JOCTET eoi_buffer[2]; 132}; 133 134static void 135init_source(j_decompress_ptr cinfo) 136{ 137 return; 138} 139 140static int 141fill_input_buffer(j_decompress_ptr cinfo) 142{ 143 struct my_src_mgr *src = (void *)cinfo->src; 144 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; 150 151 return TRUE; 152} 153 154static void 155skip_input_data(j_decompress_ptr cinfo, long num_bytes) 156{ 157 struct my_src_mgr *src = (void *)cinfo->src; 158 if (num_bytes > 0) 159 { 160 while (num_bytes > (long)src->pub.bytes_in_buffer) 161 { 162 num_bytes -= (long)src->pub.bytes_in_buffer; 163 fill_input_buffer(cinfo); 164 } 165 } 166 src->pub.next_input_byte += num_bytes; 167 src->pub.bytes_in_buffer -= num_bytes; 168} 169 170static void 171term_source(j_decompress_ptr cinfo) 172{ 173 return; 174} 175 176void 177jpeg_memory_src(j_decompress_ptr cinfo, const unsigned char * buffer, size_t bufsize) 178{ 179 struct my_src_mgr *src; 180 181 if (! cinfo->src) 182 { 183 cinfo->src = (*cinfo->mem->alloc_small)((void *)cinfo, JPOOL_PERMANENT, sizeof(struct my_src_mgr));; 184 } 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; 193} 194 195jmp_buf setjmp_buffer; 196/* Don't exit on error like libjpeg likes to do */ 197static void 198libjpeg_error_handler(j_common_ptr cinfo) 199{ 200 cinfo->err->output_message(cinfo); 201 longjmp(setjmp_buffer, 1); 202 return; 203} 204 205void 206image_free(image *pimage) 207{ 208 free(pimage->buf); 209 free(pimage); 210} 211 212pix 213get_pix(image *pimage, int32_t x, int32_t y) 214{ 215 if((x >= 0) && (y >= 0) && (x < pimage->width) && (y < pimage->height)) 216 { 217 return(pimage->buf[(y * pimage->width) + x]); 218 } 219 else 220 { 221 pix vpix = BLACK; 222 return(vpix); 223 } 224} 225 226void 227put_pix_alpha_replace(image *pimage, int32_t x, int32_t y, pix col) 228{ 229 if((x >= 0) && (y >= 0) && (x < pimage->width) && (y < pimage->height)) 230 pimage->buf[(y * pimage->width) + x] = col; 231} 232 233int 234image_get_jpeg_resolution(const char * path, int * width, int * height) 235{ 236 FILE *img; 237 unsigned char buf[8]; 238 u_int16_t offset, h, w; 239 int ret = 1; 240 long size; 241 242 243 img = fopen(path, "r"); 244 if( !img ) 245 return(-1); 246 247 fseek(img, 0, SEEK_END); 248 size = ftell(img); 249 rewind(img); 250 251 fread(&buf, 2, 1, img); 252 if( (buf[0] != 0xFF) || (buf[1] != 0xD8) ) 253 { 254 fclose(img); 255 return(-1); 256 } 257 memset(&buf, 0, sizeof(buf)); 258 259 while( ftell(img) < size ) 260 { 261 while( buf[0] != 0xFF && !feof(img) ) 262 fread(&buf, 1, 1, img); 263 264 while( buf[0] == 0xFF && !feof(img) ) 265 fread(&buf, 1, 1, img); 266 267 if( (buf[0] >= 0xc0) && (buf[0] <= 0xc3) ) 268 { 269 fread(&buf, 7, 1, img); 270 *width = 0; 271 *height = 0; 272 memcpy(&h, buf+3, 2); 273 *height = SWAP16(h); 274 memcpy(&w, buf+5, 2); 275 *width = SWAP16(w); 276 ret = 0; 277 break; 278 } 279 else 280 { 281 offset = 0; 282 fread(&buf, 2, 1, img); 283 memcpy(&offset, buf, 2); 284 offset = SWAP16(offset) - 2; 285 if( fseek(img, offset, SEEK_CUR) == -1 ) 286 break; 287 } 288 } 289 fclose(img); 290 return ret; 291} 292 293int 294image_get_jpeg_date_xmp(const char * path, char ** date) 295{ 296 FILE *img; 297 unsigned char buf[8]; 298 char *data = NULL; 299 u_int16_t offset; 300 struct NameValueParserData xml; 301 char * exif; 302 int ret = 1; 303 304 img = fopen(path, "r"); 305 if( !img ) 306 return(-1); 307 308 fread(&buf, 2, 1, img); 309 if( (buf[0] != 0xFF) || (buf[1] != 0xD8) ) 310 { 311 fclose(img); 312 return(-1); 313 } 314 memset(&buf, 0, sizeof(buf)); 315 316 while( !feof(img) ) 317 { 318 while( buf[0] != 0xFF && !feof(img) ) 319 fread(&buf, 1, 1, img); 320 321 while( buf[0] == 0xFF && !feof(img) ) 322 fread(&buf, 1, 1, img); 323 324 if( feof(img) ) 325 break; 326 327 if( buf[0] == 0xE1 ) // APP1 marker 328 { 329 offset = 0; 330 fread(&buf, 2, 1, img); 331 memcpy(&offset, buf, 2); 332 offset = SWAP16(offset) - 2; 333 334 if( offset < 30 ) 335 { 336 fseek(img, offset, SEEK_CUR); 337 continue; 338 } 339 340 data = realloc(data, 30); 341 fread(data, 29, 1, img); 342 offset -= 29; 343 if( strcmp(data, "http://ns.adobe.com/xap/1.0/") != 0 ) 344 { 345 fseek(img, offset, SEEK_CUR); 346 continue; 347 } 348 349 data = realloc(data, offset+1); 350 fread(data, offset, 1, img); 351 352 ParseNameValue(data, offset, &xml); 353 exif = GetValueFromNameValueList(&xml, "DateTimeOriginal"); 354 if( !exif ) 355 { 356 ClearNameValueList(&xml); 357 break; 358 } 359 *date = realloc(*date, strlen(exif)+1); 360 strcpy(*date, exif); 361 ClearNameValueList(&xml); 362 363 ret = 0; 364 break; 365 } 366 else 367 { 368 offset = 0; 369 fread(&buf, 2, 1, img); 370 memcpy(&offset, buf, 2); 371 offset = SWAP16(offset) - 2; 372 fseek(img, offset, SEEK_CUR); 373 } 374 } 375 fclose(img); 376 if( data ) 377 free(data); 378 return ret; 379} 380 381image * 382image_new(int32_t width, int32_t height) 383{ 384 image *vimage; 385 386 if((vimage = (image *)malloc(sizeof(image))) == NULL) 387 { 388 DPRINTF(E_WARN, L_METADATA, "0.malloc failed\n"); 389 return NULL; 390 } 391 vimage->width = width; vimage->height = height; 392 393 //printf("width:%d, height:%d, size of pix: %d\n", width, height, sizeof(pix)); 394 395 //printf("try to alloc %d bytes\n", (width * height * sizeof(pix))); 396 397 if((vimage->buf = (pix *)malloc(width * height * sizeof(pix))) == NULL) 398 { 399 DPRINTF(E_WARN, L_METADATA, "1.malloc failed\n"); 400 free(vimage); 401 return NULL; 402 } 403 return(vimage); 404} 405 406image * 407image_new_from_jpeg(const char * path, int is_file, const char * buf, int size, int scale) 408{ 409 image *vimage; 410 FILE *file = NULL; 411 struct jpeg_decompress_struct cinfo; 412 unsigned char *line[16], *ptr; 413 int x, y, i, w, h, ofs; 414 int maxbuf; 415 struct jpeg_error_mgr pub; 416 417 418 cinfo.err = jpeg_std_error(&pub); 419 pub.error_exit = libjpeg_error_handler; 420 jpeg_create_decompress(&cinfo); 421 if( is_file ) 422 { 423 if( (file = fopen(path, "r")) == NULL ) 424 { 425 return NULL; 426 } 427 jpeg_stdio_src(&cinfo, file); 428 } 429 else 430 { 431 jpeg_memory_src(&cinfo, (const unsigned char *)buf, size); 432 } 433 if( setjmp(setjmp_buffer) ) 434 { 435 jpeg_destroy_decompress(&cinfo); 436 if( is_file && file ) 437 fclose(file); 438 return NULL; 439 } 440 jpeg_read_header(&cinfo, TRUE); 441 cinfo.scale_denom = scale; 442 /* added by Michael Jiang, for CTT 1.56 */ 443 cinfo.scale_num = 1; 444 /* ended by Michael Jiang, for CTT 1.56 */ 445 446 DPRINTF(E_WARN, L_METADATA, "%s: scale:%d\n", __FUNCTION__, scale); 447 448 449 cinfo.do_fancy_upsampling = FALSE; 450 cinfo.do_block_smoothing = FALSE; 451 jpeg_start_decompress(&cinfo); 452 w = cinfo.output_width; 453 h = cinfo.output_height; 454 vimage = image_new(w, h); 455 if(!vimage) 456 { 457 jpeg_destroy_decompress(&cinfo); 458 if( is_file ) 459 fclose(file); 460 return NULL; 461 } 462 463 if( setjmp(setjmp_buffer) ) 464 { 465 jpeg_destroy_decompress(&cinfo); 466 if( is_file && file ) 467 fclose(file); 468 if( vimage ) 469 { 470 if( vimage->buf ) 471 free(vimage->buf); 472 free(vimage); 473 } 474 return NULL; 475 } 476 477 if(cinfo.rec_outbuf_height > 16) 478 { 479 DPRINTF(E_WARN, L_METADATA, "ERROR image_from_jpeg : (image_from_jpeg.c) JPEG uses line buffers > 16. Cannot load.\n"); 480 image_free(vimage); 481 if( is_file ) 482 fclose(file); 483 return NULL; 484 } 485 maxbuf = vimage->width * vimage->height; 486 if(cinfo.output_components == 3) 487 { 488 ofs = 0; 489 if((ptr = (unsigned char *)malloc(w * 3 * cinfo.rec_outbuf_height)) == NULL) 490 { 491 DPRINTF(E_WARN, L_METADATA, "3.malloc failed\n"); 492 return NULL; 493 } 494 495 for(y = 0; y < h; y += cinfo.rec_outbuf_height) 496 { 497 for(i = 0; i < cinfo.rec_outbuf_height; i++) 498 { 499 line[i] = ptr + (w * 3 * i); 500 } 501 jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); 502 for(x = 0; x < w * cinfo.rec_outbuf_height; x++) 503 { 504 if( ofs < maxbuf ) 505 { 506 vimage->buf[ofs] = COL(ptr[x + x + x], ptr[x + x + x + 1], ptr[x + x + x + 2]); 507 ofs++; 508 } 509 } 510 } 511 free(ptr); 512 } 513 else if(cinfo.output_components == 1) 514 { 515 ofs = 0; 516 for(i = 0; i < cinfo.rec_outbuf_height; i++) 517 { 518 if((line[i] = (unsigned char *)malloc(w)) == NULL) 519 { 520 int t = 0; 521 522 for(t = 0; t < i; t++) free(line[t]); 523 jpeg_destroy_decompress(&cinfo); 524 image_free(vimage); 525 if( is_file ) 526 fclose(file); 527 return NULL; 528 } 529 } 530 for(y = 0; y < h; y += cinfo.rec_outbuf_height) 531 { 532 jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); 533 for(i = 0; i < cinfo.rec_outbuf_height; i++) 534 { 535 for(x = 0; x < w; x++) 536 { 537 vimage->buf[ofs++] = COL(line[i][x], line[i][x], line[i][x]); 538 } 539 } 540 } 541 for(i = 0; i < cinfo.rec_outbuf_height; i++) 542 { 543 free(line[i]); 544 } 545 } 546 jpeg_finish_decompress(&cinfo); 547 jpeg_destroy_decompress(&cinfo); 548 if( is_file ) 549 fclose(file); 550 551 return vimage; 552} 553 554void 555image_upsize(image * pdest, image * psrc, int32_t width, int32_t height) 556{ 557 int32_t vx, vy; 558#if !defined __i386__ && !defined __x86_64__ 559 int32_t rx, ry; 560 pix vcol; 561 562 if((pdest == NULL) || (psrc == NULL)) 563 return; 564 565 for(vy = 0; vy < height; vy++) 566 { 567 for(vx = 0; vx < width; vx++) 568 { 569 rx = ((vx * psrc->width) / width); 570 ry = ((vy * psrc->height) / height); 571 vcol = get_pix(psrc, rx, ry); 572#else 573 pix vcol,vcol1,vcol2,vcol3,vcol4; 574 float rx,ry; 575 float width_scale, height_scale; 576 float x_dist, y_dist; 577 578 width_scale = (float)psrc->width / (float)width; 579 height_scale = (float)psrc->height / (float)height; 580 581 for(vy = 0;vy < height; vy++) 582 { 583 for(vx = 0;vx < width; vx++) 584 { 585 rx = vx * width_scale; 586 ry = vy * height_scale; 587 vcol1 = get_pix(psrc, (int32_t)rx, (int32_t)ry); 588 vcol2 = get_pix(psrc, ((int32_t)rx)+1, (int32_t)ry); 589 vcol3 = get_pix(psrc, (int32_t)rx, ((int32_t)ry)+1); 590 vcol4 = get_pix(psrc, ((int32_t)rx)+1, ((int32_t)ry)+1); 591 592 x_dist = rx - ((float)((int32_t)rx)); 593 y_dist = ry - ((float)((int32_t)ry)); 594 vcol = COL_FULL( (u_int8_t)((COL_RED(vcol1)*(1.0-x_dist) 595 + COL_RED(vcol2)*(x_dist))*(1.0-y_dist) 596 + (COL_RED(vcol3)*(1.0-x_dist) 597 + COL_RED(vcol4)*(x_dist))*(y_dist)), 598 (u_int8_t)((COL_GREEN(vcol1)*(1.0-x_dist) 599 + COL_GREEN(vcol2)*(x_dist))*(1.0-y_dist) 600 + (COL_GREEN(vcol3)*(1.0-x_dist) 601 + COL_GREEN(vcol4)*(x_dist))*(y_dist)), 602 (u_int8_t)((COL_BLUE(vcol1)*(1.0-x_dist) 603 + COL_BLUE(vcol2)*(x_dist))*(1.0-y_dist) 604 + (COL_BLUE(vcol3)*(1.0-x_dist) 605 + COL_BLUE(vcol4)*(x_dist))*(y_dist)), 606 (u_int8_t)((COL_ALPHA(vcol1)*(1.0-x_dist) 607 + COL_ALPHA(vcol2)*(x_dist))*(1.0-y_dist) 608 + (COL_ALPHA(vcol3)*(1.0-x_dist) 609 + COL_ALPHA(vcol4)*(x_dist))*(y_dist)) 610 ); 611#endif 612 put_pix_alpha_replace(pdest, vx, vy, vcol); 613 } 614 } 615} 616 617void 618image_downsize(image * pdest, image * psrc, int32_t width, int32_t height) 619{ 620 int32_t vx, vy; 621 pix vcol; 622 int32_t i, j; 623#if !defined __i386__ && !defined __x86_64__ 624 int32_t rx, ry, rx_next, ry_next; 625 int red, green, blue, alpha; 626 int factor; 627 628 if((pdest == NULL) || (psrc == NULL)) 629 return; 630 631 for(vy = 0; vy < height; vy++) 632 { 633 for(vx = 0; vx < width; vx++) 634 { 635 636 rx = ((vx * psrc->width) / width); 637 ry = ((vy * psrc->height) / height); 638 639 red = green = blue = alpha = 0; 640 641 rx_next = rx + (psrc->width / width); 642 ry_next = ry + (psrc->width / width); 643 factor = 0; 644 645 for( j = rx; j < rx_next; j++) 646 { 647 for( i = ry; i < ry_next; i++) 648 { 649 factor += 1; 650 vcol = get_pix(psrc, j, i); 651 652 red += COL_RED(vcol); 653 green += COL_GREEN(vcol); 654 blue += COL_BLUE(vcol); 655 alpha += COL_ALPHA(vcol); 656 } 657 } 658 659 red /= factor; 660 green /= factor; 661 blue /= factor; 662 alpha /= factor; 663 664 /* on sature les valeurs */ 665 red = (red > 255) ? 255 : ((red < 0) ? 0 : red ); 666 green = (green > 255) ? 255 : ((green < 0) ? 0 : green); 667 blue = (blue > 255) ? 255 : ((blue < 0) ? 0 : blue ); 668 alpha = (alpha > 255) ? 255 : ((alpha < 0) ? 0 : alpha); 669#else 670 float rx,ry; 671 float width_scale, height_scale; 672 float red, green, blue, alpha; 673 int32_t half_square_width, half_square_height; 674 float round_width, round_height; 675 676 if( (pdest == NULL) || (psrc == NULL) ) 677 return; 678 679 width_scale = (float)psrc->width / (float)width; 680 height_scale = (float)psrc->height / (float)height; 681 682 half_square_width = (int32_t)(width_scale / 2.0); 683 half_square_height = (int32_t)(height_scale / 2.0); 684 round_width = (width_scale / 2.0) - (float)half_square_width; 685 round_height = (height_scale / 2.0) - (float)half_square_height; 686 if(round_width > 0.0) 687 half_square_width++; 688 else 689 round_width = 1.0; 690 if(round_height > 0.0) 691 half_square_height++; 692 else 693 round_height = 1.0; 694 695 for(vy = 0;vy < height; vy++) 696 { 697 for(vx = 0;vx < width; vx++) 698 { 699 rx = vx * width_scale; 700 ry = vy * height_scale; 701 vcol = get_pix(psrc, (int32_t)rx, (int32_t)ry); 702 703 red = green = blue = alpha = 0.0; 704 705 for(j=0;j<half_square_height<<1;j++) 706 { 707 for(i=0;i<half_square_width<<1;i++) 708 { 709 vcol = get_pix(psrc, ((int32_t)rx)-half_square_width+i, 710 ((int32_t)ry)-half_square_height+j); 711 712 if(((j == 0) || (j == (half_square_height<<1)-1)) && 713 ((i == 0) || (i == (half_square_width<<1)-1))) 714 { 715 red += round_width*round_height*(float)COL_RED (vcol); 716 green += round_width*round_height*(float)COL_GREEN(vcol); 717 blue += round_width*round_height*(float)COL_BLUE (vcol); 718 alpha += round_width*round_height*(float)COL_ALPHA(vcol); 719 } 720 else if((j == 0) || (j == (half_square_height<<1)-1)) 721 { 722 red += round_height*(float)COL_RED (vcol); 723 green += round_height*(float)COL_GREEN(vcol); 724 blue += round_height*(float)COL_BLUE (vcol); 725 alpha += round_height*(float)COL_ALPHA(vcol); 726 } 727 else if((i == 0) || (i == (half_square_width<<1)-1)) 728 { 729 red += round_width*(float)COL_RED (vcol); 730 green += round_width*(float)COL_GREEN(vcol); 731 blue += round_width*(float)COL_BLUE (vcol); 732 alpha += round_width*(float)COL_ALPHA(vcol); 733 } 734 else 735 { 736 red += (float)COL_RED (vcol); 737 green += (float)COL_GREEN(vcol); 738 blue += (float)COL_BLUE (vcol); 739 alpha += (float)COL_ALPHA(vcol); 740 } 741 } 742 } 743 744 red /= width_scale*height_scale; 745 green /= width_scale*height_scale; 746 blue /= width_scale*height_scale; 747 alpha /= width_scale*height_scale; 748 749 /* on sature les valeurs */ 750 red = (red > 255.0)? 255.0 : ((red < 0.0)? 0.0:red ); 751 green = (green > 255.0)? 255.0 : ((green < 0.0)? 0.0:green); 752 blue = (blue > 255.0)? 255.0 : ((blue < 0.0)? 0.0:blue ); 753 alpha = (alpha > 255.0)? 255.0 : ((alpha < 0.0)? 0.0:alpha); 754#endif 755 put_pix_alpha_replace(pdest, vx, vy, 756 COL_FULL((u_int8_t)red, (u_int8_t)green, (u_int8_t)blue, (u_int8_t)alpha)); 757 } 758 } 759} 760 761image * 762image_resize(image * src_image, int32_t width, int32_t height) 763{ 764 image * dst_image; 765 766 dst_image = image_new(width, height); 767 if( !dst_image ) 768 return NULL; 769 if( (src_image->width < width) || (src_image->height < height) ) 770 image_upsize(dst_image, src_image, width, height); 771 else 772 image_downsize(dst_image, src_image, width, height); 773 774 return dst_image; 775} 776 777 778unsigned char * 779image_save_to_jpeg_buf(image * pimage, int * size) 780{ 781 struct jpeg_compress_struct cinfo; 782 struct jpeg_error_mgr jerr; 783 JSAMPROW row_pointer[1]; 784 int row_stride; 785 char *data; 786 int i, x; 787 struct my_dst_mgr dst; 788 789 cinfo.err = jpeg_std_error(&jerr); 790 jpeg_create_compress(&cinfo); 791 jpeg_memory_dest(&cinfo, &dst); 792 cinfo.image_width = pimage->width; 793 cinfo.image_height = pimage->height; 794 cinfo.input_components = 3; 795 cinfo.in_color_space = JCS_RGB; 796 jpeg_set_defaults(&cinfo); 797 jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE); 798 jpeg_start_compress(&cinfo, TRUE); 799 row_stride = cinfo.image_width * 3; 800 if((data = malloc(row_stride)) == NULL) 801 { 802 DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); 803 return NULL; 804 } 805 i = 0; 806 while(cinfo.next_scanline < cinfo.image_height) 807 { 808 for(x = 0; x < pimage->width; x++) 809 { 810 data[x + x + x] = COL_RED(pimage->buf[i]); 811 data[x + x + x + 1] = COL_GREEN(pimage->buf[i]); 812 data[x + x + x + 2] = COL_BLUE(pimage->buf[i]); 813 i++; 814 } 815 row_pointer[0] = (unsigned char *)data; 816 jpeg_write_scanlines(&cinfo, row_pointer, 1); 817 } 818 jpeg_finish_compress(&cinfo); 819 *size = dst.used; 820 free(data); 821 jpeg_destroy_compress(&cinfo); 822 823 return dst.buf; 824} 825 826int 827image_save_to_jpeg_file(image * pimage, const char * path) 828{ 829 int nwritten, size = 0; 830 unsigned char * buf; 831 FILE * dst_file; 832 833 buf = image_save_to_jpeg_buf(pimage, &size); 834 if( !buf ) 835 return -1; 836 dst_file = fopen(path, "w"); 837 if( !dst_file ) 838 { 839 free(buf); 840 return -1; 841 } 842 nwritten = fwrite(buf, 1, size, dst_file); 843 fclose(dst_file); 844 free(buf); 845 846 return (nwritten==size ? 0 : 1); 847} 848