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 241 img = fopen(path, "r"); 242 if( !img ) 243 return(-1); 244 245 fread(&buf, 2, 1, img); 246 if( (buf[0] != 0xFF) || (buf[1] != 0xD8) ) 247 { 248 fclose(img); 249 return(-1); 250 } 251 memset(&buf, 0, sizeof(buf)); 252 253 while( !feof(img) ) 254 { 255 while( buf[0] != 0xFF && !feof(img) ) 256 fread(&buf, 1, 1, img); 257 258 while( buf[0] == 0xFF && !feof(img) ) 259 fread(&buf, 1, 1, img); 260 261 if( (buf[0] >= 0xc0) && (buf[0] <= 0xc3) ) 262 { 263 fread(&buf, 7, 1, img); 264 *width = 0; 265 *height = 0; 266 memcpy(&h, buf+3, 2); 267 *height = SWAP16(h); 268 memcpy(&w, buf+5, 2); 269 *width = SWAP16(w); 270 ret = 0; 271 break; 272 } 273 else 274 { 275 offset = 0; 276 fread(&buf, 2, 1, img); 277 memcpy(&offset, buf, 2); 278 offset = SWAP16(offset) - 2; 279 fseek(img, offset, SEEK_CUR); 280 } 281 } 282 fclose(img); 283 return ret; 284} 285 286int 287image_get_jpeg_date_xmp(const char * path, char ** date) 288{ 289 FILE *img; 290 unsigned char buf[8]; 291 char *data = NULL; 292 u_int16_t offset; 293 struct NameValueParserData xml; 294 char * exif; 295 int ret = 1; 296 297 img = fopen(path, "r"); 298 if( !img ) 299 return(-1); 300 301 fread(&buf, 2, 1, img); 302 if( (buf[0] != 0xFF) || (buf[1] != 0xD8) ) 303 { 304 fclose(img); 305 return(-1); 306 } 307 memset(&buf, 0, sizeof(buf)); 308 309 while( !feof(img) ) 310 { 311 while( buf[0] != 0xFF && !feof(img) ) 312 fread(&buf, 1, 1, img); 313 314 while( buf[0] == 0xFF && !feof(img) ) 315 fread(&buf, 1, 1, img); 316 317 if( feof(img) ) 318 break; 319 320 if( buf[0] == 0xE1 ) // APP1 marker 321 { 322 offset = 0; 323 fread(&buf, 2, 1, img); 324 memcpy(&offset, buf, 2); 325 offset = SWAP16(offset) - 2; 326 327 if( offset < 30 ) 328 { 329 fseek(img, offset, SEEK_CUR); 330 continue; 331 } 332 333 data = realloc(data, 30); 334 fread(data, 29, 1, img); 335 offset -= 29; 336 if( strcmp(data, "http://ns.adobe.com/xap/1.0/") != 0 ) 337 { 338 fseek(img, offset, SEEK_CUR); 339 continue; 340 } 341 342 data = realloc(data, offset+1); 343 fread(data, offset, 1, img); 344 345 ParseNameValue(data, offset, &xml); 346 exif = GetValueFromNameValueList(&xml, "DateTimeOriginal"); 347 if( !exif ) 348 break; 349 *date = realloc(*date, strlen(exif)+1); 350 strcpy(*date, exif); 351 ClearNameValueList(&xml); 352 353 ret = 0; 354 break; 355 } 356 else 357 { 358 offset = 0; 359 fread(&buf, 2, 1, img); 360 memcpy(&offset, buf, 2); 361 offset = SWAP16(offset) - 2; 362 fseek(img, offset, SEEK_CUR); 363 } 364 } 365 fclose(img); 366 if( data ) 367 free(data); 368 return ret; 369} 370 371image * 372image_new(int32_t width, int32_t height) 373{ 374 image *vimage; 375 376 if((vimage = (image *)malloc(sizeof(image))) == NULL) 377 { 378 DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); 379 return NULL; 380 } 381 vimage->width = width; vimage->height = height; 382 383 DPRINTF(E_WARN, L_METADATA, "\n=================\n" ); 384 385 386 printf("width:%d, height:%d, size of pix: %d\n", width, height, sizeof(pix)); 387 388 printf("try to alloc %d bytes\n", (width * height * sizeof(pix))); 389 390 391 if((vimage->buf = (pix *)malloc(width * height * sizeof(pix))) == NULL) 392 { 393 DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); 394 DPRINTF(E_WARN, L_METADATA, "=================\n" ); 395 free(vimage); 396 return NULL; 397 } 398 else 399 DPRINTF(E_WARN, L_METADATA, "malloc ok\n\n" ); 400 401 DPRINTF(E_WARN, L_METADATA, "=================\n" ); 402 return(vimage); 403} 404 405image * 406image_new_from_jpeg(const char * path, int is_file, const char * buf, int size) 407{ 408 image *vimage; 409 FILE *file = NULL; 410 struct jpeg_decompress_struct cinfo; 411 unsigned char *line[16], *ptr; 412 int x, y, i, w, h, ofs; 413 int maxbuf; 414 struct jpeg_error_mgr pub; 415 416 417 cinfo.err = jpeg_std_error(&pub); 418 pub.error_exit = libjpeg_error_handler; 419 jpeg_create_decompress(&cinfo); 420 if( is_file ) 421 { 422 if( (file = fopen(path, "r")) == NULL ) 423 { 424 return NULL; 425 } 426 jpeg_stdio_src(&cinfo, file); 427 } 428 else 429 { 430 jpeg_memory_src(&cinfo, (const unsigned char *)buf, size); 431 } 432 if( setjmp(setjmp_buffer) ) 433 { 434 jpeg_destroy_decompress(&cinfo); 435 if( is_file && file ) 436 fclose(file); 437 return NULL; 438 } 439 jpeg_read_header(&cinfo, TRUE); 440 cinfo.do_fancy_upsampling = FALSE; 441 cinfo.do_block_smoothing = FALSE; 442 jpeg_start_decompress(&cinfo); 443 w = cinfo.output_width; 444 h = cinfo.output_height; 445 vimage = image_new(w, h); 446 if(!vimage) 447 { 448 jpeg_destroy_decompress(&cinfo); 449 if( is_file ) 450 fclose(file); 451 return NULL; 452 } 453 454 if( setjmp(setjmp_buffer) ) 455 { 456 jpeg_destroy_decompress(&cinfo); 457 if( is_file && file ) 458 fclose(file); 459 if( vimage ) 460 { 461 if( vimage->buf ) 462 free(vimage->buf); 463 free(vimage); 464 } 465 return NULL; 466 } 467 468 if(cinfo.rec_outbuf_height > 16) 469 { 470 DPRINTF(E_WARN, L_METADATA, "ERROR image_from_jpeg : (image_from_jpeg.c) JPEG uses line buffers > 16. Cannot load.\n"); 471 image_free(vimage); 472 if( is_file ) 473 fclose(file); 474 return NULL; 475 } 476 maxbuf = vimage->width * vimage->height; 477 if(cinfo.output_components == 3) 478 { 479 ofs = 0; 480 if((ptr = (unsigned char *)malloc(w * 3 * cinfo.rec_outbuf_height)) == NULL) 481 { 482 DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); 483 return NULL; 484 } 485 486 for(y = 0; y < h; y += cinfo.rec_outbuf_height) 487 { 488 for(i = 0; i < cinfo.rec_outbuf_height; i++) 489 { 490 line[i] = ptr + (w * 3 * i); 491 } 492 jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); 493 for(x = 0; x < w * cinfo.rec_outbuf_height; x++) 494 { 495 if( ofs < maxbuf ) 496 { 497 vimage->buf[ofs] = COL(ptr[x + x + x], ptr[x + x + x + 1], ptr[x + x + x + 2]); 498 ofs++; 499 } 500 } 501 } 502 free(ptr); 503 } 504 else if(cinfo.output_components == 1) 505 { 506 ofs = 0; 507 for(i = 0; i < cinfo.rec_outbuf_height; i++) 508 { 509 if((line[i] = (unsigned char *)malloc(w)) == NULL) 510 { 511 int t = 0; 512 513 for(t = 0; t < i; t++) free(line[t]); 514 jpeg_destroy_decompress(&cinfo); 515 image_free(vimage); 516 if( is_file ) 517 fclose(file); 518 return NULL; 519 } 520 } 521 for(y = 0; y < h; y += cinfo.rec_outbuf_height) 522 { 523 jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); 524 for(i = 0; i < cinfo.rec_outbuf_height; i++) 525 { 526 for(x = 0; x < w; x++) 527 { 528 vimage->buf[ofs++] = COL(line[i][x], line[i][x], line[i][x]); 529 } 530 } 531 } 532 for(i = 0; i < cinfo.rec_outbuf_height; i++) 533 { 534 free(line[i]); 535 } 536 } 537 jpeg_finish_decompress(&cinfo); 538 jpeg_destroy_decompress(&cinfo); 539 if( is_file ) 540 fclose(file); 541 542 return vimage; 543} 544 545void 546image_upsize(image * pdest, image * psrc, int32_t width, int32_t height) 547{ 548 int32_t vx, vy; 549#if !defined __i386__ && !defined __x86_64__ 550 int32_t rx, ry; 551 pix vcol; 552 553 if((pdest == NULL) || (psrc == NULL)) 554 return; 555 556 for(vy = 0; vy < height; vy++) 557 { 558 for(vx = 0; vx < width; vx++) 559 { 560 rx = ((vx * psrc->width) / width); 561 ry = ((vy * psrc->height) / height); 562 vcol = get_pix(psrc, rx, ry); 563#else 564 pix vcol,vcol1,vcol2,vcol3,vcol4; 565 float rx,ry; 566 float width_scale, height_scale; 567 float x_dist, y_dist; 568 569 width_scale = (float)psrc->width / (float)width; 570 height_scale = (float)psrc->height / (float)height; 571 572 for(vy = 0;vy < height; vy++) 573 { 574 for(vx = 0;vx < width; vx++) 575 { 576 rx = vx * width_scale; 577 ry = vy * height_scale; 578 vcol1 = get_pix(psrc, (int32_t)rx, (int32_t)ry); 579 vcol2 = get_pix(psrc, ((int32_t)rx)+1, (int32_t)ry); 580 vcol3 = get_pix(psrc, (int32_t)rx, ((int32_t)ry)+1); 581 vcol4 = get_pix(psrc, ((int32_t)rx)+1, ((int32_t)ry)+1); 582 583 x_dist = rx - ((float)((int32_t)rx)); 584 y_dist = ry - ((float)((int32_t)ry)); 585 vcol = COL_FULL( (u_int8_t)((COL_RED(vcol1)*(1.0-x_dist) 586 + COL_RED(vcol2)*(x_dist))*(1.0-y_dist) 587 + (COL_RED(vcol3)*(1.0-x_dist) 588 + COL_RED(vcol4)*(x_dist))*(y_dist)), 589 (u_int8_t)((COL_GREEN(vcol1)*(1.0-x_dist) 590 + COL_GREEN(vcol2)*(x_dist))*(1.0-y_dist) 591 + (COL_GREEN(vcol3)*(1.0-x_dist) 592 + COL_GREEN(vcol4)*(x_dist))*(y_dist)), 593 (u_int8_t)((COL_BLUE(vcol1)*(1.0-x_dist) 594 + COL_BLUE(vcol2)*(x_dist))*(1.0-y_dist) 595 + (COL_BLUE(vcol3)*(1.0-x_dist) 596 + COL_BLUE(vcol4)*(x_dist))*(y_dist)), 597 (u_int8_t)((COL_ALPHA(vcol1)*(1.0-x_dist) 598 + COL_ALPHA(vcol2)*(x_dist))*(1.0-y_dist) 599 + (COL_ALPHA(vcol3)*(1.0-x_dist) 600 + COL_ALPHA(vcol4)*(x_dist))*(y_dist)) 601 ); 602#endif 603 put_pix_alpha_replace(pdest, vx, vy, vcol); 604 } 605 } 606} 607 608void 609image_downsize(image * pdest, image * psrc, int32_t width, int32_t height) 610{ 611 int32_t vx, vy; 612 pix vcol; 613 int32_t i, j; 614#if !defined __i386__ && !defined __x86_64__ 615 int32_t rx, ry, rx_next, ry_next; 616 int red, green, blue, alpha; 617 int factor; 618 619 if((pdest == NULL) || (psrc == NULL)) 620 return; 621 622 for(vy = 0; vy < height; vy++) 623 { 624 for(vx = 0; vx < width; vx++) 625 { 626 627 rx = ((vx * psrc->width) / width); 628 ry = ((vy * psrc->height) / height); 629 630 red = green = blue = alpha = 0; 631 632 rx_next = rx + (psrc->width / width); 633 ry_next = ry + (psrc->width / width); 634 factor = 0; 635 636 for( j = rx; j < rx_next; j++) 637 { 638 for( i = ry; i < ry_next; i++) 639 { 640 factor += 1; 641 vcol = get_pix(psrc, j, i); 642 643 red += COL_RED(vcol); 644 green += COL_GREEN(vcol); 645 blue += COL_BLUE(vcol); 646 alpha += COL_ALPHA(vcol); 647 } 648 } 649 650 red /= factor; 651 green /= factor; 652 blue /= factor; 653 alpha /= factor; 654 655 /* on sature les valeurs */ 656 red = (red > 255) ? 255 : ((red < 0) ? 0 : red ); 657 green = (green > 255) ? 255 : ((green < 0) ? 0 : green); 658 blue = (blue > 255) ? 255 : ((blue < 0) ? 0 : blue ); 659 alpha = (alpha > 255) ? 255 : ((alpha < 0) ? 0 : alpha); 660#else 661 float rx,ry; 662 float width_scale, height_scale; 663 float red, green, blue, alpha; 664 int32_t half_square_width, half_square_height; 665 float round_width, round_height; 666 667 if( (pdest == NULL) || (psrc == NULL) ) 668 return; 669 670 width_scale = (float)psrc->width / (float)width; 671 height_scale = (float)psrc->height / (float)height; 672 673 half_square_width = (int32_t)(width_scale / 2.0); 674 half_square_height = (int32_t)(height_scale / 2.0); 675 round_width = (width_scale / 2.0) - (float)half_square_width; 676 round_height = (height_scale / 2.0) - (float)half_square_height; 677 if(round_width > 0.0) 678 half_square_width++; 679 else 680 round_width = 1.0; 681 if(round_height > 0.0) 682 half_square_height++; 683 else 684 round_height = 1.0; 685 686 for(vy = 0;vy < height; vy++) 687 { 688 for(vx = 0;vx < width; vx++) 689 { 690 rx = vx * width_scale; 691 ry = vy * height_scale; 692 vcol = get_pix(psrc, (int32_t)rx, (int32_t)ry); 693 694 red = green = blue = alpha = 0.0; 695 696 for(j=0;j<half_square_height<<1;j++) 697 { 698 for(i=0;i<half_square_width<<1;i++) 699 { 700 vcol = get_pix(psrc, ((int32_t)rx)-half_square_width+i, 701 ((int32_t)ry)-half_square_height+j); 702 703 if(((j == 0) || (j == (half_square_height<<1)-1)) && 704 ((i == 0) || (i == (half_square_width<<1)-1))) 705 { 706 red += round_width*round_height*(float)COL_RED (vcol); 707 green += round_width*round_height*(float)COL_GREEN(vcol); 708 blue += round_width*round_height*(float)COL_BLUE (vcol); 709 alpha += round_width*round_height*(float)COL_ALPHA(vcol); 710 } 711 else if((j == 0) || (j == (half_square_height<<1)-1)) 712 { 713 red += round_height*(float)COL_RED (vcol); 714 green += round_height*(float)COL_GREEN(vcol); 715 blue += round_height*(float)COL_BLUE (vcol); 716 alpha += round_height*(float)COL_ALPHA(vcol); 717 } 718 else if((i == 0) || (i == (half_square_width<<1)-1)) 719 { 720 red += round_width*(float)COL_RED (vcol); 721 green += round_width*(float)COL_GREEN(vcol); 722 blue += round_width*(float)COL_BLUE (vcol); 723 alpha += round_width*(float)COL_ALPHA(vcol); 724 } 725 else 726 { 727 red += (float)COL_RED (vcol); 728 green += (float)COL_GREEN(vcol); 729 blue += (float)COL_BLUE (vcol); 730 alpha += (float)COL_ALPHA(vcol); 731 } 732 } 733 } 734 735 red /= width_scale*height_scale; 736 green /= width_scale*height_scale; 737 blue /= width_scale*height_scale; 738 alpha /= width_scale*height_scale; 739 740 /* on sature les valeurs */ 741 red = (red > 255.0)? 255.0 : ((red < 0.0)? 0.0:red ); 742 green = (green > 255.0)? 255.0 : ((green < 0.0)? 0.0:green); 743 blue = (blue > 255.0)? 255.0 : ((blue < 0.0)? 0.0:blue ); 744 alpha = (alpha > 255.0)? 255.0 : ((alpha < 0.0)? 0.0:alpha); 745#endif 746 put_pix_alpha_replace(pdest, vx, vy, 747 COL_FULL((u_int8_t)red, (u_int8_t)green, (u_int8_t)blue, (u_int8_t)alpha)); 748 } 749 } 750} 751 752image * 753image_resize(image * src_image, int32_t width, int32_t height) 754{ 755 image * dst_image; 756 757 dst_image = image_new(width, height); 758 if( !dst_image ) 759 return NULL; 760 if( (src_image->width < width) || (src_image->height < height) ) 761 image_upsize(dst_image, src_image, width, height); 762 else 763 image_downsize(dst_image, src_image, width, height); 764 765 return dst_image; 766} 767 768 769unsigned char * 770image_save_to_jpeg_buf(image * pimage, int * size) 771{ 772 struct jpeg_compress_struct cinfo; 773 struct jpeg_error_mgr jerr; 774 JSAMPROW row_pointer[1]; 775 int row_stride; 776 char *data; 777 int i, x; 778 struct my_dst_mgr dst; 779 780 cinfo.err = jpeg_std_error(&jerr); 781 jpeg_create_compress(&cinfo); 782 jpeg_memory_dest(&cinfo, &dst); 783 cinfo.image_width = pimage->width; 784 cinfo.image_height = pimage->height; 785 cinfo.input_components = 3; 786 cinfo.in_color_space = JCS_RGB; 787 jpeg_set_defaults(&cinfo); 788 jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE); 789 jpeg_start_compress(&cinfo, TRUE); 790 row_stride = cinfo.image_width * 3; 791 if((data = malloc(row_stride)) == NULL) 792 { 793 DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); 794 return NULL; 795 } 796 i = 0; 797 while(cinfo.next_scanline < cinfo.image_height) 798 { 799 for(x = 0; x < pimage->width; x++) 800 { 801 data[x + x + x] = COL_RED(pimage->buf[i]); 802 data[x + x + x + 1] = COL_GREEN(pimage->buf[i]); 803 data[x + x + x + 2] = COL_BLUE(pimage->buf[i]); 804 i++; 805 } 806 row_pointer[0] = (unsigned char *)data; 807 jpeg_write_scanlines(&cinfo, row_pointer, 1); 808 } 809 jpeg_finish_compress(&cinfo); 810 *size = dst.used; 811 free(data); 812 jpeg_destroy_compress(&cinfo); 813 814 return dst.buf; 815} 816 817int 818image_save_to_jpeg_file(image * pimage, const char * path) 819{ 820 int nwritten, size = 0; 821 unsigned char * buf; 822 FILE * dst_file; 823 824 buf = image_save_to_jpeg_buf(pimage, &size); 825 if( !buf ) 826 return -1; 827 dst_file = fopen(path, "w"); 828 if( !dst_file ) 829 { 830 free(buf); 831 return -1; 832 } 833 nwritten = fwrite(buf, 1, size, dst_file); 834 fclose(dst_file); 835 free(buf); 836 837 return (nwritten==size ? 0 : 1); 838} 839