"Fossies" - the Fresh Open Source Software Archive

Member "minidlna-1.3.0/image_utils.c" (24 Nov 2020, 21037 Bytes) of package /linux/privat/minidlna-1.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "image_utils.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.1_vs_1.3.0.

    1 /* MiniDLNA media server
    2  * Copyright (C) 2009  Justin Maggard
    3  *
    4  * This file is part of MiniDLNA.
    5  *
    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.
    9  *
   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.
   14  *
   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/>.
   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 "config.h"
   30 #include <stdio.h>
   31 #include <stdlib.h>
   32 #include <string.h>
   33 #include <unistd.h>
   34 #include <setjmp.h>
   35 #include <jpeglib.h>
   36 #ifdef HAVE_MACHINE_ENDIAN_H
   37 #include <machine/endian.h>
   38 #else
   39 #include <endian.h>
   40 #endif
   41 
   42 #include "upnpreplyparse.h"
   43 #include "image_utils.h"
   44 #include "log.h"
   45 
   46 #if __BYTE_ORDER == __LITTLE_ENDIAN
   47 # define SWAP16(w) ( (((w) >> 8) & 0x00ff) | (((w) << 8) & 0xff00) )
   48 #else
   49 # define SWAP16(w) (w)
   50 #endif
   51 
   52 #define JPEG_QUALITY  96
   53 
   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
   61 
   62 
   63 struct my_dst_mgr {
   64     struct jpeg_destination_mgr jdst;
   65     JOCTET *buf;
   66     JOCTET *off;
   67     size_t sz;
   68     size_t used;
   69 };
   70 
   71 /* Destination manager to store data in a buffer */
   72 static void
   73 my_dst_mgr_init(j_compress_ptr cinfo)
   74 {
   75     struct my_dst_mgr *dst = (void *)cinfo->dest;
   76 
   77     dst->used = 0;
   78     dst->sz = cinfo->image_width
   79           * cinfo->image_height
   80           * cinfo->input_components;
   81     dst->buf = malloc(dst->sz * sizeof *dst->buf);
   82     dst->off = dst->buf;
   83     dst->jdst.next_output_byte = dst->off;
   84     dst->jdst.free_in_buffer = dst->sz;
   85 
   86     return;
   87 }
   88 
   89 static boolean
   90 my_dst_mgr_empty(j_compress_ptr cinfo)
   91 {
   92     struct my_dst_mgr *dst = (void *)cinfo->dest;
   93 
   94     dst->sz *= 2;
   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;
  100 
  101     return TRUE;
  102 }
  103 
  104 static void
  105 my_dst_mgr_term(j_compress_ptr cinfo)
  106 {
  107     struct my_dst_mgr *dst = (void *)cinfo->dest;
  108 
  109     dst->used += dst->sz - dst->jdst.free_in_buffer;
  110     dst->off = dst->buf + dst->used;
  111 
  112     return;
  113 }
  114 
  115 static void
  116 jpeg_memory_dest(j_compress_ptr cinfo, struct my_dst_mgr *dst)
  117 {
  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;
  122 
  123     return;
  124 }
  125 
  126 /* Source manager to read data from a buffer */
  127 struct
  128 my_src_mgr
  129 {
  130     struct jpeg_source_mgr pub;
  131     JOCTET eoi_buffer[2];
  132 };
  133 
  134 static void
  135 init_source(j_decompress_ptr cinfo)
  136 {
  137     return;
  138 }
  139 
  140 static boolean
  141 fill_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 
  154 static void
  155 skip_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 
  170 static void
  171 term_source(j_decompress_ptr cinfo)
  172 {
  173     return;
  174 }
  175 
  176 void
  177 jpeg_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         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;
  191 }
  192 
  193 static jmp_buf setjmp_buffer;
  194 /* Don't exit on error like libjpeg likes to do */
  195 static void
  196 libjpeg_error_handler(j_common_ptr cinfo)
  197 {
  198     cinfo->err->output_message(cinfo);
  199     longjmp(setjmp_buffer, 1);
  200     return;
  201 }
  202 
  203 void
  204 image_free(image_s *pimage)
  205 {
  206     free(pimage->buf);
  207     free(pimage);
  208 }
  209 
  210 pix
  211 get_pix(image_s *pimage, int32_t x, int32_t y)
  212 {
  213     if (x < 0)
  214         x = 0;
  215     else if (x >= pimage->width)
  216         x = pimage->width - 1;
  217 
  218     if (y < 0)
  219         y = 0;
  220     else if (y >= pimage->height)
  221         y = pimage->height - 1;
  222 
  223     return(pimage->buf[(y * pimage->width) + x]);
  224 }
  225 
  226 void
  227 put_pix_alpha_replace(image_s *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 
  233 int
  234 image_get_jpeg_resolution(const char * path, int * width, int * height)
  235 {
  236     FILE *img;
  237     unsigned char buf[8];
  238     uint16_t offset, h, w;
  239     int ret = 1;
  240     size_t nread;
  241     long size;
  242     
  243 
  244     img = fopen(path, "r");
  245     if( !img )
  246         return -1;
  247 
  248     fseek(img, 0, SEEK_END);
  249     size = ftell(img);
  250     rewind(img);
  251 
  252     nread = fread(&buf, 2, 1, img);
  253     if( (nread < 1) || (buf[0] != 0xFF) || (buf[1] != 0xD8) )
  254     {
  255         fclose(img);
  256         return -1;
  257     }
  258     memset(&buf, 0, sizeof(buf));
  259 
  260     while( ftell(img) < size )
  261     {
  262         while( nread > 0 && buf[0] != 0xFF && !feof(img) )
  263             nread = fread(&buf, 1, 1, img);
  264 
  265         while( nread > 0 && buf[0] == 0xFF && !feof(img) )
  266             nread = fread(&buf, 1, 1, img);
  267 
  268         if( (buf[0] >= 0xc0) && (buf[0] <= 0xc3) )
  269         {
  270             nread = fread(&buf, 7, 1, img);
  271             *width = 0;
  272             *height = 0;
  273             if( nread < 1 )
  274                 break;
  275             memcpy(&h, buf+3, 2);
  276             *height = SWAP16(h);
  277             memcpy(&w, buf+5, 2);
  278             *width = SWAP16(w);
  279             ret = 0;
  280             break;
  281         }
  282         else
  283         {
  284             offset = 0;
  285             nread = fread(&buf, 2, 1, img);
  286             if( nread < 1 )
  287                 break;
  288             memcpy(&offset, buf, 2);
  289             offset = SWAP16(offset) - 2;
  290             if( fseek(img, offset, SEEK_CUR) == -1 )
  291                 break;
  292         }
  293     }
  294     fclose(img);
  295     return ret;
  296 }
  297 
  298 int
  299 image_get_jpeg_date_xmp(const char * path, char ** date)
  300 {
  301     FILE *img;
  302     unsigned char buf[8];
  303     char *data = NULL, *newdata;
  304     uint16_t offset;
  305     struct NameValueParserData xml;
  306     char * exif;
  307     int ret = 1;
  308     size_t nread;
  309 
  310     img = fopen(path, "r");
  311     if( !img )
  312         return(-1);
  313 
  314     nread = fread(&buf, 2, 1, img);
  315     if( (nread < 1) || (buf[0] != 0xFF) || (buf[1] != 0xD8) )
  316     {
  317         fclose(img);
  318         return(-1);
  319     }
  320     memset(&buf, 0, sizeof(buf));
  321 
  322     while( !feof(img) )
  323     {
  324         while( nread > 0 && buf[0] != 0xFF && !feof(img) )
  325             nread = fread(&buf, 1, 1, img);
  326 
  327         while( nread > 0 && buf[0] == 0xFF && !feof(img) )
  328             nread = fread(&buf, 1, 1, img);
  329 
  330         if( feof(img) )
  331             break;
  332 
  333         if( buf[0] == 0xE1 ) // APP1 marker
  334         {
  335             offset = 0;
  336             nread = fread(&buf, 2, 1, img);
  337             if( nread < 1 )
  338                 break;
  339             memcpy(&offset, buf, 2);
  340             offset = SWAP16(offset) - 2;
  341 
  342             if( offset < 30 )
  343             {
  344                 fseek(img, offset, SEEK_CUR);
  345                 continue;
  346             }
  347 
  348             newdata = realloc(data, 30);
  349             if( !newdata )
  350                 break;
  351             data = newdata;
  352 
  353             nread = fread(data, 29, 1, img);
  354             if( nread < 1 )
  355                 break;
  356             offset -= 29;
  357             if( strcmp(data, "http://ns.adobe.com/xap/1.0/") != 0 )
  358             {
  359                 fseek(img, offset, SEEK_CUR);
  360                 continue;
  361             }
  362 
  363             newdata = realloc(data, offset+1);
  364             if( !newdata )
  365                 break;
  366             data = newdata;
  367             nread = fread(data, offset, 1, img);
  368             if( nread < 1 )
  369                 break;
  370 
  371             ParseNameValue(data, offset, &xml, 0);
  372             exif = GetValueFromNameValueList(&xml, "DateTimeOriginal");
  373             if( !exif )
  374             {
  375                 ClearNameValueList(&xml);
  376                 break;
  377             }
  378             *date = realloc(*date, strlen(exif)+1);
  379             strcpy(*date, exif);
  380             ClearNameValueList(&xml);
  381 
  382             ret = 0;
  383             break;
  384         }
  385         else
  386         {
  387             offset = 0;
  388             nread = fread(&buf, 2, 1, img);
  389             if( nread < 1 )
  390                 break;
  391             memcpy(&offset, buf, 2);
  392             offset = SWAP16(offset) - 2;
  393             fseek(img, offset, SEEK_CUR);
  394         }
  395     }
  396     fclose(img);
  397     free(data);
  398     return ret;
  399 }
  400 
  401 image_s *
  402 image_new(int32_t width, int32_t height)
  403 {
  404     image_s *vimage;
  405 
  406     if((vimage = (image_s *)malloc(sizeof(image_s))) == NULL)
  407     {
  408         DPRINTF(E_WARN, L_METADATA, "malloc failed\n");
  409         return NULL;
  410     }
  411     vimage->width = width; vimage->height = height;
  412 
  413     if((vimage->buf = (pix *)malloc(width * height * sizeof(pix))) == NULL)
  414     {
  415         DPRINTF(E_WARN, L_METADATA, "malloc failed\n");
  416         free(vimage);
  417         return NULL;
  418     }
  419     return(vimage);
  420 }
  421 
  422 image_s *
  423 image_new_from_jpeg(const char *path, int is_file, const uint8_t *buf, int size, int scale, int rotate)
  424 {
  425     image_s *vimage;
  426     FILE  *file = NULL;
  427     struct jpeg_decompress_struct cinfo;
  428     unsigned char *line[16], *ptr;
  429     int x, y, i, w, h, ofs;
  430     int maxbuf;
  431     struct jpeg_error_mgr pub;
  432 
  433     cinfo.err = jpeg_std_error(&pub);
  434     pub.error_exit = libjpeg_error_handler;
  435     jpeg_create_decompress(&cinfo);
  436     if( is_file )
  437     {
  438         if( (file = fopen(path, "r")) == NULL )
  439         {
  440             return NULL;
  441         }
  442         jpeg_stdio_src(&cinfo, file);
  443     }
  444     else
  445     {
  446         jpeg_memory_src(&cinfo, buf, size);
  447     }
  448     if( setjmp(setjmp_buffer) )
  449     {
  450         jpeg_destroy_decompress(&cinfo);
  451         if( is_file && file )
  452             fclose(file);
  453         return NULL;
  454     }
  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);
  464     if(!vimage)
  465     {
  466         jpeg_destroy_decompress(&cinfo);
  467         if( is_file )
  468             fclose(file);
  469         return NULL;
  470     }
  471 
  472     if( setjmp(setjmp_buffer) )
  473     {
  474         jpeg_destroy_decompress(&cinfo);
  475         if( is_file && file )
  476             fclose(file);
  477         if( vimage )
  478         {
  479             free(vimage->buf);
  480             free(vimage);
  481         }
  482         return NULL;
  483     }
  484 
  485     if(cinfo.rec_outbuf_height > 16)
  486     {
  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);
  489         image_free(vimage);
  490         if( is_file )
  491             fclose(file);
  492         return NULL;
  493     }
  494     maxbuf = vimage->width * vimage->height;
  495     if(cinfo.output_components == 3)
  496     {
  497         int rx, ry;
  498         ofs = 0;
  499         if((ptr = malloc(w * 3 * cinfo.rec_outbuf_height + 16)) == NULL)
  500         {
  501             DPRINTF(E_WARN, L_METADATA, "malloc failed\n");
  502             jpeg_destroy_decompress(&cinfo);
  503             image_free(vimage);
  504             if( is_file )
  505                 fclose(file);
  506             return NULL;
  507         }
  508 
  509         for(y = 0; y < h; y += cinfo.rec_outbuf_height)
  510         {
  511             ry = (rotate & (ROTATE_90|ROTATE_180)) ? (y - h + 1) * -1 : y;
  512             for(i = 0; i < cinfo.rec_outbuf_height; i++)
  513             {
  514                 line[i] = ptr + (w * 3 * i);
  515             }
  516             jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
  517             for(x = 0; x < w * cinfo.rec_outbuf_height; x++)
  518             {
  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);
  521                 if( ofs < maxbuf )
  522                     vimage->buf[ofs] = COL(ptr[x + x + x], ptr[x + x + x + 1], ptr[x + x + x + 2]);
  523             }
  524         }
  525         free(ptr);
  526     }
  527     else if(cinfo.output_components == 1)
  528     {
  529         int rx, ry;
  530         ofs = 0;
  531         for(i = 0; i < cinfo.rec_outbuf_height; i++)
  532         {
  533             if((line[i] = malloc(w)) == NULL)
  534             {
  535                 int t = 0;
  536 
  537                 for(t = 0; t < i; t++) free(line[t]);
  538                 jpeg_destroy_decompress(&cinfo);
  539                 image_free(vimage);
  540                 if( is_file )
  541                     fclose(file);
  542                 return NULL;
  543             }
  544         }
  545         for(y = 0; y < h; y += cinfo.rec_outbuf_height)
  546         {
  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++)
  550             {
  551                 for(x = 0; x < w; x++)
  552                 {
  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);
  557                     if( ofs < maxbuf )
  558                         vimage->buf[ofs] =
  559                             COL(line[i][x], line[i][x], line[i][x]);
  560                 }
  561             }
  562         }
  563         for(i = 0; i < cinfo.rec_outbuf_height; i++)
  564         {
  565              free(line[i]);
  566         }
  567     }
  568     jpeg_finish_decompress(&cinfo);
  569     jpeg_destroy_decompress(&cinfo);
  570     if( is_file )
  571         fclose(file);
  572 
  573     return vimage;
  574 }
  575 
  576 void
  577 image_upsize(image_s * pdest, image_s * psrc, int32_t width, int32_t height)
  578 {
  579     int32_t vx, vy;
  580 #if !defined __i386__ && !defined __x86_64__
  581     int32_t rx, ry;
  582     pix vcol;
  583 
  584     if((pdest == NULL) || (psrc == NULL))
  585         return;
  586 
  587     for(vy = 0; vy < height; vy++)
  588     {
  589         for(vx = 0; vx < width; vx++)
  590         {
  591             rx = ((vx * psrc->width) / width);
  592             ry = ((vy * psrc->height) / height);
  593             vcol = get_pix(psrc, rx, ry);
  594 #else
  595     pix   vcol,vcol1,vcol2,vcol3,vcol4;
  596     float rx,ry;
  597     float width_scale, height_scale;
  598     float x_dist, y_dist;
  599 
  600     width_scale  = (float)psrc->width  / (float)width;
  601     height_scale = (float)psrc->height / (float)height;
  602 
  603     for(vy = 0;vy < height; vy++)
  604     {
  605         for(vx = 0;vx < width; vx++)
  606         {
  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);
  613 
  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))
  632                            );
  633 #endif
  634             put_pix_alpha_replace(pdest, vx, vy, vcol);
  635         }
  636     }
  637 }
  638 
  639 void
  640 image_downsize(image_s * pdest, image_s * psrc, int32_t width, int32_t height)
  641 {
  642     int32_t vx, vy;
  643     pix vcol;
  644     int32_t i, j;
  645 #if !defined __i386__ && !defined __x86_64__
  646     int32_t rx, ry, rx_next, ry_next;
  647     int red, green, blue, alpha;
  648     int factor;
  649 
  650     if((pdest == NULL) || (psrc == NULL))
  651         return;
  652 
  653     for(vy = 0; vy < height; vy++)
  654     {
  655         for(vx = 0; vx < width; vx++)
  656         {
  657 
  658             rx = ((vx * psrc->width) / width);
  659             ry = ((vy * psrc->height) / height);
  660 
  661             red = green = blue = alpha = 0;
  662 
  663             rx_next = rx + (psrc->width / width);
  664             ry_next = ry + (psrc->width / width);
  665             factor = 0;
  666 
  667             for( j = rx; j < rx_next; j++)
  668             {
  669                 for( i = ry; i < ry_next; i++)
  670                 {
  671                     factor += 1;
  672                     vcol = get_pix(psrc, j, i);
  673 
  674                     red   += COL_RED(vcol);
  675                     green += COL_GREEN(vcol);
  676                     blue  += COL_BLUE(vcol);
  677                     alpha += COL_ALPHA(vcol);
  678                 }
  679             }
  680 
  681             red   /= factor;
  682             green /= factor;
  683             blue  /= factor;
  684             alpha /= factor;
  685 
  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);
  691 #else
  692     float rx,ry;
  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;
  697 
  698     if( (pdest == NULL) || (psrc == NULL) )
  699         return;
  700 
  701     width_scale  = (float)psrc->width  / (float)width;
  702     height_scale = (float)psrc->height / (float)height;
  703 
  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)
  709         half_square_width++;
  710     else
  711         round_width = 1.0;
  712     if(round_height > 0.0)
  713         half_square_height++;
  714     else
  715         round_height = 1.0;
  716 
  717     for(vy = 0;vy < height; vy++)  
  718     {
  719         for(vx = 0;vx < width; vx++)
  720         {
  721             rx = vx * width_scale;
  722             ry = vy * height_scale;
  723             vcol = get_pix(psrc, (int32_t)rx, (int32_t)ry);
  724 
  725             red = green = blue = alpha = 0.0;
  726 
  727             for(j=0;j<half_square_height<<1;j++)
  728             {
  729                 for(i=0;i<half_square_width<<1;i++)
  730                 {
  731                     vcol = get_pix(psrc, ((int32_t)rx)-half_square_width+i,
  732                                          ((int32_t)ry)-half_square_height+j);
  733 
  734                     if(((j == 0) || (j == (half_square_height<<1)-1)) && 
  735                        ((i == 0) || (i == (half_square_width<<1)-1)))
  736                     {
  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);
  741                     }
  742                     else if((j == 0) || (j == (half_square_height<<1)-1))
  743                     {
  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);
  748                     }
  749                     else if((i == 0) || (i == (half_square_width<<1)-1))
  750                     {
  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);
  755                     }
  756                     else
  757                     {
  758                         red   += (float)COL_RED  (vcol);
  759                         green += (float)COL_GREEN(vcol);
  760                         blue  += (float)COL_BLUE (vcol);
  761                         alpha += (float)COL_ALPHA(vcol);
  762                     }
  763                 }
  764             }
  765 
  766             red   /= width_scale*height_scale;
  767             green /= width_scale*height_scale;
  768             blue  /= width_scale*height_scale;
  769             alpha /= width_scale*height_scale;
  770 
  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);
  776 #endif
  777             put_pix_alpha_replace(pdest, vx, vy,
  778                           COL_FULL((uint8_t)red, (uint8_t)green, (uint8_t)blue, (uint8_t)alpha));
  779         }
  780     }
  781 }
  782 
  783 image_s *
  784 image_resize(image_s * src_image, int32_t width, int32_t height)
  785 {
  786     image_s * dst_image;
  787 
  788     dst_image = image_new(width, height);
  789     if( !dst_image )
  790         return NULL;
  791     if( (src_image->width < width) || (src_image->height < height) )
  792         image_upsize(dst_image, src_image, width, height);
  793     else
  794         image_downsize(dst_image, src_image, width, height);
  795 
  796     return dst_image;
  797 }
  798 
  799 
  800 unsigned char *
  801 image_save_to_jpeg_buf(image_s * pimage, int * size)
  802 {
  803     struct jpeg_compress_struct cinfo;
  804     struct jpeg_error_mgr jerr;
  805     JSAMPROW row_pointer[1];
  806     int row_stride;
  807     char *data;
  808     int i, x;
  809     struct my_dst_mgr dst;
  810 
  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)
  823     {
  824         DPRINTF(E_WARN, L_METADATA, "malloc failed\n");
  825         free(dst.buf);
  826         jpeg_destroy_compress(&cinfo);
  827         return NULL;
  828     }
  829     i = 0;
  830     while(cinfo.next_scanline < cinfo.image_height)
  831     {
  832         for(x = 0; x < pimage->width; x++)
  833         {
  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]);
  837             i++;
  838         }
  839         row_pointer[0] = (unsigned char *)data;
  840         jpeg_write_scanlines(&cinfo, row_pointer, 1);
  841     }
  842     jpeg_finish_compress(&cinfo);
  843     *size = dst.used;
  844     free(data);
  845     jpeg_destroy_compress(&cinfo);
  846 
  847     return dst.buf;
  848 }
  849 
  850 char *
  851 image_save_to_jpeg_file(image_s * pimage, char * path)
  852 {
  853     int nwritten, size = 0;
  854     unsigned char * buf;
  855     FILE * dst_file;
  856 
  857     buf = image_save_to_jpeg_buf(pimage, &size);
  858     if( !buf )
  859         return NULL;
  860     dst_file = fopen(path, "w");
  861     if( !dst_file )
  862     {
  863         free(buf);
  864         return NULL;
  865     }
  866     nwritten = fwrite(buf, 1, size, dst_file);
  867     fclose(dst_file);
  868     free(buf);
  869 
  870     return (nwritten == size) ? path : NULL;
  871 }