diff --git a/INSTALL b/INSTALL index 78537d6..b3bbd16 100644 --- a/INSTALL +++ b/INSTALL @@ -1,12 +1,12 @@ MiniDLNA project. -(c) 2008 Justin Maggard +(c) 2009 Justin Maggard Parts (c) 2006-2008 Thomas Bernard Homepage : http://sourceforge.net/projects/minidlna/ Prerequisites : - libexif -- libgd2 (either libgd2-xpm or libgd2-noxpm) +- libjpeg - libid3tag - libFLAC - libvorbis diff --git a/Makefile b/Makefile index 6550028..aec7597 100644 --- a/Makefile +++ b/Makefile @@ -28,20 +28,20 @@ BASEOBJS = minidlna.o upnphttp.o upnpdescgen.o upnpsoap.o \ upnpreplyparse.o minixml.o \ getifaddr.o daemonize.o upnpglobalvars.o \ options.o minissdp.o upnpevents.o \ - sql.o utils.o metadata.o albumart.o scanner.o inotify.o \ + sql.o utils.o metadata.o scanner.o inotify.o \ tivo_utils.o tivo_beacon.o tivo_commands.o \ tagutils/textutils.o tagutils/misc.o tagutils/tagutils.o \ - log.o + image_utils.o albumart.o log.o ALLOBJS = $(BASEOBJS) $(LNXOBJS) -LIBS = -lexif -ljpeg -lsqlite3 -lavformat -lid3tag -lFLAC -lvorbis -luuid -lgd +LIBS = -lexif -ljpeg -lsqlite3 -lavformat -lid3tag -lFLAC -lvorbis -luuid TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o EXECUTABLES = minidlna testupnpdescgen -.PHONY: all clean install depend genuuid +.PHONY: all clean install depend all: $(EXECUTABLES) @@ -50,7 +50,7 @@ clean: $(RM) $(EXECUTABLES) $(RM) testupnpdescgen.o -install: minidlna genuuid +install: minidlna $(INSTALL) -d $(SBININSTALLDIR) $(INSTALL) minidlna $(SBININSTALLDIR) $(INSTALL) -d $(ETCINSTALLDIR) @@ -60,11 +60,6 @@ install: minidlna genuuid $(INSTALL) -d $(PREFIX)/etc/init.d $(INSTALL) linux/miniupnpd.init.d.script $(PREFIX)/etc/init.d/miniupnpd -# genuuid is using the uuidgen CLI tool which is part of libuuid -# from the e2fsprogs -genuuid: - sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`(genuuid||uuidgen) 2>/dev/null`/" minidlna.conf - minidlna: $(BASEOBJS) $(LNXOBJS) $(LIBS) testupnpdescgen: $(TESTUPNPDESCGENOBJS) @@ -83,7 +78,7 @@ minidlna.o: upnphttp.h upnpdescgen.h minidlnapath.h getifaddr.h upnpsoap.h minidlna.o: options.h minissdp.h daemonize.h upnpevents.h minidlna.o: commonrdr.h log.h upnphttp.o: config.h upnphttp.h upnpdescgen.h minidlnapath.h upnpsoap.h -upnphttp.o: upnpevents.h log.h +upnphttp.o: upnpevents.h image_utils.h sql.h log.h upnpdescgen.o: config.h upnpdescgen.h minidlnapath.h upnpglobalvars.h upnpdescgen.o: minidlnatypes.h upnpdescstrings.h log.h upnpsoap.o: config.h upnpglobalvars.h minidlnatypes.h log.h utils.h sql.h @@ -105,8 +100,13 @@ upnpdescgen.o: config.h upnpdescgen.h minidlnapath.h upnpglobalvars.h upnpdescgen.o: minidlnatypes.h upnpdescstrings.h scanner.o: upnpglobalvars.h metadata.h utils.h sql.h scanner.h log.h metadata.o: upnpglobalvars.h metadata.h albumart.h utils.h sql.h log.h +albumart.o: upnpglobalvars.h albumart.h utils.h image_utils.h sql.h log.h tagutils/misc.o: tagutils/misc.h tagutils/textutils.o: tagutils/misc.h tagutils/textutils.h log.h -tagutils/tagutils.o: tagutils/tagutils-asf.c tagutils/tagutils-flc.c tagutils/tagutils-plist.c tagutils/tagutils-aac.c tagutils/tagutils-asf.h tagutils/tagutils-flc.h tagutils/tagutils-mp3.c tagutils/tagutils-ogg.c tagutils/tagutils-aac.h tagutils/tagutils.h tagutils/tagutils-mp3.h tagutils/tagutils-ogg.h log.h +tagutils/tagutils.o: tagutils/tagutils-asf.c tagutils/tagutils-flc.c tagutils/tagutils-plist.c +tagutils/tagutils.o: tagutils/tagutils-aac.c tagutils/tagutils-asf.h tagutils/tagutils-flc.h tagutils/tagutils-mp3.c +tagutils/tagutils.o: tagutils/tagutils-ogg.c tagutils/tagutils-aac.h tagutils/tagutils.h tagutils/tagutils-mp3.h tagutils/tagutils-ogg.h log.h +image_utils.o: image_utils.h +utils.o: utils.h sql.o: sql.h log.o: log.h diff --git a/README b/README index 8111274..2672db8 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ MiniDLNA project -(c) 2008 Justin Maggard +(c) 2009 Justin Maggard Parts (c) 2006-2007 Thomas Bernard webpage: http://sourceforge.net/projects/minidlna/ diff --git a/albumart.c b/albumart.c index 8493ba2..a8f5334 100644 --- a/albumart.c +++ b/albumart.c @@ -25,51 +25,24 @@ #include #include -#include #include "upnpglobalvars.h" #include "sql.h" #include "utils.h" +#include "image_utils.h" #include "log.h" -/* For libjpeg error handling */ -jmp_buf setjmp_buffer; -static void libjpeg_error_handler(j_common_ptr cinfo) -{ - cinfo->err->output_message (cinfo); - longjmp(setjmp_buffer, 1); - return; -} - -#if 0 // Not needed currently -int -check_res(int width, int height, char * dlna_pn) -{ - if( (width <= 0) || (height <= 0) ) - return 0; - if( width <= 160 && height <= 160 ) - strcpy(dlna_pn, "JPEG_TN"); - else if( width <= 640 && height <= 480 ) - strcpy(dlna_pn, "JPEG_SM"); - else if( width <= 1024 && height <= 768 ) - strcpy(dlna_pn, "JPEG_MED"); - else if( width <= 4096 && height <= 4096 ) - strcpy(dlna_pn, "JPEG_LRG"); - else - return 0; - return 1; -} -#endif - char * -save_resized_album_art(void * ptr, const char * path, int srcw, int srch, int file, int size) +save_resized_album_art(image * imsrc, const char * path) { - FILE *dstfile; - gdImagePtr imsrc = 0, imdst = 0; int dstw, dsth; + image * imdst; char * cache_file; char * cache_dir; + if( !imsrc ) + return NULL; + asprintf(&cache_file, DB_PATH "/art_cache%s", path); if( access(cache_file, F_OK) == 0 ) return cache_file; @@ -78,114 +51,30 @@ save_resized_album_art(void * ptr, const char * path, int srcw, int srch, int fi make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); free(cache_dir); - if( file ) - imsrc = gdImageCreateFromJpeg((FILE *)ptr); - else - imsrc = gdImageCreateFromJpegPtr(size, ptr); - if( !imsrc ) - goto error; - - dstfile = fopen(cache_file, "w"); - if( !dstfile ) - goto error; - - if( srcw > srch ) + if( imsrc->width > imsrc->height ) { dstw = 160; - dsth = (srch<<8) / ((srcw<<8)/160); + dsth = (imsrc->height<<8) / ((imsrc->width<<8)/160); } else { - dstw = (srcw<<8) / ((srch<<8)/160); + dstw = (imsrc->width<<8) / ((imsrc->height<<8)/160); dsth = 160; } - imdst = gdImageCreateTrueColor(dstw, dsth); + imdst = image_resize(imsrc, dstw, dsth); if( !imdst ) - { - gdImageDestroy(imsrc); - fclose(dstfile); goto error; - } - #if 0 // Try our box filter resizer instead - #ifdef __sparc__ - gdImageCopyResized(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, imsrc->sx, imsrc->sy); - #else - gdImageCopyResampled(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, imsrc->sx, imsrc->sy); - #endif - #else - boxfilter_resize(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, imsrc->sx, imsrc->sy); - #endif - gdImageJpeg(imdst, dstfile, 96); - fclose(dstfile); - gdImageDestroy(imsrc); - gdImageDestroy(imdst); - return cache_file; + if( image_save_to_jpeg_file(imdst, cache_file) == 0 ) + { + image_free(imdst); + return cache_file; + } error: free(cache_file); return NULL; } -/* These next few functions are to allow loading JPEG data directly from memory for libjpeg. - * The standard functions only allow you to read from a file. - * This code comes from the JpgAlleg library, at http://wiki.allegro.cc/index.php?title=Libjpeg */ -struct -my_src_mgr -{ - struct jpeg_source_mgr pub; - JOCTET eoi_buffer[2]; -}; - -static void -init_source(j_decompress_ptr cinfo) -{ -} - -static int -fill_input_buffer(j_decompress_ptr cinfo) -{ - return 1; -} - -static void -skip_input_data(j_decompress_ptr cinfo, long num_bytes) -{ - struct my_src_mgr *src = (void *)cinfo->src; - if (num_bytes > 0) - { - while (num_bytes > (long)src->pub.bytes_in_buffer) - { - num_bytes -= (long)src->pub.bytes_in_buffer; - fill_input_buffer(cinfo); - } - } - src->pub.next_input_byte += num_bytes; - src->pub.bytes_in_buffer -= num_bytes; -} - -static void -term_source(j_decompress_ptr cinfo) -{ -} - -void -jpeg_memory_src(j_decompress_ptr cinfo, unsigned char const *buffer, size_t bufsize) -{ - struct my_src_mgr *src; - if (! cinfo->src) - { - cinfo->src = (*cinfo->mem->alloc_small)((void *)cinfo, JPOOL_PERMANENT, sizeof(struct my_src_mgr));; - } - src = (void *)cinfo->src; - src->pub.init_source = init_source; - src->pub.fill_input_buffer = fill_input_buffer; - src->pub.skip_input_data = skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; - src->pub.term_source = term_source; - src->pub.next_input_byte = buffer; - src->pub.bytes_in_buffer = bufsize; -} - /* Simple, efficient hash function from Daniel J. Bernstein */ unsigned int DJBHash(const char * str, int len) { @@ -204,12 +93,11 @@ unsigned int DJBHash(const char * str, int len) char * check_embedded_art(const char * path, const char * image_data, int image_size) { - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; int width = 0, height = 0; char * art_path = NULL; char * cache_dir; FILE * dstfile; + image * imsrc; size_t nwritten; static char last_path[PATH_MAX]; static unsigned int last_hash = 0; @@ -237,22 +125,13 @@ check_embedded_art(const char * path, const char * image_data, int image_size) } } - cinfo.err = jpeg_std_error(&jerr); - jerr.error_exit = libjpeg_error_handler; - jpeg_create_decompress(&cinfo); - if( setjmp(setjmp_buffer) ) - goto error; - jpeg_memory_src(&cinfo, (unsigned char *)image_data, image_size); - jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); - width = cinfo.output_width; - height = cinfo.output_height; - error: - jpeg_destroy_decompress(&cinfo); + imsrc = image_new_from_jpeg(NULL, 0, image_data, image_size); + width = imsrc->width; + height = imsrc->height; if( width > 160 || height > 160 ) { - art_path = save_resized_album_art((void *)image_data, path, width, height, 0, image_size); + art_path = save_resized_album_art(imsrc, path); } else if( width > 0 && height > 0 ) { @@ -274,6 +153,7 @@ check_embedded_art(const char * path, const char * image_data, int image_size) return NULL; } } + image_free(imsrc); if( !art_path ) { DPRINTF(E_WARN, L_METADATA, "Invalid embedded album art in %s\n", basename((char *)path)); @@ -291,9 +171,7 @@ check_for_album_file(char * dir) { char * file = malloc(PATH_MAX); struct album_art_name_s * album_art_name; - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - static FILE * infile; + image * imsrc; int width=0, height=0; char * art_file; @@ -302,28 +180,16 @@ check_for_album_file(char * dir) sprintf(file, "%s/%s", dir, album_art_name->name); if( access(file, R_OK) == 0 ) { - infile = fopen(file, "r"); - cinfo.err = jpeg_std_error(&jerr); - jerr.error_exit = libjpeg_error_handler; - jpeg_create_decompress(&cinfo); - if( setjmp(setjmp_buffer) ) - goto error; - jpeg_stdio_src(&cinfo, infile); - jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); - width = cinfo.output_width; - height = cinfo.output_height; + imsrc = image_new_from_jpeg(file, 1, NULL, 0); + width = imsrc->width; + height = imsrc->height; if( width > 160 || height > 160 ) { art_file = file; - rewind(infile); - file = save_resized_album_art((void *)infile, art_file, width, height, 1, 0); + file = save_resized_album_art(imsrc, art_file); free(art_file); } - error: - jpeg_destroy_decompress(&cinfo); - fclose(infile); - + image_free(imsrc); return(file); } } diff --git a/albumart.h b/albumart.h index 7711d59..1ae5cac 100644 --- a/albumart.h +++ b/albumart.h @@ -1,4 +1,4 @@ -/* Utility functions +/* Album art extraction, caching, and scaling * * Project : minidlna * Website : http://sourceforge.net/projects/minidlna/ diff --git a/genconfig.sh b/genconfig.sh index 607f5c8..d9e96f9 100755 --- a/genconfig.sh +++ b/genconfig.sh @@ -29,9 +29,9 @@ fi ${RM} ${CONFIGFILE} -echo "/* MiniUPnP Project" >> ${CONFIGFILE} -echo " * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/" >> ${CONFIGFILE} -echo " * (c) 2006-2008 Thomas Bernard" >> ${CONFIGFILE} +echo "/* MiniDLNA Project" >> ${CONFIGFILE} +echo " * http://sourceforge.net/projects/minidlna/" >> ${CONFIGFILE} +echo " * (c) 2008-2009 Justin Maggard" >> ${CONFIGFILE} echo " * generated by $0 on `date` */" >> ${CONFIGFILE} echo "#ifndef $CONFIGMACRO" >> ${CONFIGFILE} echo "#define $CONFIGMACRO" >> ${CONFIGFILE} diff --git a/image_utils.c b/image_utils.c new file mode 100644 index 0000000..7e208e4 --- /dev/null +++ b/image_utils.c @@ -0,0 +1,518 @@ +/* MiniDLNA media server + * Copyright (C) 2009 Justin Maggard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* These functions are mostly based on code from other projects. + * There are function to effiently resize a JPEG image, and some utility functions. + * They are here to allow loading and saving JPEG data directly to or from memory with libjpeg. + * The standard functions only allow you to read from or write to a file. + * + * The reading code comes from the JpgAlleg library, at http://wiki.allegro.cc/index.php?title=Libjpeg + * The writing code was posted on a Google group from openjpeg, at http://groups.google.com/group/openjpeg/browse_thread/thread/331e6cf60f70797f + * The resize functions come from the resize_image project, at http://www.golac.fr/Image-Resizer + */ + +#include +#include +#include +#include +#include +#include + +#include "image_utils.h" +#include "log.h" + +#define JPEG_QUALITY 96 + +#define COL(red, green, blue) (((red) << 24) | ((green) << 16) | ((blue) << 8) | 0xFF) +#define COL_FULL(red, green, blue, alpha) (((red) << 24) | ((green) << 16) | ((blue) << 8) | (alpha)) +#define COL_RED(col) (col >> 24) +#define COL_GREEN(col) ((col >> 16) & 0xFF) +#define COL_BLUE(col) ((col >> 8) & 0xFF) +#define COL_ALPHA(col) (col & 0xFF) +#define BLACK 0x000000FF + + +struct my_dst_mgr { + struct jpeg_destination_mgr jdst; + JOCTET *buf; + JOCTET *off; + size_t sz; + size_t used; +}; + +/* Destination manager to store data in a buffer */ +static void +my_dst_mgr_init(j_compress_ptr cinfo) +{ + struct my_dst_mgr *dst = (void *)cinfo->dest; + + dst->used = 0; + dst->sz = cinfo->image_width + * cinfo->image_height + * cinfo->input_components; + dst->buf = malloc(dst->sz * sizeof *dst->buf); + dst->off = dst->buf; + dst->jdst.next_output_byte = dst->off; + dst->jdst.free_in_buffer = dst->sz; + + return; + +} + +static boolean +my_dst_mgr_empty(j_compress_ptr cinfo) +{ + struct my_dst_mgr *dst = (void *)cinfo->dest; + + dst->sz *= 2; + dst->used = dst->off - dst->buf; + dst->buf = realloc(dst->buf, dst->sz * sizeof *dst->buf); + dst->off = dst->buf + dst->used; + dst->jdst.next_output_byte = dst->off; + dst->jdst.free_in_buffer = dst->sz - dst->used; + + return TRUE; + +} + +static void +my_dst_mgr_term(j_compress_ptr cinfo) +{ + struct my_dst_mgr *dst = (void *)cinfo->dest; + + dst->used += dst->sz - dst->jdst.free_in_buffer; + dst->off = dst->buf + dst->used; + + return; + +} + +static void +jpeg_memory_dest(j_compress_ptr cinfo, struct my_dst_mgr *dst) +{ + dst->jdst.init_destination = my_dst_mgr_init; + dst->jdst.empty_output_buffer = my_dst_mgr_empty; + dst->jdst.term_destination = my_dst_mgr_term; + cinfo->dest = (void *)dst; + + return; + +} + +/* Source manager to read data from a buffer */ +struct +my_src_mgr +{ + struct jpeg_source_mgr pub; + JOCTET eoi_buffer[2]; +}; + +static void +init_source(j_decompress_ptr cinfo) +{ + return; +} + +static int +fill_input_buffer(j_decompress_ptr cinfo) +{ + return 1; +} + +static void +skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + struct my_src_mgr *src = (void *)cinfo->src; + if (num_bytes > 0) + { + while (num_bytes > (long)src->pub.bytes_in_buffer) + { + num_bytes -= (long)src->pub.bytes_in_buffer; + fill_input_buffer(cinfo); + } + } + src->pub.next_input_byte += num_bytes; + src->pub.bytes_in_buffer -= num_bytes; +} + +static void +term_source(j_decompress_ptr cinfo) +{ + return; +} + +void +jpeg_memory_src(j_decompress_ptr cinfo, const unsigned char * buffer, size_t bufsize) +{ + struct my_src_mgr *src; + + if (! cinfo->src) + { + cinfo->src = (*cinfo->mem->alloc_small)((void *)cinfo, JPOOL_PERMANENT, sizeof(struct my_src_mgr));; + } + src = (void *)cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; + src->pub.term_source = term_source; + src->pub.next_input_byte = buffer; + src->pub.bytes_in_buffer = bufsize; +} + +/* Don't exit on error like libjpeg likes to do */ +static void +libjpeg_error_handler(j_common_ptr cinfo) +{ + cinfo->err->output_message(cinfo); + return; +} + +void +image_free(image *pimage) +{ + free(pimage->buf); + free(pimage); +} + +pix +get_pix(image *pimage, int32_t x, int32_t y) +{ + if((x >= 0) && (y >= 0) && (x < pimage->width) && (y < pimage->height)) + { + return(pimage->buf[(y * pimage->width) + x]); + } + else + { + pix vpix = BLACK; + return(vpix); + } +} + +void +put_pix_alpha_replace(image *pimage, int32_t x, int32_t y, pix col) +{ + if((x >= 0) && (y >= 0) && (x < pimage->width) && (y < pimage->height)) + pimage->buf[(y * pimage->width) + x] = col; +} + +image * +image_new(int32_t width, int32_t height) +{ + image *vimage; + + if((vimage = (image *)malloc(sizeof(image))) == NULL) + { + DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); + return NULL; + } + vimage->width = width; vimage->height = height; + + if((vimage->buf = (pix *)malloc(width * height * sizeof(pix))) == NULL) + { + DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); + return NULL; + } + return(vimage); +} + +image * +image_new_from_jpeg(const char * path, int is_file, const char * buf, int size) +{ + image *vimage; + FILE *file; + struct jpeg_decompress_struct cinfo; + unsigned char *line[16], *ptr; + int x, y, i, w, h, ofs; + int maxbuf; + struct jpeg_error_mgr pub; + + + cinfo.err = jpeg_std_error(&pub); + pub.error_exit = libjpeg_error_handler; + jpeg_create_decompress(&cinfo); + if( is_file ) + { + if( (file = fopen(path, "r")) == NULL ) + { + return NULL; + } + jpeg_stdio_src(&cinfo, file); + } + else + { + jpeg_memory_src(&cinfo, (const unsigned char *)buf, size); + } + jpeg_read_header(&cinfo, TRUE); + cinfo.do_fancy_upsampling = FALSE; + cinfo.do_block_smoothing = FALSE; + jpeg_start_decompress(&cinfo); + w = cinfo.output_width; + h = cinfo.output_height; + vimage = image_new(w, h); + if(!vimage) + { + jpeg_destroy_decompress(&cinfo); + if( is_file ) + fclose(file); + return NULL; + } + + if(cinfo.rec_outbuf_height > 16) + { + DPRINTF(E_WARN, L_METADATA, "ERROR image_from_jpeg : (image_from_jpeg.c) JPEG uses line buffers > 16. Cannot load.\n"); + image_free(vimage); + if( is_file ) + fclose(file); + return NULL; + } + maxbuf = vimage->width * vimage->height; + if(cinfo.output_components == 3) + { + ofs = 0; + if((ptr = (unsigned char *)malloc(w * 3 * cinfo.rec_outbuf_height)) == NULL) + { + DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); + return NULL; + } + + for(y = 0; y < h; y += cinfo.rec_outbuf_height) + { + for(i = 0; i < cinfo.rec_outbuf_height; i++) + { + line[i] = ptr + (w * 3 * i); + } + jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); + for(x = 0; x < w * cinfo.rec_outbuf_height; x++) + { + if( ofs < maxbuf ) + { + vimage->buf[ofs] = COL(ptr[x + x + x], ptr[x + x + x + 1], ptr[x + x + x + 2]); + ofs++; + } + } + } + free(ptr); + } + else if(cinfo.output_components == 1) + { + ofs = 0; + for(i = 0; i < cinfo.rec_outbuf_height; i++) + { + if((line[i] = (unsigned char *)malloc(w)) == NULL) + { + int t = 0; + + for(t = 0; t < i; t++) free(line[t]); + jpeg_destroy_decompress(&cinfo); + image_free(vimage); + if( is_file ) + fclose(file); + return NULL; + } + } + for(y = 0; y < h; y += cinfo.rec_outbuf_height) + { + jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); + for(i = 0; i < cinfo.rec_outbuf_height; i++) + { + for(x = 0; x < w; x++) + { + vimage->buf[ofs++] = COL(line[i][x], line[i][x], line[i][x]); + } + } + } + for(i = 0; i < cinfo.rec_outbuf_height; i++) + { + free(line[i]); + } + } + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + if( is_file ) + fclose(file); + + return vimage; +} + +void +image_resize_nearest(image * pdest, image * psrc, int32_t width, int32_t height) +{ + int32_t vx, vy, rx, ry; + pix vcol; + + if((pdest == NULL) || (psrc == NULL)) + return; + + for(vy = 0; vy < height; vy++) + { + for(vx = 0; vx < width; vx++) + { + rx = ((vx * psrc->width) / width); + ry = ((vy * psrc->height) / height); + vcol = get_pix(psrc, rx, ry); + put_pix_alpha_replace(pdest, vx, vy, vcol); + } + } +} + +void +image_downsize_rought(image * pdest, image * psrc, int32_t width, int32_t height) +{ + int32_t vx, vy; + pix vcol; + int32_t i, j; + int32_t rx, ry, rx_next, ry_next; + int red, green, blue, alpha; + int factor; + + if((pdest == NULL) || (psrc == NULL)) + return; + + for(vy = 0; vy < height; vy++) + { + for(vx = 0; vx < width; vx++) + { + + rx = ((vx * psrc->width) / width); + ry = ((vy * psrc->height) / height); + + red = green = blue = alpha = 0; + + rx_next = rx + (psrc->width / width); + ry_next = ry + (psrc->width / width); + factor = 0; + + for( j = rx; j < rx_next; j++) + { + for( i = ry; i < ry_next; i++) + { + factor += 1; + vcol = get_pix(psrc, j, i); + + red += COL_RED(vcol); + green += COL_GREEN(vcol); + blue += COL_BLUE(vcol); + alpha += COL_ALPHA(vcol); + } + } + + red /= factor; + green /= factor; + blue /= factor; + alpha /= factor; + + /* on sature les valeurs */ + red = (red > 255) ? 255 : ((red < 0) ? 0 : red ); + green = (green > 255) ? 255 : ((green < 0) ? 0 : green); + blue = (blue > 255) ? 255 : ((blue < 0) ? 0 : blue ); + alpha = (alpha > 255) ? 255 : ((alpha < 0) ? 0 : alpha); + + put_pix_alpha_replace(pdest, vx, vy, + COL_FULL((u_int8_t)red, (u_int8_t)green, (u_int8_t)blue, (u_int8_t)alpha)); + } + } +} + +image * +image_resize(image * src_image, int32_t width, int32_t height) +{ + image * dst_image; + + dst_image = image_new(width, height); + if( !dst_image ) + return NULL; + if( (src_image->width < width) || (src_image->height < height) ) + image_resize_nearest(dst_image, src_image, width, height); + else + image_downsize_rought(dst_image, src_image, width, height); + + return dst_image; +} + + +unsigned char * +image_save_to_jpeg_buf(image * pimage, int * size) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPROW row_pointer[1]; + int row_stride; + char *data; + int i, x; + struct my_dst_mgr dst; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_memory_dest(&cinfo, &dst); + cinfo.image_width = pimage->width; + cinfo.image_height = pimage->height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE); + jpeg_start_compress(&cinfo, TRUE); + row_stride = cinfo.image_width * 3; + if((data = malloc(row_stride)) == NULL) + { + DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); + return NULL; + } + i = 0; + while(cinfo.next_scanline < cinfo.image_height) + { + for(x = 0; x < pimage->width; x++) + { + data[x + x + x] = COL_RED(pimage->buf[i]); + data[x + x + x + 1] = COL_GREEN(pimage->buf[i]); + data[x + x + x + 2] = COL_BLUE(pimage->buf[i]); + i++; + } + row_pointer[0] = (unsigned char *)data; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + jpeg_finish_compress(&cinfo); + *size = dst.used; + free(data); + jpeg_destroy_compress(&cinfo); + + return dst.buf; +} + +int +image_save_to_jpeg_file(image * pimage, const char * path) +{ + int nwritten, size = 0; + unsigned char * buf; + FILE * dst_file; + + buf = image_save_to_jpeg_buf(pimage, &size); + if( !buf ) + return -1; + dst_file = fopen(path, "w"); + if( !dst_file ) + { + free(buf); + return -1; + } + nwritten = fwrite(buf, 1, size, dst_file); + fclose(dst_file); + free(buf); + + return (nwritten==size ? 0 : 1); +} diff --git a/image_utils.h b/image_utils.h new file mode 100644 index 0000000..cac6d01 --- /dev/null +++ b/image_utils.h @@ -0,0 +1,33 @@ +/* Image manipulation functions + * + * Project : minidlna + * Website : http://sourceforge.net/projects/minidlna/ + * Author : Justin Maggard + * Copyright (c) 2009 Justin Maggard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#include + +typedef u_int32_t pix; + +typedef struct { + int32_t width; + int32_t height; + pix *buf; +} image; + +void +image_free(image *pimage); + +image * +image_new_from_jpeg(const char * path, int is_file, const char * ptr, int size); + +image * +image_resize(image * src_image, int32_t width, int32_t height); + +unsigned char * +image_save_to_jpeg_buf(image * pimage, int * size); + +int +image_save_to_jpeg_file(image * pimage, const char * path); diff --git a/metadata.c b/metadata.c index b567142..3ce7e19 100644 --- a/metadata.c +++ b/metadata.c @@ -1,5 +1,5 @@ /* MiniDLNA media server - * Copyright (C) 2008 Justin Maggard + * Copyright (C) 2008-2009 Justin Maggard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/metadata.h b/metadata.h index f274d8a..823b032 100644 --- a/metadata.h +++ b/metadata.h @@ -3,7 +3,7 @@ * Project : minidlna * Website : http://sourceforge.net/projects/minidlna/ * Author : Justin Maggard - * Copyright (c) 2008 Justin Maggard + * Copyright (c) 2008-2009 Justin Maggard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ diff --git a/minidlna.c b/minidlna.c index b7f8e2e..03633b3 100644 --- a/minidlna.c +++ b/minidlna.c @@ -1,7 +1,7 @@ /* MiniDLNA project * * http://sourceforge.net/projects/minidlna/ - * (c) 2008 Justin Maggard + * (c) 2008-2009 Justin Maggard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution * @@ -594,9 +594,11 @@ main(int argc, char * * argv) struct timeval timeout, timeofday, lasttimeofday = {0, 0}, lastupdatetime = {0, 0}; int max_fd = -1; int last_changecnt = 0; + #ifdef TIVO_SUPPORT unsigned short int loop_cnt = 0; int sbeacon; struct sockaddr_in tivo_bcast; + #endif char * sql; pthread_t thread[2]; diff --git a/scanner.c b/scanner.c index de84281..0bcaba8 100644 --- a/scanner.c +++ b/scanner.c @@ -1,5 +1,5 @@ /* MiniDLNA media server - * Copyright (C) 2008 Justin Maggard + * Copyright (C) 2008-2009 Justin Maggard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/scanner.h b/scanner.h index daec516..82f44a6 100644 --- a/scanner.h +++ b/scanner.h @@ -3,7 +3,7 @@ * Project : minidlna * Website : http://sourceforge.net/projects/minidlna/ * Author : Justin Maggard - * Copyright (c) 2008 Justin Maggard + * Copyright (c) 2008-2009 Justin Maggard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ diff --git a/sql.c b/sql.c index bcf51f1..8c1f919 100644 --- a/sql.c +++ b/sql.c @@ -1,5 +1,5 @@ /* MiniDLNA media server - * Copyright (C) 2008 Justin Maggard + * Copyright (C) 2008-2009 Justin Maggard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sql.h b/sql.h index fc57610..a69e49a 100644 --- a/sql.h +++ b/sql.h @@ -3,7 +3,7 @@ * Project : minidlna * Website : http://sourceforge.net/projects/minidlna/ * Author : Justin Maggard - * Copyright (c) 2008 Justin Maggard + * Copyright (c) 2008-2009 Justin Maggard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ diff --git a/tivo_beacon.h b/tivo_beacon.h index c4f688e..b1982e4 100644 --- a/tivo_beacon.h +++ b/tivo_beacon.h @@ -1,3 +1,12 @@ +/* TiVo discovery + * + * Project : minidlna + * Website : http://sourceforge.net/projects/minidlna/ + * Author : Justin Maggard + * Copyright (c) 2009 Justin Maggard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ #include "config.h" #ifdef TIVO_SUPPORT /* diff --git a/tivo_commands.c b/tivo_commands.c index 8fff1bd..adcedc7 100644 --- a/tivo_commands.c +++ b/tivo_commands.c @@ -1,3 +1,20 @@ +/* MiniDLNA media server + * Copyright (C) 2009 Justin Maggard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #include "config.h" #ifdef TIVO_SUPPORT #include @@ -56,6 +73,7 @@ SendRootContainer(struct upnphttp * h) "" "", friendly_name, friendly_name, friendly_name); BuildResp_upnphttp(h, resp, len); + free(resp); SendResp_upnphttp(h); } diff --git a/tivo_commands.h b/tivo_commands.h index 8cec076..7307a73 100644 --- a/tivo_commands.h +++ b/tivo_commands.h @@ -1,5 +1,16 @@ +/* TiVo command processing + * + * Project : minidlna + * Website : http://sourceforge.net/projects/minidlna/ + * Author : Justin Maggard + * Copyright (c) 2009 Justin Maggard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ #include "config.h" #ifdef TIVO_SUPPORT + void ProcessTiVoCommand(struct upnphttp * h, const char * orig_path); + #endif diff --git a/tivo_utils.c b/tivo_utils.c index 645bc6d..5c171c6 100644 --- a/tivo_utils.c +++ b/tivo_utils.c @@ -1,3 +1,20 @@ +/* MiniDLNA media server + * Copyright (C) 2009 Justin Maggard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #include "config.h" #ifdef TIVO_SUPPORT #include diff --git a/tivo_utils.h b/tivo_utils.h index 5dcf2a6..c77a83d 100644 --- a/tivo_utils.h +++ b/tivo_utils.h @@ -1,3 +1,12 @@ +/* TiVo helper functions + * + * Project : minidlna + * Website : http://sourceforge.net/projects/minidlna/ + * Author : Justin Maggard + * Copyright (c) 2009 Justin Maggard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ #include "config.h" #ifdef TIVO_SUPPORT #include @@ -13,4 +22,5 @@ decodeString(char * string, int inplace); void TiVoRandomSeedFunc(sqlite3_context *context, int argc, sqlite3_value **argv); + #endif diff --git a/upnpglobalvars.h b/upnpglobalvars.h index a3afe26..955871c 100644 --- a/upnpglobalvars.h +++ b/upnpglobalvars.h @@ -57,9 +57,9 @@ extern time_t startup_time; extern struct runtime_vars_s runtime_vars; /* runtime boolean flags */ extern int runtime_flags; -#define INOTIFYMASK 0x0001 -#define SYSUPTIMEMASK 0x0002 -#define TIVOMASK 0x0004 +#define INOTIFYMASK 0x0001 +#define SYSUPTIMEMASK 0x0002 +#define TIVOMASK 0x0004 #define SETFLAG(mask) runtime_flags |= mask #define GETFLAG(mask) runtime_flags & mask diff --git a/upnphttp.c b/upnphttp.c index 6b575b8..32996d6 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -1,6 +1,6 @@ /* MiniDLNA project * http://minidlna.sourceforge.net/ - * (c) 2008 Justin Maggard + * (c) 2008-2009 Justin Maggard * * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution @@ -33,10 +33,10 @@ #include "upnpglobalvars.h" #include "utils.h" +#include "image_utils.h" #include "log.h" #include "sql.h" #include -#include #ifdef TIVO_SUPPORT #include "tivo_utils.h" #include "tivo_commands.h" @@ -723,7 +723,6 @@ static const char httpresphead[] = "Content-Length: %d\r\n" /*"Server: miniupnpd/1.0 UPnP/1.0\r\n"*/ // "Accept-Ranges: bytes\r\n" -// "DATE: Wed, 24 Sep 2008 05:57:19 GMT\r\n" //"Server: " MINIUPNPD_SERVER_STRING "\r\n" ; /*"\r\n";*/ /* @@ -1114,18 +1113,18 @@ SendResp_resizedimg(struct upnphttp * h, char * object) char **result; char date[30]; time_t curtime = time(NULL); - FILE *imgfile; int width=640, height=480, dstw, dsth, rotation, size; - char * data; + unsigned char * data; char *path, *file_path; char *resolution, *tn; char *key, *val; char *saveptr, *item = NULL; char *pixelshape = NULL; int rows=0, ret; - gdImagePtr imsrc = 0, imdst = 0; ExifData *ed; ExifLoader *l; + image * imsrc; + image * imdst; #if USE_FORK pid_t newpid = 0; newpid = fork(); @@ -1178,8 +1177,8 @@ SendResp_resizedimg(struct upnphttp * h, char * object) ret = sql_get_table(db, sql_buf, &result, &rows, NULL); if( (ret != SQLITE_OK) || !rows || (access(result[3], F_OK) != 0) ) { - free(path); DPRINTF(E_ERROR, L_HTTP, "Didn't find valid file for %s!\n", path); + free(path); goto resized_error; } file_path = result[3]; @@ -1204,20 +1203,12 @@ SendResp_resizedimg(struct upnphttp * h, char * object) sqlite3_free_table(result); goto resized_error; } - imsrc = gdImageCreateFromJpegPtr(ed->size, ed->data); + imsrc = image_new_from_jpeg(NULL, 0, (char *)ed->data, ed->size); exif_data_unref(ed); } else { - imgfile = fopen(file_path, "r"); - if( !imgfile ) - { - Send404(h); - sqlite3_free_table(result); - goto resized_error; - } - imsrc = gdImageCreateFromJpeg(imgfile); - fclose(imgfile); + imsrc = image_new_from_jpeg(file_path, 1, NULL, 0); } if( !imsrc ) { @@ -1227,23 +1218,15 @@ SendResp_resizedimg(struct upnphttp * h, char * object) } /* Figure out the best destination resolution we can use */ dstw = width; - dsth = ((((width<<10)/imsrc->sx)*imsrc->sy)>>10); + dsth = ((((width<<10)/imsrc->width)*imsrc->height)>>10); if( dsth > height ) { dsth = height; - dstw = (((height<<10)/imsrc->sy) * imsrc->sx>>10); + dstw = (((height<<10)/imsrc->height) * imsrc->width>>10); } - imdst = gdImageCreateTrueColor(dstw, dsth); - #if 0 // Use box filter resizer - #ifdef __sparc__ - gdImageCopyResized(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, imsrc->sx, imsrc->sy); - #else - gdImageCopyResampled(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, imsrc->sx, imsrc->sy); - #endif - #else - boxfilter_resize(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, imsrc->sx, imsrc->sy); - #endif - data = (char *)gdImageJpegPtr(imdst, &size, 99); + imdst = image_resize(imsrc, dstw, dsth); + data = image_save_to_jpeg_buf(imdst, &size); + DPRINTF(E_INFO, L_HTTP, "size: %d\n", size); strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime)); snprintf(header, sizeof(header)-50, "%s 200 OK\r\n" @@ -1268,12 +1251,11 @@ SendResp_resizedimg(struct upnphttp * h, char * object) if( (send_data(h, header, strlen(header)) == 0) && (h->req_command != EHead) ) { - send_data(h, data, size); + send_data(h, (char *)data, size); } - gdFree(data); - gdImageDestroy(imsrc); - gdImageDestroy(imdst); DPRINTF(E_INFO, L_HTTP, "Done serving %s\n", file_path); + image_free(imsrc); + image_free(imdst); sqlite3_free_table(result); resized_error: #if USE_FORK diff --git a/upnpsoap.c b/upnpsoap.c index 724b8ed..0962ddb 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -1,6 +1,6 @@ /* MiniDLNA project * http://minidlna.sourceforge.net/ - * (c) 2008 Justin Maggard + * (c) 2008-2009 Justin Maggard * * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution diff --git a/utils.c b/utils.c index 0fafe2a..f190530 100644 --- a/utils.c +++ b/utils.c @@ -1,5 +1,5 @@ /* MiniDLNA media server - * Copyright (C) 2008 Justin Maggard + * Copyright (C) 2008-2009 Justin Maggard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +25,6 @@ #include #include #include -#include int ends_with(const char * haystack, const char * needle) @@ -148,128 +147,3 @@ make_dir(char * path, mode_t mode) printf("make_dir: cannot create directory '%s'", path); return -1; } - -/* Use our own boxfilter resizer, because gdCopyImageResampled is slow, - * and gdCopyImageResized looks horrible when you downscale much. */ -#define N_FRAC 8 -#define MASK_FRAC ((1 << N_FRAC) - 1) -#define ROUND2(v) (((v) + (1 << (N_FRAC - 1))) >> N_FRAC) -#define DIV(x, y) ( ((x) << (N_FRAC - 3)) / ((y) >> 3) ) -void -boxfilter_resize(gdImagePtr dst, gdImagePtr src, - int dstX, int dstY, int srcX, int srcY, - int dstW, int dstH, int srcW, int srcH) -{ - int x, y; - int sy1, sy2, sx1, sx2; - - if(!dst->trueColor) - { - gdImageCopyResized(dst, src, dstX, dstY, srcX, srcY, dstW, dstH, - srcW, srcH); - return; - } - for(y = dstY; y < (dstY + dstH); y++) - { - sy1 = (((y - dstY) * srcH) << N_FRAC) / dstH; - sy2 = (((y - dstY + 1) * srcH) << N_FRAC) / dstH; - for(x = dstX; x < (dstX + dstW); x++) - { - int sx, sy; - int spixels = 0; - int red = 0, green = 0, blue = 0, alpha = 0; - sx1 = (((x - dstX) * srcW) << N_FRAC) / dstW; - sx2 = (((x - dstX + 1) * srcW) << N_FRAC) / dstW; - sy = sy1; - do { - int yportion; - if((sy >> N_FRAC) == (sy1 >> N_FRAC)) - { - yportion = (1 << N_FRAC) - (sy & MASK_FRAC); - if(yportion > sy2 - sy1) - { - yportion = sy2 - sy1; - } - sy = sy & ~MASK_FRAC; - } - else if(sy == (sy2 & ~MASK_FRAC)) - { - yportion = sy2 & MASK_FRAC; - } - else - { - yportion = (1 << N_FRAC); - } - sx = sx1; - do { - int xportion; - int pcontribution; - int p; - if((sx >> N_FRAC) == (sx1 >> N_FRAC)) - { - xportion = (1 << N_FRAC) - (sx & MASK_FRAC); - if(xportion > sx2 - sx1) - { - xportion = sx2 - sx1; - } - sx = sx & ~MASK_FRAC; - } - else if(sx == (sx2 & ~MASK_FRAC)) - { - xportion = sx2 & MASK_FRAC; - } - else - { - xportion = (1 << N_FRAC); - } - - if(xportion && yportion) - { - pcontribution = (xportion * yportion) >> N_FRAC; - p = gdImageGetTrueColorPixel(src, ROUND2(sx) + srcX, ROUND2(sy) + srcY); - if(pcontribution == (1 << N_FRAC)) - { - // optimization for down-scaler, which many pixel has pcontribution=1 - red += gdTrueColorGetRed(p) << N_FRAC; - green += gdTrueColorGetGreen(p) << N_FRAC; - blue += gdTrueColorGetBlue(p) << N_FRAC; - alpha += gdTrueColorGetAlpha(p) << N_FRAC; - spixels += (1 << N_FRAC); - } - else - { - red += gdTrueColorGetRed(p) * pcontribution; - green += gdTrueColorGetGreen(p) * pcontribution; - blue += gdTrueColorGetBlue(p) * pcontribution; - alpha += gdTrueColorGetAlpha(p) * pcontribution; - spixels += pcontribution; - } - } - sx += (1 << N_FRAC); - } - while(sx < sx2); - sy += (1 << N_FRAC); - } - while(sy < sy2); - if(spixels != 0) - { - red = DIV(red, spixels); - green = DIV(green, spixels); - blue = DIV(blue, spixels); - alpha = DIV(alpha, spixels); - } - /* Clamping to allow for rounding errors above */ - if(red > (255 << N_FRAC)) - red = (255 << N_FRAC); - if(green > (255 << N_FRAC)) - green = (255 << N_FRAC); - if(blue > (255 << N_FRAC)) - blue = (255 << N_FRAC); - if(alpha > (gdAlphaMax << N_FRAC)) - alpha = (gdAlphaMax << N_FRAC); - gdImageSetPixel(dst, x, y, - gdTrueColorAlpha(ROUND2(red), ROUND2(green), ROUND2(blue), ROUND2(alpha))); - } - } -} - diff --git a/utils.h b/utils.h index 192a1d2..4467d4e 100644 --- a/utils.h +++ b/utils.h @@ -3,13 +3,12 @@ * Project : minidlna * Website : http://sourceforge.net/projects/minidlna/ * Author : Justin Maggard - * Copyright (c) 2008 Justin Maggard + * Copyright (c) 2008-2009 Justin Maggard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #ifndef __UTILS_H__ #define __UTILS_H__ -#include int ends_with(const char * haystack, const char * needle); @@ -26,9 +25,4 @@ strip_ext(char * name); int make_dir(char * path, mode_t mode); -/* A GD resize function with a good balance of quality and speed */ -void -boxfilter_resize(gdImagePtr dst, gdImagePtr src, - int dstX, int dstY, int srcX, int srcY, - int dstW, int dstH, int srcW, int srcH); #endif