├── .gitignore ├── AUTHORS ├── CMakeLists.txt ├── COPYING ├── COPYING-PLAIN ├── ChangeLog ├── Doxyfile ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── README.md ├── autogen.sh ├── configure.ac ├── debian ├── .gitignore ├── changelog.in ├── control ├── copyright ├── epeg0-bin.install ├── libepeg0-dev.install ├── libepeg0.install └── rules ├── epeg-uninstalled.pc.in ├── epeg.c.in ├── epeg.pc.in ├── epeg.spec.in ├── gendoc └── src ├── Makefile.am ├── bin ├── Makefile.am ├── epeg_main.c └── epeg_main.h └── lib ├── Epeg.h ├── Makefile.am ├── epeg_main.c └── epeg_private.h /.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | .libs 3 | epeg 4 | *.lo 5 | libepeg.la 6 | Makefile 7 | Makefile.in 8 | aclocal.m4 9 | autom4te.cache 10 | config.h 11 | config.h.in 12 | config.log 13 | config.status 14 | config.guess 15 | config.sub 16 | configure 17 | compile 18 | depcomp 19 | epeg-config 20 | epeg_docs.tar.gz 21 | install-sh 22 | libtool 23 | missing 24 | stamp-h1 25 | doc 26 | *.tar.gz 27 | ltmain.sh 28 | mkinstalldirs 29 | epeg.c 30 | epeg.pc 31 | epeg-uninstalled.pc 32 | epeg.spec 33 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The Rasterman (Carsten Haitzler) 2 | Jerome Foucher 3 | Michal Kowalczuk, Wirtualna Polska 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(libepeg) 4 | set (VERSION "0.9.2") 5 | 6 | option(BUILD_STATIC_LIB "Build static library" ON) 7 | option(BUILD_SHARED_LIB "Build shared library" ON) 8 | option(BUILD_PROGRAM "Build command line tool" OFF) 9 | 10 | # Build configuration 11 | # this project needs libjpeg and libexif. 12 | # in order to build the shared library, the static or shared libraries of libjpeg 13 | # and libexif must be found. 14 | # if they are not in a standard location, you can specify: 15 | # CMAKE_FIND_ROOT_PATH or JPEG_INCLUDE_DIRECTORY/EXIF_INCLUDE_DIRECTORY and 16 | # JPEG_LIB_DIRECTORY/EXIF_LIB_DIRECTORY 17 | ################################################################################ 18 | 19 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 20 | 21 | 22 | # Platform specific build configuration 23 | ################################################################################ 24 | 25 | if(WIN32) 26 | message(STATUS "Building for windows") 27 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 28 | endif() 29 | 30 | 31 | # Source files 32 | ################################################################################ 33 | 34 | 35 | file(GLOB_RECURSE libepeg_SRC src/lib/*.c) 36 | list(SORT libepeg_SRC) 37 | 38 | set(libepeg_HEADER src/lib/Epeg.h) 39 | 40 | file(GLOB_RECURSE epeg_SRC src/bin/*.c) 41 | list(SORT epeg_SRC) 42 | 43 | 44 | find_path(JPEG_DIR_HEADER NAME jerror.h HINTS "${JPEG_INCLUDE_DIRECTORY}") 45 | if (NOT JPEG_DIR_HEADER) 46 | message(FATAL_ERROR "Error: jerror.h not found, you must first install libjpeg or specify JPEG_INCLUDE_DIRECTORY!") 47 | endif() 48 | 49 | message(STATUS "Found jerror.h...") 50 | include_directories(BEFORE SYSTEM "${JPEG_DIR_HEADER}") 51 | 52 | 53 | find_path(EXIF_DIR_HEADER NAME libexif/exif-data.h HINTS "${EXIF_INCLUDE_DIRECTORY}") 54 | if (NOT EXIF_DIR_HEADER) 55 | message(FATAL_ERROR "Error: libexif/exif-data.h not found, you must first install libexif or specify EXIF_INCLUDE_DIRECTORY!") 56 | endif() 57 | 58 | message(STATUS "Found libexif/exif-data.h...") 59 | include_directories(BEFORE SYSTEM "${EXIF_DIR_HEADER}") 60 | 61 | 62 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 63 | add_compile_options(-fdata-sections -ffunction-sections) 64 | endif() 65 | 66 | # Build 67 | ################################################################################ 68 | 69 | # Build library 70 | if (BUILD_SHARED_LIB OR BUILD_PROGRAM) 71 | if(NOT DEFINED JPEG_LIB_DIRECTORY) 72 | set(JPEG_LIB_DIRECTORY ${JPEG_DIR_HEADER}/../lib) 73 | endif() 74 | find_library(JPEG_LIBRARY NAMES jpeg HINTS ${JPEG_LIB_DIRECTORY}) 75 | if (NOT JPEG_LIBRARY) 76 | message(FATAL_ERROR "Error: cant find jpeg library, you must first install libjpeg or specify JPEG_LIB_DIRECTORY!") 77 | endif() 78 | 79 | 80 | if(NOT DEFINED EXIF_LIB_DIRECTORY) 81 | set(EXIF_LIB_DIRECTORY ${EXIF_DIR_HEADER}/../lib) 82 | endif() 83 | find_library(EXIF_LIBRARY NAMES exif HINTS ${EXIF_LIB_DIRECTORY}) 84 | if (NOT EXIF_LIBRARY) 85 | message(FATAL_ERROR "Error: cant find exif library, you must first install libexif or specify EXIF_LIB_DIRECTORY!") 86 | endif() 87 | endif() 88 | 89 | if(BUILD_SHARED_LIB) 90 | message(STATUS "Building shared library") 91 | add_library(epeg_shared SHARED ${libepeg_SRC}) 92 | if(WIN32) 93 | target_compile_definitions(epeg_shared PUBLIC BUILDING_DLL) 94 | endif() 95 | target_link_libraries(epeg_shared ${JPEG_LIBRARY} ${EXIF_LIBRARY}) 96 | set_target_properties(epeg_shared PROPERTIES OUTPUT_NAME epeg) 97 | 98 | install(TARGETS epeg_shared DESTINATION lib) 99 | endif() 100 | 101 | if (BUILD_STATIC_LIB OR BUILD_PROGRAM) 102 | message(STATUS "Building static library") 103 | add_library(epeg_static STATIC ${libepeg_SRC}) 104 | set_target_properties(epeg_static PROPERTIES OUTPUT_NAME epeg) 105 | install(TARGETS epeg_static DESTINATION lib) 106 | endif() 107 | 108 | if (BUILD_PROGRAM) 109 | set(dll_lib m) 110 | add_executable(epeg_bin ${epeg_SRC}) 111 | message(STATUS "Building command line tool") 112 | target_link_libraries(epeg_bin epeg_static ${JPEG_LIBRARY} ${EXIF_LIBRARY}) 113 | target_link_libraries(epeg_bin -Wl,--gc-sections) 114 | target_link_libraries(epeg_bin -Wl,-Bdynamic ${dll_lib}) 115 | set_target_properties(epeg_bin PROPERTIES OUTPUT_NAME epeg) 116 | install(TARGETS epeg_bin DESTINATION bin) 117 | endif() 118 | 119 | if (NOT EXISTS src/lib/config.h) 120 | file(WRITE src/lib/config.h "") 121 | endif() 122 | 123 | 124 | install(FILES ${libepeg_HEADER} DESTINATION include) 125 | 126 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to 5 | deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies of the Software and its Copyright notices. In addition publicly 12 | documented acknowledgment must be given that this software has been used if no 13 | source code of this software is made available publicly. This includes 14 | acknowledgments in either Copyright notices, Manuals, Publicity and Marketing 15 | documents or any documentation provided with any product containing this 16 | software. This License does not apply to any software that links to the 17 | libraries provided by this software (statically or dynamically), but only to 18 | the software provided. 19 | 20 | Please see the COPYING.PLAIN for a plain-english explanation of this notice 21 | and it's intent. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 26 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 27 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 28 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | -------------------------------------------------------------------------------- /COPYING-PLAIN: -------------------------------------------------------------------------------- 1 | Plain English Copyright Notice 2 | 3 | This file is not intended to be the actual License. The reason this file 4 | exists is that we here are programmers and engineers. We aren't lawyers. We 5 | provide licenses that we THINK say the right things, but we have our own 6 | intentions at heart. This is a plain-english explanation of what those 7 | intentions are, and if you follow them you will be within the "spirit" of 8 | the license. 9 | 10 | The intent is for us to enjoy writing software that is useful to us (the 11 | AUTHORS) and allow others to use it freely and also benefit from the work we 12 | put into making it. We don't want to restrict others using it. They should 13 | not *HAVE* to make the source code of the applications they write that 14 | simply link to these libraries (be that statically or dynamically), or for 15 | them to be limited as to what license they choose to use (be it open, closed 16 | or anything else). But we would like to know you are using these libraries. 17 | We simply would like to know that it has been useful to someone. This is why 18 | we ask for acknowledgement of some sort. 19 | 20 | You can do what you want with the source of this software - it doesn't 21 | matter. We still have it here for ourselves and it is open and free to use 22 | and download and play with. It can't be taken away. We don't really mind what 23 | you do with the source to your software. We would simply like to know that 24 | you are using it - especially if it makes it to a commerical product. If you 25 | simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and 26 | then make sure you include a paragraph or page in the manual for the product 27 | with the copyright notice and state that you used this software, we will be 28 | very happy. If you want to contribute back modifications and fixes you may have 29 | made we will welcome those too with open arms (generally). If you want help 30 | with changes needed, ports needed or features to be added, arrangements can 31 | be easily made with some dialogue. 32 | 33 | Carsten Haitzler 34 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattes/epeg/17bbae0f0a0b777e5fb01e0d16891e07153a41eb/ChangeLog -------------------------------------------------------------------------------- /Doxyfile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = Epeg 2 | PROJECT_NUMBER = 3 | OUTPUT_DIRECTORY = doc 4 | INPUT = epeg.c 5 | IMAGE_PATH = doc/img 6 | OUTPUT_LANGUAGE = English 7 | GENERATE_HTML = YES 8 | HTML_OUTPUT = html 9 | HTML_FILE_EXTENSION = .html 10 | HTML_HEADER = doc/head.html 11 | HTML_FOOTER = doc/foot.html 12 | HTML_STYLESHEET = doc/e.css 13 | HTML_ALIGN_MEMBERS = YES 14 | ENUM_VALUES_PER_LINE = 1 15 | GENERATE_HTMLHELP = NO 16 | CHM_FILE = 17 | HHC_LOCATION = 18 | GENERATE_CHI = NO 19 | BINARY_TOC = NO 20 | TOC_EXPAND = NO 21 | DISABLE_INDEX = YES 22 | EXTRACT_ALL = NO 23 | EXTRACT_PRIVATE = NO 24 | EXTRACT_STATIC = NO 25 | EXTRACT_LOCAL_CLASSES = NO 26 | HIDE_UNDOC_MEMBERS = YES 27 | HIDE_UNDOC_CLASSES = YES 28 | HIDE_FRIEND_COMPOUNDS = YES 29 | BRIEF_MEMBER_DESC = YES 30 | REPEAT_BRIEF = YES 31 | ALWAYS_DETAILED_SEC = NO 32 | INLINE_INHERITED_MEMB = NO 33 | FULL_PATH_NAMES = NO 34 | STRIP_FROM_PATH = 35 | INTERNAL_DOCS = NO 36 | STRIP_CODE_COMMENTS = YES 37 | CASE_SENSE_NAMES = YES 38 | SHORT_NAMES = NO 39 | HIDE_SCOPE_NAMES = NO 40 | VERBATIM_HEADERS = NO 41 | SHOW_INCLUDE_FILES = NO 42 | JAVADOC_AUTOBRIEF = YES 43 | MULTILINE_CPP_IS_BRIEF = NO 44 | DETAILS_AT_TOP = NO 45 | INHERIT_DOCS = YES 46 | INLINE_INFO = YES 47 | SORT_MEMBER_DOCS = YES 48 | DISTRIBUTE_GROUP_DOC = NO 49 | TAB_SIZE = 2 50 | GENERATE_TODOLIST = YES 51 | GENERATE_TESTLIST = YES 52 | GENERATE_BUGLIST = YES 53 | GENERATE_DEPRECATEDLIST= YES 54 | ALIASES = 55 | ENABLED_SECTIONS = 56 | MAX_INITIALIZER_LINES = 30 57 | OPTIMIZE_OUTPUT_FOR_C = YES 58 | OPTIMIZE_OUTPUT_JAVA = NO 59 | SHOW_USED_FILES = NO 60 | QUIET = NO 61 | WARNINGS = YES 62 | WARN_IF_UNDOCUMENTED = YES 63 | WARN_FORMAT = "$file:$line: $text" 64 | WARN_LOGFILE = 65 | FILE_PATTERNS = 66 | RECURSIVE = NO 67 | EXCLUDE = 68 | EXCLUDE_SYMLINKS = NO 69 | EXCLUDE_PATTERNS = 70 | EXAMPLE_PATH = 71 | EXAMPLE_PATTERNS = 72 | EXAMPLE_RECURSIVE = NO 73 | INPUT_FILTER = 74 | FILTER_SOURCE_FILES = NO 75 | SOURCE_BROWSER = NO 76 | INLINE_SOURCES = NO 77 | REFERENCED_BY_RELATION = YES 78 | REFERENCES_RELATION = YES 79 | ALPHABETICAL_INDEX = YES 80 | COLS_IN_ALPHA_INDEX = 2 81 | IGNORE_PREFIX = 82 | GENERATE_TREEVIEW = NO 83 | TREEVIEW_WIDTH = 250 84 | GENERATE_LATEX = YES 85 | LATEX_OUTPUT = latex 86 | LATEX_CMD_NAME = latex 87 | MAKEINDEX_CMD_NAME = makeindex 88 | COMPACT_LATEX = NO 89 | PAPER_TYPE = a4wide 90 | EXTRA_PACKAGES = 91 | LATEX_HEADER = 92 | PDF_HYPERLINKS = YES 93 | USE_PDFLATEX = NO 94 | LATEX_BATCHMODE = NO 95 | GENERATE_RTF = NO 96 | RTF_OUTPUT = rtf 97 | COMPACT_RTF = NO 98 | RTF_HYPERLINKS = NO 99 | RTF_STYLESHEET_FILE = 100 | RTF_EXTENSIONS_FILE = 101 | GENERATE_MAN = YES 102 | MAN_OUTPUT = man 103 | MAN_EXTENSION = .3 104 | MAN_LINKS = YES 105 | GENERATE_XML = NO 106 | XML_SCHEMA = 107 | XML_DTD = 108 | GENERATE_AUTOGEN_DEF = NO 109 | ENABLE_PREPROCESSING = YES 110 | MACRO_EXPANSION = NO 111 | EXPAND_ONLY_PREDEF = NO 112 | SEARCH_INCLUDES = NO 113 | INCLUDE_PATH = 114 | INCLUDE_FILE_PATTERNS = 115 | PREDEFINED = 116 | EXPAND_AS_DEFINED = 117 | SKIP_FUNCTION_MACROS = YES 118 | TAGFILES = 119 | GENERATE_TAGFILE = 120 | ALLEXTERNALS = NO 121 | EXTERNAL_GROUPS = YES 122 | PERL_PATH = /usr/bin/perl 123 | CLASS_DIAGRAMS = NO 124 | HIDE_UNDOC_RELATIONS = YES 125 | HAVE_DOT = NO 126 | CLASS_GRAPH = NO 127 | COLLABORATION_GRAPH = NO 128 | TEMPLATE_RELATIONS = NO 129 | INCLUDE_GRAPH = NO 130 | INCLUDED_BY_GRAPH = NO 131 | GRAPHICAL_HIERARCHY = NO 132 | DOT_IMAGE_FORMAT = png 133 | DOT_PATH = 134 | DOTFILE_DIRS = 135 | MAX_DOT_GRAPH_WIDTH = 512 136 | MAX_DOT_GRAPH_HEIGHT = 512 137 | GENERATE_LEGEND = YES 138 | DOT_CLEANUP = YES 139 | SEARCHENGINE = NO 140 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | COMPILING and INSTALLING: 2 | 3 | If you got a official release tar archive do: 4 | ./configure 5 | 6 | ( otherwise if you got this from enlightenment cvs do: ./autogen.sh ) 7 | 8 | Then to compile: 9 | make 10 | 11 | To install (run this as root, or the user who handles installs): 12 | make install 13 | 14 | NOTE: You MUST make install Epeg for it to run properly. 15 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | 3 | SUBDIRS = src 4 | 5 | MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ 6 | config.h.in config.sub configure install-sh \ 7 | ltconfig ltmain.sh missing mkinstalldirs \ 8 | stamp-h.in epeg.c depcomp \ 9 | epeg.spec debian/changelog 10 | 11 | EXTRA_DIST = README AUTHORS COPYING COPYING-PLAIN \ 12 | autogen.sh epeg.spec epeg.spec.in epeg.c.in gendoc \ 13 | Doxyfile \ 14 | debian/changelog \ 15 | debian/changelog.in \ 16 | debian/control \ 17 | debian/copyright \ 18 | debian/libepeg0-dev.install \ 19 | debian/epeg0-bin.install \ 20 | debian/libepeg0.install \ 21 | debian/rules 22 | 23 | pkgconfigdir = $(libdir)/pkgconfig 24 | pkgconfig_DATA = epeg.pc 25 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattes/epeg/17bbae0f0a0b777e5fb01e0d16891e07153a41eb/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Epeg 0.9.0 2 | 3 | What is Epeg? 4 | 5 | An IMMENSELY FAST JPEG thumbnailer library API. 6 | 7 | Why write this? It's a convenience library API to using libjpeg to load JPEG 8 | images destined to be turned into thumbnails of the original, saving 9 | information with these thumbnails, retreiving it and managing to load the image 10 | ready for scaling with the minimum of fuss and CPU overhead. 11 | 12 | This means it's insanely fast at loading large JPEG images and scaling them 13 | down to tiny thumbnails. It's speedup will be proportional to the size 14 | difference between the source image and the output thumbnail size as a 15 | count of their pixels. 16 | 17 | It makes use of libjpeg features of being able to load an image by only 18 | decoding the DCT coefficients needed to reconstruct an image of the size 19 | desired. This gives a massive speedup. If you do not try and access the pixels 20 | in a format other than YUV (or GRAY8 if the source is grascale) then it also 21 | avoids colorspace conversions as well. 22 | 23 | Please see the full documentation for Epeg for more details. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | epeg 2 | ==== 3 | 4 | An IMMENSELY FAST JPEG thumbnailer library API. 5 | 6 | Why write this? It's a convenience library API to using libjpeg to load JPEG 7 | images destined to be turned into thumbnails of the original, saving 8 | information with these thumbnails, retreiving it and managing to load the image 9 | ready for scaling with the minimum of fuss and CPU overhead. 10 | 11 | This means it's insanely fast at loading large JPEG images and scaling them 12 | down to tiny thumbnails. It's speedup will be proportional to the size 13 | difference between the source image and the output thumbnail size as a 14 | count of their pixels. 15 | 16 | It makes use of libjpeg features of being able to load an image by only 17 | decoding the DCT coefficients needed to reconstruct an image of the size 18 | desired. This gives a massive speedup. If you do not try and access the pixels 19 | in a format other than YUV (or GRAY8 if the source is grascale) then it also 20 | avoids colorspace conversions as well. 21 | 22 | Original Version 23 | ---------------- 24 | 25 | The epeg library was developed within the [Enlightenment](http://www.enlightenment.org) project. 26 | As of some unknown version the epeg library disappeared from the project or was merged into some other library. 27 | The last version of epeg I know of is epeg [v0.9.1.042](https://github.com/mattes/epeg/archive/v0.9.1.042.zip). 28 | 29 | **Please note that the latest master branch of this repository contains code updates and improvements.** 30 | 31 | Bindings 32 | -------- 33 | * Python, https://github.com/jbaiter/epeg-cffi, https://pypi.python.org/pypi/epeg-cffi 34 | * Node.js, https://www.npmjs.org/package/epeg 35 | 36 | Blog posts 37 | ---------- 38 | 39 | * [blazing fast epeg photo resize on raspberry pi](https://web.archive.org/web/20160310234752/http://blog.sunekaae.com/2013/04/blazing-fast-epeg-photo-resize-on_3.html) by Sune Kaae 40 | 41 | 42 | 43 | License 44 | ------- 45 | Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) 46 | 47 | Permission is hereby granted, free of charge, to any person obtaining a copy 48 | of this software and associated documentation files (the "Software"), to 49 | deal in the Software without restriction, including without limitation the 50 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 51 | sell copies of the Software, and to permit persons to whom the Software is 52 | furnished to do so, subject to the following conditions: 53 | 54 | The above copyright notice and this permission notice shall be included in 55 | all copies of the Software and its Copyright notices. In addition publicly 56 | documented acknowledgment must be given that this software has been used if no 57 | source code of this software is made available publicly. This includes 58 | acknowledgments in either Copyright notices, Manuals, Publicity and Marketing 59 | documents or any documentation provided with any product containing this 60 | software. This License does not apply to any software that links to the 61 | libraries provided by this software (statically or dynamically), but only to 62 | the software provided. 63 | 64 | Please see the COPYING.PLAIN for a plain-english explanation of this notice 65 | and it's intent. 66 | 67 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 68 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 69 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 70 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 71 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 72 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 73 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf autom4te.cache 4 | rm -f aclocal.m4 ltmain.sh 5 | 6 | touch README 7 | 8 | echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS || exit 1 9 | echo "Running autoheader..." ; autoheader || exit 1 10 | echo "Running autoconf..." ; autoconf || exit 1 11 | echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1 12 | echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1 13 | 14 | if [ -z "$NOCONFIGURE" ]; then 15 | ./configure "$@" 16 | fi 17 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | 3 | # get rid of that stupid cache mechanism 4 | rm -f config.cache 5 | 6 | AC_INIT(epeg, 0.9.1.042, enlightenment-devel@lists.sourceforge.net) 7 | AC_PREREQ(2.52) 8 | AC_CONFIG_SRCDIR(configure.ac) 9 | 10 | AM_INIT_AUTOMAKE(1.6 dist-bzip2) 11 | AM_CONFIG_HEADER(config.h) 12 | 13 | AC_ISC_POSIX 14 | AC_PROG_CC 15 | AM_PROG_CC_STDC 16 | AC_HEADER_STDC 17 | AC_C_CONST 18 | 19 | AC_LIBTOOL_WIN32_DLL 20 | define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl 21 | define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl 22 | AC_PROG_LIBTOOL 23 | 24 | VMAJ=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $1);}'` 25 | VMIN=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $2);}'` 26 | VMIC=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $3);}'` 27 | SNAP=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $4);}'` 28 | version_info=`expr $VMAJ + $VMIN`":$VMIC:$VMIN" 29 | AC_SUBST(version_info) 30 | 31 | dnl AC_CHECK_FUNCS(fmemopen) 32 | dnl AC_CHECK_FUNCS(open_memstream) 33 | 34 | AC_CHECK_LIB([m], [log], [], [echo "invalid libm. log not found"]) 35 | AC_CHECK_LIB([jpeg], [jpeg_simple_progression], [], [echo "libjpeg library not found. Please install it before proceeding"; exit -1]) 36 | AC_CHECK_LIB([exif], [exif_data_new_from_file], [], [echo "libexif library not found. Please install it before proceeding"; exit -1], [-lm]) 37 | 38 | AC_OUTPUT([ 39 | Makefile 40 | epeg.pc 41 | epeg-uninstalled.pc 42 | epeg.spec 43 | src/Makefile 44 | src/lib/Makefile 45 | src/bin/Makefile 46 | debian/changelog 47 | ]) 48 | 49 | 50 | ##################################################################### 51 | ## Info 52 | 53 | echo 54 | echo 55 | echo 56 | echo "------------------------------------------------------------------------" 57 | echo "$PACKAGE $VERSION" 58 | echo "------------------------------------------------------------------------" 59 | echo 60 | echo "Configuration Options Summary:" 61 | echo 62 | echo " Compilation..........: make" 63 | echo 64 | echo " Installation.........: make install" 65 | echo 66 | echo " prefix.............: $prefix" 67 | echo 68 | -------------------------------------------------------------------------------- /debian/.gitignore: -------------------------------------------------------------------------------- 1 | changelog 2 | -------------------------------------------------------------------------------- /debian/changelog.in: -------------------------------------------------------------------------------- 1 | epeg (@VERSION@-1) unstable; urgency=low 2 | 3 | * Initial CVS release 4 | 5 | -- E17 Debian Team Sun, 02 Apr 2006 16:13:04 +0900 6 | 7 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: epeg 2 | Section: libs 3 | Priority: optional 4 | Maintainer: E17 Debian Team 5 | Build-Depends: cdbs, debhelper (>= 5), libjpeg62-dev 6 | Standards-Version: 3.7.2 7 | 8 | Package: libepeg0-dev 9 | Section: libdevel 10 | Architecture: any 11 | Depends: libepeg0 (= ${Source-Version}), libjpeg62-dev 12 | Provides: libepeg-dev 13 | Description: Enlightenment jpeg thumbnailer library development files 14 | This package contains headers and static libraries for development with 15 | libepeg. 16 | 17 | Package: libepeg0 18 | Section: libs 19 | Architecture: any 20 | Suggests: epeg-bin 21 | Depends: ${shlibs:Depends} 22 | Provides: libepeg 23 | Description: Enlightenment jpeg thumbnailer library API 24 | It's a convenience library API to using libjpeg to load JPEG images 25 | destined to be turned into thumbnails of the original, saving 26 | information with these thumbnails, retreiving it and managing to load 27 | the image ready for scaling with the minimum of fuss and CPU overhead. 28 | 29 | Package: epeg0-bin 30 | Section: libs 31 | Architecture: any 32 | Depends: ${shlibs:Depends} 33 | Provides: epeg-bin 34 | Description: Enlightenment jpeg thumbnailer programs 35 | It's a convenience library API to using libjpeg to load JPEG images 36 | destined to be turned into thumbnails of the original, saving 37 | information with these thumbnails, retreiving it and managing to load 38 | the image ready for scaling with the minimum of fuss and CPU overhead. 39 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Sytse Wielinga on 2 | Thu, 4 Mar 2004 22:07:34 +0100. 3 | 4 | The source is downloaded from the e17/libs/epeg module of the enlightenment CVS 5 | tree. For more information, see: 6 | 7 | http://www.enlightenment.org/cvs.html 8 | 9 | Upstream Authors: Enlightenment team 10 | 11 | Copyright: 12 | 13 | Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to 17 | deal in the Software without restriction, including without limitation the 18 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 19 | sell copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in 23 | all copies of the Software and its Copyright notices. In addition publicly 24 | documented acknowledgment must be given that this software has been used if no 25 | source code of this software is made available publicly. This includes 26 | acknowledgments in either Copyright notices, Manuals, Publicity and Marketing 27 | documents or any documentation provided with any product containing this 28 | software. This License does not apply to any software that links to the 29 | libraries provided by this software (statically or dynamically), but only to 30 | the software provided. 31 | 32 | Please see the COPYING.PLAIN for a plain-english explanation of this notice 33 | and it's intent. 34 | 35 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 36 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 37 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 38 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 39 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 40 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 41 | -------------------------------------------------------------------------------- /debian/epeg0-bin.install: -------------------------------------------------------------------------------- 1 | debian/tmp/usr/bin/epeg 2 | -------------------------------------------------------------------------------- /debian/libepeg0-dev.install: -------------------------------------------------------------------------------- 1 | debian/tmp/usr/lib/pkgconfig/* 2 | debian/tmp/usr/include/* 3 | debian/tmp/usr/lib/lib*.a 4 | debian/tmp/usr/lib/lib*.so 5 | debian/tmp/usr/lib/lib*.la 6 | -------------------------------------------------------------------------------- /debian/libepeg0.install: -------------------------------------------------------------------------------- 1 | debian/tmp/usr/lib/lib*.so.* 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | include /usr/share/cdbs/1/rules/debhelper.mk 4 | include /usr/share/cdbs/1/class/autotools.mk 5 | 6 | clean:: 7 | ./autogen.sh --prefix=/usr 8 | -------------------------------------------------------------------------------- /epeg-uninstalled.pc.in: -------------------------------------------------------------------------------- 1 | prefix= 2 | exec_prefix= 3 | libdir=${pcfiledir}/src/lib/.libs 4 | includedir=${pcfiledir}/src/lib 5 | 6 | Name: epeg 7 | Description: Epeg JPEG thumbnailer library (not installed) 8 | Version: @VERSION@ 9 | Libs: ${libdir}/libepeg.a -ljpeg 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /epeg.c.in: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @brief Epeg JPEG Thumbnailer library 4 | 5 | These routines are used for the Epeg library. 6 | */ 7 | 8 | /** 9 | 10 | @mainpage Epeg Library Documentation 11 | @image html epeg.png 12 | @version 0.9.0 13 | @author Carsten Haitzler 14 | @date 2000-2003 15 | 16 | @section intro What is Epeg? 17 | 18 | An IMMENSELY FAST JPEG thumbnailer library API. 19 | 20 | Why write this? It's a convenience library API to using libjpeg to load JPEG 21 | images destined to be turned into thumbnails of the original, saving 22 | information with these thumbnails, retreiving it and managing to load the image 23 | ready for scaling with the minimum of fuss and CPU overhead. 24 | 25 | This means it's insanely fast at loading large JPEG images and scaling them 26 | down to tiny thumbnails. It's speedup will be proportional to the size 27 | difference between the source image and the output thumbnail size as a 28 | count of their pixels. 29 | 30 | It makes use of libjpeg features of being able to load an image by only 31 | decoding the DCT coefficients needed to reconstruct an image of the size 32 | desired. This gives a massive speedup. If you do not try and access the pixels 33 | in a format other than YUV (or GRAY8 if the source is grascale) then it also 34 | avoids colorspace conversions as well. 35 | 36 | Using the library is very easy, look at this example: 37 | 38 | @code 39 | #include "Epeg.h" 40 | 41 | int 42 | main(int argc, char **argv) 43 | { 44 | Epeg_Image *im; 45 | 46 | if (argc != 3) 47 | { 48 | printf("Usage: %s input.jpg thumb.jpg\n", argv[0]); 49 | exit(0); 50 | } 51 | im = epeg_file_open(argv[1]); 52 | if (!im) 53 | { 54 | printf("Cannot open %s\n", argv[1]); 55 | exit(-1); 56 | } 57 | 58 | epeg_decode_size_set (im, 128, 96); 59 | epeg_quality_set (im, 75); 60 | epeg_thumbnail_comments_enable (im, 1); 61 | epeg_file_output_set (im, argv[2]); 62 | epeg_encode (im); 63 | epeg_close (im); 64 | 65 | return 0; 66 | } 67 | @endcode 68 | 69 | You can compile this program with as small a line as: 70 | 71 | @verbatim 72 | gcc epeg_test.c -o epeg_test `epeg-config --cflags --libs` 73 | @endverbatim 74 | 75 | It is a very simple library that just makes life easier when tyring to 76 | generate lots of thumbnails for large JPEG images as quickly as possible. 77 | Your milage may vary, but it should save you lots of time and effort in using 78 | libjpeg in general. 79 | 80 | @todo Check all input parameters for sanity. 81 | @todo Actually report error conditions properly. 82 | 83 | */ 84 | -------------------------------------------------------------------------------- /epeg.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: epeg 7 | Description: Epeg JPEG thumbnailer library 8 | Version: @VERSION@ 9 | Libs: -L${libdir} -lepeg -ljpeg 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /epeg.spec.in: -------------------------------------------------------------------------------- 1 | %define _missing_doc_files_terminate_build 0 2 | 3 | Summary: JPEG Scaling Library 4 | Name: @PACKAGE@ 5 | Version: @VERSION@ 6 | Release: 0.%(date '+%Y%m%d') 7 | License: BSD 8 | Group: System Environment/Libraries 9 | URL: http://www.enlightenment.org/ 10 | Source: ftp://ftp.enlightenment.org/pub/epeg/%{name}-%{version}.tar.gz 11 | Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings } 12 | Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)} 13 | Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}} 14 | #BuildSuggests: xorg-x11-devel 15 | BuildRequires: libjpeg-devel XFree86-devel 16 | BuildRoot: %{_tmppath}/%{name}-%{version}-root 17 | 18 | %description 19 | Epeg is a library which provides facilities for scaling JPEG images 20 | very quickly. 21 | 22 | %package devel 23 | Summary: Epeg headers, static libraries, documentation and test programs 24 | Group: System Environment/Libraries 25 | Requires: %{name} = %{version} 26 | Requires: libjpeg-devel XFree86-devel 27 | 28 | %description devel 29 | Headers, static libraries, test programs and documentation for Eet 30 | 31 | %prep 32 | %setup -q 33 | 34 | %build 35 | %{configure} --prefix=%{_prefix} 36 | %{__make} %{?_smp_mflags} %{?mflags} 37 | 38 | %install 39 | %{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install 40 | test -x `which doxygen` && sh gendoc || : 41 | 42 | %clean 43 | test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT 44 | 45 | %post 46 | /sbin/ldconfig 47 | 48 | %postun 49 | /sbin/ldconfig 50 | 51 | %files 52 | %defattr(-, root, root) 53 | %doc AUTHORS COPYING README 54 | %{_libdir}/libepeg.so* 55 | %{_libdir}/libepeg.la 56 | 57 | %files devel 58 | %defattr(-, root, root) 59 | %doc doc/html 60 | %{_libdir}/libepeg.a 61 | %{_bindir}/epeg* 62 | %{_includedir}/Epeg* 63 | %{_libdir}/pkgconfig/* 64 | %changelog 65 | -------------------------------------------------------------------------------- /gendoc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cp ./epeg.c.in ./epeg.c 3 | #for I in `find ./src/lib -name "Epeg.h" -print`; do 4 | # cat $I >> ./epeg.c 5 | #done 6 | for I in `find ./src/lib -name "*.c" -print`; do 7 | cat $I >> ./epeg.c 8 | done 9 | rm -rf ./doc/html ./doc/latex ./doc/man 10 | doxygen 11 | cp doc/img/*.png doc/html/ 12 | cp doc/img/*.gif doc/html/ 13 | exit 0 14 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | MAINTAINERCLEANFILES = Makefile.in 3 | 4 | SUBDIRS = lib bin 5 | -------------------------------------------------------------------------------- /src/bin/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | MAINTAINERCLEANFILES = Makefile.in 3 | 4 | AM_CPPFLAGS = \ 5 | -I../lib \ 6 | -I$(top_srcdir)/src/lib 7 | 8 | bin_PROGRAMS = epeg 9 | 10 | epeg_SOURCES = \ 11 | epeg_main.c \ 12 | epeg_main.h 13 | 14 | epeg_LDADD = \ 15 | $(top_builddir)/src/lib/libepeg.la 16 | 17 | epeg_DEPENDENCIES = $(top_builddir)/src/lib/libepeg.la 18 | -------------------------------------------------------------------------------- /src/bin/epeg_main.c: -------------------------------------------------------------------------------- 1 | #include "epeg_main.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define MAX(x, y) (((x) > (y)) ? (x) : (y)) 8 | 9 | static int verbose_flag = 0; 10 | static int thumb_width = 0; // < 0 means % of input 11 | static int thumb_height = 0; // < 0 means % of input 12 | static int preserve_flag = 0; // preserve aspect 13 | static int max_dimension = 0; // > 0 means we reduce max(w,h) to max_dimension, with aspect preserved 14 | static int inset_flag = 0; // Ensure specified dimensions will be covered 15 | static int thumb_quality = 85; // Quality value from 1 to 100 16 | static char *thumb_comment = NULL; 17 | static struct option long_options[] = 18 | { 19 | {"verbose", no_argument, 0, 'v'}, 20 | {"width", required_argument, 0, 'w'}, 21 | {"height", required_argument, 0, 'h'}, 22 | {"preserve",no_argument, 0, 'p'}, 23 | {"max", required_argument, 0, 'm'}, 24 | {"inset", no_argument, 0, 'i'}, 25 | {"quality", required_argument, 0, 'q'}, 26 | {"comment", required_argument, 0, 'c'}, 27 | {0, 0, 0, 0} 28 | }; 29 | 30 | void 31 | usage(const char *myname) 32 | { 33 | printf("Usage: %s [options] input.jpg thumb.jpg\n" 34 | " -v, --verbose\n" 35 | " -w, --width=[%%] set thumbnail width [%% of input]\n" 36 | " -h, --height=[%%] set thumbnail height [%% of input]\n" 37 | " -p, --preserve preserve aspect if only one of width and height given\n" 38 | " -m, --max= reduce max(w,h) to maximum, with aspect preserved\n" 39 | " -i, --inset cover at least the specified size (no upscaling or cropping)\n" 40 | " -c, --comment= put a comment in thumbnail\n" 41 | " -q, --quality= set thumbnail quality (1-100)\n", myname); 42 | exit(0); 43 | } 44 | 45 | int 46 | main(int argc, char **argv) 47 | { 48 | Epeg_Image *im; 49 | int c; 50 | int option_index = 0; 51 | char *input_file = NULL, *output_file = NULL; 52 | char *p; 53 | 54 | while ((c = getopt_long(argc, argv, "w:h:vipc:m:q:", long_options, &option_index)) != -1) { 55 | switch (c) { 56 | case 0: 57 | usage(argv[0]); 58 | break; 59 | case 'v': 60 | verbose_flag = 1; 61 | break; 62 | case 'w': 63 | thumb_width = strtol(optarg, NULL, 10); 64 | if (thumb_width == 0) { 65 | fprintf(stderr, "setting thumb_width to a default minimum of 64\n"); 66 | thumb_width = 64; 67 | } else { 68 | // If optarg="NUMBER%" store -NUMBER (see below) 69 | if ((p = strstr(optarg, "%"))) thumb_width = -thumb_width; 70 | } 71 | if (verbose_flag) printf("thumb_width = %d\n", thumb_width); 72 | break; 73 | case 'h': 74 | thumb_height = strtol(optarg, NULL, 10); 75 | if (thumb_height == 0) { 76 | fprintf(stderr, "setting thumb_height to a default minimum of 64\n"); 77 | thumb_height = 64; 78 | } else { 79 | // If optarg="NUMBER%" store -NUMBER (see below) 80 | if ((p = strstr(optarg, "%"))) thumb_height = -thumb_height; 81 | } 82 | if (verbose_flag) printf("thumb_height = %d\n", thumb_height); 83 | break; 84 | case 'p': 85 | preserve_flag = 1; 86 | break; 87 | case 'm': 88 | max_dimension = strtol(optarg, NULL, 10); 89 | if (verbose_flag) printf("max_dimension = %d\n", max_dimension); 90 | break; 91 | case 'q': 92 | thumb_quality = strtol(optarg, NULL, 10); 93 | if (thumb_quality < 1 || thumb_quality > 100) { 94 | fprintf(stderr, "setting thumb_quality to default of 85\n"); 95 | thumb_quality = 85; 96 | } 97 | if (verbose_flag) printf("thumb_quality = %d\n", thumb_quality); 98 | break; 99 | case 'i': 100 | inset_flag = 1; 101 | break; 102 | case 'c': 103 | thumb_comment = strdup(optarg); 104 | if (verbose_flag) printf("thumb_comment = %s\n", thumb_comment); 105 | break; 106 | case '?': 107 | usage(argv[0]); 108 | break; 109 | default: 110 | abort(); 111 | } 112 | } 113 | 114 | if (optind < argc) { 115 | if (optind < (argc-1)) { 116 | input_file = argv[optind++]; 117 | if (verbose_flag) printf("input_file = %s\n", input_file); 118 | output_file = argv[optind]; 119 | if (verbose_flag) printf("output_file = %s\n", output_file); 120 | } else { 121 | usage(argv[0]); 122 | } 123 | } 124 | 125 | if (!input_file || !output_file) usage(argv[0]); 126 | 127 | if (!thumb_comment) thumb_comment = ""; 128 | 129 | im = epeg_file_open(input_file); 130 | if (!im) { 131 | fprintf(stderr, "%s: cannot open %s\n", argv[0], input_file); 132 | exit(-1); 133 | } 134 | 135 | { 136 | const char *com; 137 | Epeg_Thumbnail_Info info; 138 | int w, h; 139 | 140 | com = epeg_comment_get(im); 141 | if (verbose_flag) if (com) printf("Comment: %s\n", com); 142 | epeg_thumbnail_comments_get(im, &info); 143 | if (info.mimetype) { 144 | if (verbose_flag) printf("Thumb Mimetype: %s\n", info.mimetype); 145 | if (verbose_flag) if (info.uri) printf("Thumb URI: %s\n", info.uri); 146 | if (verbose_flag) printf("Thumb Mtime: %llu\n", info.mtime); 147 | if (verbose_flag) printf("Thumb Width: %i\n", info.w); 148 | if (verbose_flag) printf("Thumb Height: %i\n", info.h); 149 | } 150 | epeg_size_get(im, &w, &h); 151 | if (verbose_flag) printf("Image size: %ix%i\n", w, h); 152 | 153 | if (thumb_width < 0) { 154 | // This means we want %thumb_width of w 155 | thumb_width = w * (-thumb_width) / 100; 156 | } 157 | if (thumb_height < 0) { 158 | // This means we want %thumb_height of h 159 | thumb_height = h * (-thumb_height) / 100; 160 | } 161 | 162 | if (max_dimension > 0) { 163 | if ((w > h) ^ inset_flag) { 164 | thumb_width = max_dimension; 165 | thumb_height = max_dimension * h / w; 166 | } else { 167 | thumb_height = max_dimension; 168 | thumb_width = max_dimension * w / h; 169 | } 170 | } else if (inset_flag) { 171 | thumb_width = MAX(thumb_width, thumb_height * w / h); 172 | thumb_height = MAX(thumb_height, thumb_width * h / w); 173 | } 174 | 175 | if (preserve_flag == 1) { 176 | if (thumb_width == 0) 177 | thumb_width = w * thumb_height / h; 178 | if (thumb_height == 0) 179 | thumb_height = h * thumb_width / w; 180 | } 181 | } 182 | 183 | if (verbose_flag) printf("Thumb size: %dx%d\n", thumb_width, thumb_height); 184 | epeg_decode_size_set(im, thumb_width, thumb_height); 185 | epeg_quality_set (im, thumb_quality); 186 | epeg_thumbnail_comments_enable (im, 1); 187 | epeg_comment_set (im, thumb_comment); 188 | epeg_file_output_set (im, output_file); 189 | epeg_encode (im); 190 | epeg_close (im); 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /src/bin/epeg_main.h: -------------------------------------------------------------------------------- 1 | #ifndef EPEG_H 2 | #define EPEG_H 3 | 4 | #include "Epeg.h" 5 | #include 6 | #include 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/lib/Epeg.h: -------------------------------------------------------------------------------- 1 | #ifndef _EPEG_H 2 | #define _EPEG_H 3 | 4 | #ifdef EAPI 5 | #undef EAPI 6 | #endif 7 | #ifdef WIN32 8 | # ifdef BUILDING_DLL 9 | # define EAPI __declspec(dllexport) 10 | # elif defined(USE_EPEG_DLL) 11 | # define EAPI __declspec(dllimport) 12 | # else 13 | # define EAPI 14 | # endif 15 | #else 16 | # ifdef __GNUC__ 17 | # if __GNUC__ >= 4 18 | # define EAPI __attribute__ ((visibility("default"))) 19 | # else 20 | # define EAPI 21 | # endif 22 | # else 23 | # define EAPI 24 | # endif 25 | #endif 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | typedef enum _Epeg_Colorspace 32 | { 33 | EPEG_GRAY8, 34 | EPEG_YUV8, 35 | EPEG_RGB8, 36 | EPEG_BGR8, 37 | EPEG_RGBA8, 38 | EPEG_BGRA8, 39 | EPEG_ARGB32, 40 | EPEG_CMYK 41 | } 42 | Epeg_Colorspace; 43 | 44 | typedef struct _Epeg_Image Epeg_Image; 45 | typedef struct _Epeg_Thumbnail_Info Epeg_Thumbnail_Info; 46 | 47 | struct _Epeg_Thumbnail_Info 48 | { 49 | char *uri; 50 | unsigned long long int mtime; 51 | int w, h; 52 | char *mimetype; 53 | }; 54 | 55 | EAPI Epeg_Image *epeg_file_open (const char *file); 56 | EAPI Epeg_Image *epeg_memory_open (unsigned char *data, int size); 57 | EAPI void epeg_size_get (Epeg_Image *im, int *w, int *h); 58 | EAPI void epeg_decode_size_set (Epeg_Image *im, int w, int h); 59 | EAPI void epeg_orientation_get (Epeg_Image *im, int *orientation); 60 | EAPI void epeg_orientation_set (Epeg_Image *im, int orientation); 61 | EAPI void epeg_colorspace_get (Epeg_Image *im, int *space); 62 | EAPI void epeg_decode_colorspace_set (Epeg_Image *im, Epeg_Colorspace colorspace); 63 | EAPI const void *epeg_pixels_get (Epeg_Image *im, int x, int y, int w, int h); 64 | EAPI void epeg_pixels_free (Epeg_Image *im, const void *data); 65 | EAPI const char *epeg_comment_get (Epeg_Image *im); 66 | EAPI void epeg_thumbnail_comments_get (Epeg_Image *im, Epeg_Thumbnail_Info *info); 67 | EAPI void epeg_comment_set (Epeg_Image *im, const char *comment); 68 | EAPI void epeg_quality_set (Epeg_Image *im, int quality); 69 | EAPI void epeg_thumbnail_comments_enable (Epeg_Image *im, int onoff); 70 | EAPI void epeg_file_output_set (Epeg_Image *im, const char *file); 71 | EAPI void epeg_memory_output_set (Epeg_Image *im, unsigned char **data, int *size); 72 | EAPI int epeg_encode (Epeg_Image *im); 73 | EAPI int epeg_trim (Epeg_Image *im); 74 | EAPI void epeg_close (Epeg_Image *im); 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/lib/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | MAINTAINERCLEANFILES = Makefile.in 3 | 4 | lib_LTLIBRARIES = libepeg.la 5 | include_HEADERS = Epeg.h 6 | libepeg_la_SOURCES = \ 7 | epeg_main.c \ 8 | epeg_private.h 9 | 10 | libepeg_la_DEPENDENCIES = $(top_builddir)/config.h 11 | libepeg_la_LDFLAGS = -version-info @version_info@ 12 | -------------------------------------------------------------------------------- /src/lib/epeg_main.c: -------------------------------------------------------------------------------- 1 | #include "Epeg.h" 2 | #include "epeg_private.h" 3 | #include 4 | 5 | static Epeg_Image *_epeg_open_header (Epeg_Image *im); 6 | static int _epeg_decode (Epeg_Image *im); 7 | static int _epeg_scale (Epeg_Image *im); 8 | static int _epeg_decode_for_trim (Epeg_Image *im); 9 | static int _epeg_trim (Epeg_Image *im); 10 | static int _epeg_encode (Epeg_Image *im); 11 | 12 | static void _epeg_fatal_error_handler (j_common_ptr cinfo); 13 | 14 | static const JOCTET fake_EOI[2] = { 0xFF, JPEG_EOI }; 15 | 16 | static ExifByteOrder exif_byte_order = EXIF_BYTE_ORDER_INTEL; 17 | 18 | /** 19 | * Open a JPEG image by filename. 20 | * @param file The file path to open. 21 | * @return A handle to the opened JPEG file, with the header decoded. 22 | * 23 | * This function opens the file indicated by the @p file parameter, and 24 | * attempts to decode it as a jpeg file. If this failes, NULL is returned. 25 | * Otherwise a valid handle to an open JPEG file is returned that can be used 26 | * by other Epeg calls. 27 | * 28 | * The @p file must be a pointer to a valid C string, NUL (0 byte) terminated 29 | * thats is a relative or absolute file path. If not results are not 30 | * determined. 31 | * 32 | * See also: epeg_memory_open(), epeg_close() 33 | */ 34 | EAPI Epeg_Image * 35 | epeg_file_open(const char *file) 36 | { 37 | Epeg_Image *im; 38 | 39 | im = calloc(1, sizeof(Epeg_Image)); 40 | if (!im) return NULL; 41 | 42 | im->in.file = strdup(file); 43 | if (!im->in.file) 44 | { 45 | free(im); 46 | return NULL; 47 | } 48 | 49 | im->in.f = fopen(im->in.file, "rb"); 50 | if (!im->in.f) 51 | { 52 | epeg_close(im); 53 | return NULL; 54 | } 55 | fstat(fileno(im->in.f), &(im->stat_info)); 56 | im->out.quality = 75; 57 | return _epeg_open_header(im); 58 | } 59 | 60 | /** 61 | * Open a JPEG image stored in memory. 62 | * @param data A pointer to the memory containing the JPEG data. 63 | * @param size The size of the memory segment containing the JPEG. 64 | * @return A handle to the opened JPEG, with the header decoded. 65 | * 66 | * This function opens a JPEG file that is stored in memory pointed to by 67 | * @p data, and that is @p size bytes in size. If successful a valid handle 68 | * is returned, or on failure NULL is returned. 69 | * 70 | * See also: epeg_file_open(), epeg_close() 71 | */ 72 | EAPI EAPI Epeg_Image * 73 | epeg_memory_open(unsigned char *data, int size) 74 | { 75 | Epeg_Image *im; 76 | 77 | im = calloc(1, sizeof(Epeg_Image)); 78 | if (!im) return NULL; 79 | 80 | im->out.quality = 75; 81 | im->in.mem.data = (unsigned char **)data; 82 | im->in.mem.size = size; 83 | im->in.f = NULL; 84 | im->in.w = 0; 85 | im->in.h = 0; 86 | return _epeg_open_header(im); 87 | } 88 | 89 | /** 90 | * Return the original JPEG pixel size. 91 | * @param im A handle to an opened Epeg image. 92 | * @param w A pointer to the width value in pixels to be filled in. 93 | * @param h A pointer to the height value in pixels to be filled in. 94 | * 95 | * Returns the image size in pixels. 96 | * 97 | */ 98 | EAPI void 99 | epeg_size_get(Epeg_Image *im, int *w, int *h) 100 | { 101 | if (w) *w = im->in.w; 102 | if (h) *h = im->in.h; 103 | } 104 | 105 | /** 106 | * Return the original JPEG orientation. 107 | * @param im A handle to an opened Epeg image. 108 | * @param orientation A pointer to the orientation value to be filled in. 109 | * 110 | * Returns the image orientation. 111 | * 112 | */ 113 | 114 | EAPI void 115 | epeg_orientation_get(Epeg_Image *im, int *orientation) 116 | { 117 | if (orientation) *orientation = im->in.orientation; 118 | } 119 | 120 | /** 121 | * Sets the image orientation. 122 | * @param im A handle to an opened Epeg image. 123 | * @param orientation The orientation value to set. 124 | * 125 | * 126 | */ 127 | 128 | EAPI void 129 | epeg_orientation_set(Epeg_Image *im, int orientation) 130 | { 131 | im->in.orientation = orientation; 132 | } 133 | 134 | /** 135 | * Return the original JPEG pixel color space. 136 | * @param im A handle to an opened Epeg image. 137 | * @param space A pointer to the color space value to be filled in. 138 | * 139 | * Returns the image color space. 140 | * 141 | */ 142 | EAPI void 143 | epeg_colorspace_get(Epeg_Image *im, int *space) 144 | { 145 | if (space) *space = im->color_space; 146 | } 147 | 148 | /** 149 | * Set the size of the image to decode in pixels. 150 | * @param im A handle to an opened Epeg image. 151 | * @param w The width of the image to decode at, in pixels. 152 | * @param h The height of the image to decode at, in pixels. 153 | * 154 | * Sets the size at which to deocode the JPEG image, giving an optimised load 155 | * that only decodes the pixels needed. 156 | * 157 | */ 158 | EAPI void 159 | epeg_decode_size_set(Epeg_Image *im, int w, int h) 160 | { 161 | if (im->pixels) return; 162 | if (w < 1) w = 1; 163 | else if (w > im->in.w) w = im->in.w; 164 | if (h < 1) h = 1; 165 | else if (h > im->in.h) h = im->in.h; 166 | im->out.w = w; 167 | im->out.h = h; 168 | im->out.x = 0; 169 | im->out.y = 0; 170 | } 171 | 172 | EAPI void 173 | epeg_decode_bounds_set(Epeg_Image *im, int x, int y, int w, int h) 174 | { 175 | if (im->pixels) return; 176 | if (w < 1) w = 1; 177 | else if (w > im->in.w) w = im->in.w; 178 | if (h < 1) h = 1; 179 | else if (h > im->in.h) h = im->in.h; 180 | im->out.w = w; 181 | im->out.h = h; 182 | if (x < 0) x = 0; 183 | if (y < 0) y = 0; 184 | im->out.x = x; 185 | im->out.y = y; 186 | } 187 | 188 | /** 189 | * Set the colorspace in which to decode the image. 190 | * @param im A handle to an opened Epeg image. 191 | * @param colorspace The colorspace to decode the image in. 192 | * 193 | * This sets the colorspace to decode the image in. The default is EPEG_YUV8, 194 | * as this is normally the native colorspace of a JPEG file, avoiding any 195 | * colorspace conversions for a faster load and/or save. 196 | */ 197 | EAPI void 198 | epeg_decode_colorspace_set(Epeg_Image *im, Epeg_Colorspace colorspace) 199 | { 200 | if (im->pixels) return; 201 | if ((colorspace < EPEG_GRAY8) || (colorspace > EPEG_CMYK)) return; 202 | im->color_space = colorspace; 203 | } 204 | 205 | /** 206 | * Get a segment of decoded pixels from an image. 207 | * @param im A handle to an opened Epeg image. 208 | * @param x Rectangle X. 209 | * @param y Rectangle Y. 210 | * @param w Rectangle width. 211 | * @param h Rectangle height. 212 | * @return Pointer to the top left of the requested pixel block. 213 | * 214 | * Return image pixels in the decoded format from the specified location 215 | * rectangle bounded with the box @p x, @p y @p w X @p y. The pixel block is 216 | * packed with no row padding, and it organsied from top-left to bottom right, 217 | * row by row. You must free the pixel block using epeg_pixels_free() before 218 | * you close the image handle, and assume the pixels to be read-only memory. 219 | * 220 | * On success the pointer is returned, on failure, NULL is returned. Failure 221 | * may be because the rectangle is out of the bounds of the image, memory 222 | * allocations failed or the image data cannot be decoded. 223 | * 224 | */ 225 | EAPI const void * 226 | epeg_pixels_get(Epeg_Image *im, int x, int y, int w, int h) 227 | { 228 | int xx, yy, ww, hh, bpp, ox, oy, ow, oh, iw, ih; 229 | 230 | if (!im->pixels) 231 | { 232 | if (_epeg_decode(im) != 0) return NULL; 233 | } 234 | 235 | if (!im->pixels) return NULL; 236 | if ((im->out.w < 1) || (im->out.h < 1)) return NULL; 237 | 238 | if (_epeg_scale(im) != 0) return NULL; 239 | 240 | bpp = im->in.jinfo.output_components; 241 | iw = im->out.w; 242 | ih = im->out.h; 243 | ow = w; 244 | oh = h; 245 | ox = 0; 246 | oy = 0; 247 | if ((x + ow) > iw) ow = iw - x; 248 | if ((y + oh) > ih) oh = ih - y; 249 | if (ow < 1) return NULL; 250 | if (oh < 1) return NULL; 251 | if (x < 0) 252 | { 253 | ow += x; 254 | ox = -x; 255 | } 256 | if (y < 0) 257 | { 258 | oh += y; 259 | oy = -y; 260 | } 261 | if (ow < 1) return NULL; 262 | if (oh < 1) return NULL; 263 | 264 | ww = x + ox + ow; 265 | hh = y + oy + oh; 266 | 267 | if (im->color_space == EPEG_GRAY8) 268 | { 269 | unsigned char *pix, *p; 270 | 271 | pix = malloc(w * h * 1); 272 | if (!pix) return NULL; 273 | for (yy = y + oy; yy < hh; yy++) 274 | { 275 | unsigned char *s; 276 | 277 | s = im->lines[yy] + ((x + ox) * bpp); 278 | p = pix + ((((yy - y) * w) + ox)); 279 | for (xx = x + ox; xx < ww; xx++) 280 | { 281 | p[0] = s[0]; 282 | p++; 283 | s += bpp; 284 | } 285 | } 286 | return pix; 287 | } 288 | else if (im->color_space == EPEG_YUV8) 289 | { 290 | unsigned char *pix, *p; 291 | 292 | pix = malloc(w * h * 3); 293 | if (!pix) return NULL; 294 | for (yy = y + oy; yy < hh; yy++) 295 | { 296 | unsigned char *s; 297 | 298 | s = im->lines[yy] + ((x + ox) * bpp); 299 | p = pix + ((((yy - y) * w) + ox) * 3); 300 | for (xx = x + ox; xx < ww; xx++) 301 | { 302 | p[0] = s[0]; 303 | p[1] = s[1]; 304 | p[2] = s[2]; 305 | p += 3; 306 | s += bpp; 307 | } 308 | } 309 | return pix; 310 | } 311 | else if (im->color_space == EPEG_RGB8) 312 | { 313 | unsigned char *pix, *p; 314 | 315 | pix = malloc(w * h * 3); 316 | if (!pix) return NULL; 317 | for (yy = y + oy; yy < hh; yy++) 318 | { 319 | unsigned char *s; 320 | 321 | s = im->lines[yy] + ((x + ox) * bpp); 322 | p = pix + ((((yy - y) * w) + ox) * 3); 323 | for (xx = x + ox; xx < ww; xx++) 324 | { 325 | p[0] = s[0]; 326 | p[1] = s[1]; 327 | p[2] = s[2]; 328 | p += 3; 329 | s += bpp; 330 | } 331 | } 332 | return pix; 333 | } 334 | else if (im->color_space == EPEG_BGR8) 335 | { 336 | unsigned char *pix, *p; 337 | 338 | pix = malloc(w * h * 3); 339 | if (!pix) return NULL; 340 | for (yy = y + oy; yy < hh; yy++) 341 | { 342 | unsigned char *s; 343 | 344 | s = im->lines[yy] + ((x + ox) * bpp); 345 | p = pix + ((((yy - y) * w) + ox) * 3); 346 | for (xx = x + ox; xx < ww; xx++) 347 | { 348 | p[0] = s[2]; 349 | p[1] = s[1]; 350 | p[2] = s[0]; 351 | p += 3; 352 | s += bpp; 353 | } 354 | } 355 | return pix; 356 | } 357 | else if (im->color_space == EPEG_RGBA8) 358 | { 359 | unsigned char *pix, *p; 360 | 361 | pix = malloc(w * h * 4); 362 | if (!pix) return NULL; 363 | for (yy = y + oy; yy < hh; yy++) 364 | { 365 | unsigned char *s; 366 | 367 | s = im->lines[yy] + ((x + ox) * bpp); 368 | p = pix + ((((yy - y) * w) + ox) * 4); 369 | for (xx = x + ox; xx < ww; xx++) 370 | { 371 | p[0] = s[0]; 372 | p[1] = s[1]; 373 | p[2] = s[2]; 374 | p[3] = 0xff; 375 | p += 4; 376 | s += bpp; 377 | } 378 | } 379 | return pix; 380 | } 381 | else if (im->color_space == EPEG_BGRA8) 382 | { 383 | unsigned char *pix, *p; 384 | 385 | pix = malloc(w * h * 4); 386 | if (!pix) return NULL; 387 | for (yy = y + oy; yy < hh; yy++) 388 | { 389 | unsigned char *s; 390 | 391 | s = im->lines[yy] + ((x + ox) * bpp); 392 | p = pix + ((((yy - y) * w) + ox) * 4); 393 | for (xx = x + ox; xx < ww; xx++) 394 | { 395 | p[0] = 0xff; 396 | p[1] = s[2]; 397 | p[2] = s[1]; 398 | p[3] = s[0]; 399 | p += 4; 400 | s += bpp; 401 | } 402 | } 403 | return pix; 404 | } 405 | else if (im->color_space == EPEG_ARGB32) 406 | { 407 | unsigned int *pix, *p; 408 | 409 | pix = malloc(w * h * 4); 410 | if (!pix) return NULL; 411 | for (yy = y + oy; yy < hh; yy++) 412 | { 413 | unsigned char *s; 414 | 415 | s = im->lines[yy] + ((x + ox) * bpp); 416 | p = pix + ((((yy - y) * w) + ox)); 417 | for (xx = x + ox; xx < ww; xx++) 418 | { 419 | p[0] = 0xff000000 | (s[0] << 16) | (s[1] << 8) | (s[2]); 420 | p++; 421 | s += bpp; 422 | } 423 | } 424 | return pix; 425 | } 426 | else if (im->color_space == EPEG_CMYK) 427 | { 428 | unsigned char *pix, *p; 429 | 430 | pix = malloc(w * h * 4); 431 | if (!pix) return NULL; 432 | for (yy = y + oy; yy < hh; yy++) 433 | { 434 | unsigned char *s; 435 | 436 | s = im->lines[yy] + ((x + ox) * bpp); 437 | p = pix + ((((yy - y) * w) + ox) * 4); 438 | for (xx = x + ox; xx < ww; xx++) 439 | { 440 | p[0] = s[0]; 441 | p[1] = s[1]; 442 | p[2] = s[2]; 443 | p[3] = 0xff; 444 | p += 4; 445 | s += bpp; 446 | } 447 | } 448 | return pix; 449 | } 450 | return NULL; 451 | } 452 | 453 | /** 454 | * Get a segment of decoded pixels from an image. 455 | * @param im A handle to an opened Epeg image. 456 | * @param x Rectangle X. 457 | * @param y Rectangle Y. 458 | * @param w Rectangle width. 459 | * @param h Rectangle height. 460 | * @return Pointer to the top left of the requested pixel block. 461 | * 462 | * Return image pixels in the decoded format from the specified location 463 | * rectangle bounded with the box @p x, @p y @p w X @p y. The pixel block is 464 | * packed with no row padding, and it organsied from top-left to bottom right, 465 | * row by row. You must free the pixel block using epeg_pixels_free() before 466 | * you close the image handle, and assume the pixels to be read-only memory. 467 | * 468 | * On success the pointer is returned, on failure, NULL is returned. Failure 469 | * may be because the rectangle is out of the bounds of the image, memory 470 | * allocations failed or the image data cannot be decoded. 471 | * 472 | */ 473 | EAPI const void * 474 | epeg_pixels_get_as_RGB8(Epeg_Image *im, int x, int y, int w, int h) 475 | { 476 | int xx, yy, ww, hh, bpp, ox, oy, ow, oh, iw, ih; 477 | 478 | if (!im->pixels) 479 | { 480 | if (_epeg_decode(im) != 0) return NULL; 481 | } 482 | 483 | if (!im->pixels) return NULL; 484 | if ((im->out.w < 1) || (im->out.h < 1)) return NULL; 485 | 486 | bpp = im->in.jinfo.output_components; 487 | iw = im->out.w; 488 | ih = im->out.h; 489 | ow = w; 490 | oh = h; 491 | ox = 0; 492 | oy = 0; 493 | if ((x + ow) > iw) ow = iw - x; 494 | if ((y + oh) > ih) oh = ih - y; 495 | if (ow < 1) return NULL; 496 | if (oh < 1) return NULL; 497 | if (x < 0) 498 | { 499 | ow += x; 500 | ox = -x; 501 | } 502 | if (y < 0) 503 | { 504 | oh += y; 505 | oy = -y; 506 | } 507 | if (ow < 1) return NULL; 508 | if (oh < 1) return NULL; 509 | 510 | ww = x + ox + ow; 511 | hh = y + oy + oh; 512 | 513 | if (im->color_space == EPEG_GRAY8) 514 | { 515 | unsigned char *pix, *p; 516 | 517 | pix = malloc(w * h * 3); 518 | if (!pix) return NULL; 519 | for (yy = y + oy; yy < hh; yy++) 520 | { 521 | unsigned char *s; 522 | 523 | s = im->lines[yy] + ((x + ox) * bpp); 524 | p = pix + ((((yy - y) * w) + ox) * 3); 525 | for (xx = x + ox; xx < ww; xx++) 526 | { 527 | p[0] = s[0]; 528 | p[1] = s[0]; 529 | p[2] = s[0]; 530 | p += 3; 531 | s += bpp; 532 | } 533 | } 534 | return pix; 535 | } 536 | if (im->color_space == EPEG_RGB8) 537 | { 538 | unsigned char *pix, *p; 539 | 540 | pix = malloc(w * h * 3); 541 | if (!pix) return NULL; 542 | for (yy = y + oy; yy < hh; yy++) 543 | { 544 | unsigned char *s; 545 | 546 | s = im->lines[yy] + ((x + ox) * bpp); 547 | p = pix + ((((yy - y) * w) + ox) * 3); 548 | for (xx = x + ox; xx < ww; xx++) 549 | { 550 | p[0] = s[0]; 551 | p[1] = s[1]; 552 | p[2] = s[2]; 553 | p += 3; 554 | s += bpp; 555 | } 556 | } 557 | return pix; 558 | } 559 | if (im->color_space == EPEG_CMYK) 560 | { 561 | unsigned char *pix, *p; 562 | 563 | pix = malloc(w * h * 3); 564 | if (!pix) return NULL; 565 | for (yy = y + oy; yy < hh; yy++) 566 | { 567 | unsigned char *s; 568 | 569 | s = im->lines[yy] + ((x + ox) * bpp); 570 | p = pix + ((((yy - y) * w) + ox) * 3); 571 | for (xx = x + ox; xx < ww; xx++) 572 | { 573 | p[0] = (unsigned char)(MIN(255, (s[0] * s[3]) / 255)); 574 | p[1] = (unsigned char)(MIN(255, (s[1] * s[3]) / 255)); 575 | p[2] = (unsigned char)(MIN(255, (s[2] * s[3]) / 255)); 576 | p += 3; 577 | s += bpp; 578 | } 579 | } 580 | return pix; 581 | } 582 | return NULL; 583 | } 584 | 585 | /** 586 | * Free requested pixel block from an image. 587 | * @param im A handle to an opened Epeg image. 588 | * @param data The pointer to the image pixels. 589 | * 590 | * This frees the data for a block of pixels requested from image @p im. 591 | * @p data must be a valid (non NULL) pointer to a pixel block taken from the 592 | * image @p im by epeg_pixels_get() and mustbe called before the image is 593 | * closed by epeg_close(). 594 | */ 595 | EAPI void 596 | epeg_pixels_free(Epeg_Image *im, const void *data) 597 | { 598 | free((void *)data); 599 | } 600 | 601 | /** 602 | * Get the image comment field as a string. 603 | * @param im A handle to an opened Epeg image. 604 | * @return A pointer to the loaded image comments. 605 | * 606 | * This function returns the comment field as a string (NUL byte terminated) 607 | * of the loaded image @p im, if there is a comment, or NULL if no comment is 608 | * saved with the image. Consider the string returned to be read-only. 609 | * 610 | */ 611 | EAPI const char * 612 | epeg_comment_get(Epeg_Image *im) 613 | { 614 | return im->in.comment; 615 | } 616 | 617 | /** 618 | * Get thumbnail comments of loaded image. 619 | * @param im A handle to an opened Epeg image. 620 | * @param info Pointer to a thumbnail info struct to be filled in. 621 | * 622 | * This function retrieves thumbnail comments written by Epeg to any saved 623 | * JPEG files. If no thumbnail comments were saved, the fields will be 0 in 624 | * the @p info struct on return. 625 | * 626 | */ 627 | EAPI void 628 | epeg_thumbnail_comments_get(Epeg_Image *im, Epeg_Thumbnail_Info *info) 629 | { 630 | if (!info) return; 631 | info->uri = im->in.thumb_info.uri; 632 | info->mtime = im->in.thumb_info.mtime; 633 | info->w = im->in.thumb_info.w; 634 | info->h = im->in.thumb_info.h; 635 | info->mimetype = im->in.thumb_info.mime; 636 | } 637 | 638 | /** 639 | * Set the comment field of the image for saving. 640 | * @param im A handle to an opened Epeg image. 641 | * @param comment The comment to set. 642 | * 643 | * Set the comment for the image file for when it gets saved. This is a NUL 644 | * byte terminated C string. If @p comment is NULL the output file will have 645 | * no comment field. 646 | * 647 | * The default comment will be any comment loaded from the input file. 648 | * 649 | */ 650 | EAPI void 651 | epeg_comment_set(Epeg_Image *im, const char *comment) 652 | { 653 | if (im->out.comment) free(im->out.comment); 654 | if (!comment) im->out.comment = NULL; 655 | else im->out.comment = strdup(comment); 656 | } 657 | 658 | /** 659 | * Set the encoding quality of the saved image. 660 | * @param im A handle to an opened Epeg image. 661 | * @param quality The quality of encoding from 0 to 100. 662 | * 663 | * Set the quality of the output encoded image. Values from 0 to 100 664 | * inclusive are valid, with 100 being the maximum quality, and 0 being the 665 | * minimum. If the quality is set equal to or above 90%, the output U and V 666 | * color planes are encoded at 1:1 with the Y plane. 667 | * 668 | * The default quality is 75. 669 | * 670 | */ 671 | EAPI void 672 | epeg_quality_set(Epeg_Image *im, int quality) 673 | { 674 | if (quality < 0) quality = 0; 675 | else if (quality > 100) quality = 100; 676 | im->out.quality = quality; 677 | } 678 | 679 | /** 680 | * Enable thumbnail comments in saved image. 681 | * @param im A handle to an opened Epeg image. 682 | * @param onoff A boolean on and off enabling flag. 683 | * 684 | * if @p onoff is 1, the output file will have thumbnail comments added to 685 | * it, and if it is 0, it will not. The default is 0. 686 | * 687 | */ 688 | EAPI void 689 | epeg_thumbnail_comments_enable(Epeg_Image *im, int onoff) 690 | { 691 | im->out.thumbnail_info = onoff; 692 | } 693 | 694 | /** 695 | * Set the output file path for the image when saved. 696 | * @param im A handle to an opened Epeg image. 697 | * @param file The path to the output file. 698 | * 699 | * This sets the output file path name (either a full or relative path name) 700 | * to where the file will be written when saved. @p file must be a NUL 701 | * terminated C string conatining the path to the file to be saved to. If it is 702 | * NULL, the image will not be saved to a file when calling epeg_encode(). 703 | */ 704 | EAPI void 705 | epeg_file_output_set(Epeg_Image *im, const char *file) 706 | { 707 | if (im->out.file) free(im->out.file); 708 | if (!file) im->out.file = NULL; 709 | else im->out.file = strdup(file); 710 | } 711 | 712 | /** 713 | * Set the output file to be a block of allocated memory. 714 | * @param im A handle to an opened Epeg image. 715 | * @param data A pointer to a pointer to a memory block. 716 | * @param size A pointer to a counter of the size of the memory block. 717 | * 718 | * This sets the output encoding of the image when saved to be allocated 719 | * memory. After epeg_close() is called the pointer pointed to by @p data 720 | * and the integer pointed to by @p size will contain the pointer to the 721 | * memory block and its size in bytes, respecitvely. The memory block can be 722 | * freed with the free() function call. If the save fails the pointer to the 723 | * memory block will be unaffected, as will the size. 724 | * 725 | */ 726 | EAPI void 727 | epeg_memory_output_set(Epeg_Image *im, unsigned char **data, int *size) 728 | { 729 | im->out.mem.data = data; 730 | im->out.mem.size = size; 731 | im->out.file = NULL; 732 | } 733 | 734 | /** 735 | * This saves the image to its specified destination. 736 | * @param im A handle to an opened Epeg image. 737 | * 738 | * This saves the image @p im to its destination specified by 739 | * epeg_file_output_set() or epeg_memory_output_set(). The image will be 740 | * encoded at the deoded pixel size, using the quality, comment and thumbnail 741 | * comment settings set on the image. 742 | * 743 | * retval 1 - error scale 744 | * 2 - error encode 745 | * 3 - error decode 746 | * 4 - error decode ( setjmp ) 747 | */ 748 | EAPI int 749 | epeg_encode(Epeg_Image *im) 750 | { 751 | int ret; 752 | if ((ret = _epeg_decode(im)) != 0) 753 | return (ret == 2 ? 4 : 3); 754 | if (_epeg_scale(im) != 0) 755 | return 1; 756 | if (_epeg_encode(im) != 0) 757 | return 2; 758 | return 0; 759 | } 760 | 761 | /** 762 | * FIXME: Document this 763 | * @param im A handle to an opened Epeg image. 764 | * 765 | * FIXME: Document this. 766 | */ 767 | EAPI int 768 | epeg_trim(Epeg_Image *im) 769 | { 770 | if (_epeg_decode_for_trim(im) != 0) 771 | return 1; 772 | if (_epeg_trim(im) != 0) 773 | return 1; 774 | if (_epeg_encode(im) != 0) 775 | return 1; 776 | return 0; 777 | } 778 | 779 | /** 780 | * Close an image handle. 781 | * @param im A handle to an opened Epeg image. 782 | * 783 | * This closes an opened image handle and frees all memory associated with it. 784 | * It does not free encoded data generated by epeg_memory_output_set() followed 785 | * by epeg_encode() nor does it guarantee to free any data recieved by 786 | * epeg_pixels_get(). Once an image handle is closed consider it invalid. 787 | */ 788 | EAPI void 789 | epeg_close(Epeg_Image *im) 790 | { 791 | if (!im) return; 792 | if (im->pixels) free(im->pixels); 793 | if (im->lines) free(im->lines); 794 | if (im->in.file) free(im->in.file); 795 | if (!im->in.file) free(im->in.jinfo.src); 796 | if (im->in.f || im->in.mem.data) jpeg_destroy_decompress(&(im->in.jinfo)); 797 | if (im->in.f) fclose(im->in.f); 798 | if (im->in.comment) free(im->in.comment); 799 | if (im->in.thumb_info.uri) free(im->in.thumb_info.uri); 800 | if (im->in.thumb_info.mime) free(im->in.thumb_info.mime); 801 | if (im->out.file) free(im->out.file); 802 | if (!im->out.file) free(im->out.jinfo.dest); 803 | if (im->out.f || im->out.mem.data) jpeg_destroy_compress(&(im->out.jinfo)); 804 | if (im->out.f) fclose(im->out.f); 805 | if (im->out.comment) free(im->out.comment); 806 | free(im); 807 | } 808 | 809 | static Epeg_Image * 810 | _epeg_open_header(Epeg_Image *im) 811 | { 812 | struct jpeg_marker_struct *m; 813 | struct jpeg_source_mgr *src_mgr = NULL; 814 | 815 | im->in.jinfo.err = jpeg_std_error(&(im->jerr.pub)); 816 | im->jerr.pub.error_exit = _epeg_fatal_error_handler; 817 | #ifdef NOWARNINGS 818 | im->jerr.pub.emit_message = _emit_message; 819 | im->jerr.pub.output_message = _output_message; 820 | im->jerr.pub.format_message = _format_message; 821 | #endif 822 | 823 | if (setjmp(im->jerr.setjmp_buffer)) 824 | { 825 | error: 826 | epeg_close(im); 827 | im = NULL; 828 | return NULL; 829 | } 830 | 831 | jpeg_create_decompress(&(im->in.jinfo)); 832 | jpeg_save_markers(&(im->in.jinfo), JPEG_APP0 + 7, 1024); 833 | /* Save Exif markers */ 834 | jpeg_save_markers(&(im->in.jinfo), JPEG_APP0 + 1, 65535); 835 | jpeg_save_markers(&(im->in.jinfo), JPEG_COM, 65535); 836 | if (im->in.f != NULL) 837 | { 838 | jpeg_stdio_src(&(im->in.jinfo), im->in.f); 839 | } 840 | else 841 | { 842 | /* Setup RAM source manager. */ 843 | src_mgr = calloc(1, sizeof(struct jpeg_source_mgr)); 844 | if (!src_mgr) goto error; 845 | src_mgr->init_source = _jpeg_init_source; 846 | src_mgr->fill_input_buffer = _jpeg_fill_input_buffer; 847 | src_mgr->skip_input_data = _jpeg_skip_input_data; 848 | src_mgr->resync_to_restart = jpeg_resync_to_restart; 849 | src_mgr->term_source = _jpeg_term_source; 850 | src_mgr->bytes_in_buffer = im->in.mem.size; 851 | src_mgr->next_input_byte = (JOCTET *) im->in.mem.data; 852 | im->in.jinfo.src = (struct jpeg_source_mgr *) src_mgr; 853 | } 854 | 855 | jpeg_read_header(&(im->in.jinfo), TRUE); 856 | im->in.w = im->in.jinfo.image_width; 857 | im->in.h = im->in.jinfo.image_height; 858 | if (im->in.w < 1) goto error; 859 | if (im->in.h < 1) goto error; 860 | 861 | im->out.w = im->in.w; 862 | im->out.h = im->in.h; 863 | 864 | im->color_space = ((im->in.color_space = im->in.jinfo.out_color_space) == JCS_GRAYSCALE) ? EPEG_GRAY8 : EPEG_RGB8; 865 | if (im->in.color_space == JCS_CMYK) im->color_space = EPEG_CMYK; 866 | 867 | /* Will be set if orientation is present in EXIF data */ 868 | im->in.orientation = 0; 869 | 870 | for (m = im->in.jinfo.marker_list; m; m = m->next) 871 | { 872 | if (m->marker == JPEG_COM) 873 | { 874 | if (im->in.comment) free(im->in.comment); 875 | im->in.comment = malloc(m->data_length + 1); 876 | if (im->in.comment) 877 | { 878 | memcpy(im->in.comment, m->data, m->data_length); 879 | im->in.comment[m->data_length] = 0; 880 | } 881 | } 882 | else if (m->marker == (JPEG_APP0 + 7)) 883 | { 884 | if ((m->data_length > 7) && 885 | (!strncmp((char *)m->data, "Thumb::", 7))) 886 | { 887 | char *p, *p2; 888 | 889 | p = malloc(m->data_length + 1); 890 | if (p) 891 | { 892 | memcpy(p, m->data, m->data_length); 893 | p[m->data_length] = 0; 894 | p2 = strchr(p, '\n'); 895 | if (p2) 896 | { 897 | p2[0] = 0; 898 | if (!strcmp(p, "Thumb::URI")) 899 | 900 | im->in.thumb_info.uri = strdup(p2 + 1); 901 | else if (!strcmp(p, "Thumb::MTime")) 902 | sscanf(p2 + 1, "%llu", &(im->in.thumb_info.mtime)); 903 | else if (!strcmp(p, "Thumb::Image::Width")) 904 | im->in.thumb_info.w = atoi(p2 + 1); 905 | else if (!strcmp(p, "Thumb::Image::Height")) 906 | im->in.thumb_info.h = atoi(p2 + 1); 907 | else if (!strcmp(p, "Thumb::Mimetype")) 908 | im->in.thumb_info.mime = strdup(p2 + 1); 909 | } 910 | free(p); 911 | } 912 | } 913 | } 914 | else if (m->marker == (JPEG_APP0 + 1)) 915 | { 916 | /* 917 | * Look for an Exif Orientation tag. If found, 918 | * store it in im->in.orientation. Later, this will 919 | * be written to the output jpeg Exif data. 920 | */ 921 | ExifData *ed = exif_data_new_from_data(m->data, m->data_length); 922 | if (ed) { 923 | exif_byte_order = exif_data_get_byte_order(ed); 924 | ExifEntry *entry = exif_content_get_entry(ed->ifd[EXIF_IFD_0],EXIF_TAG_ORIENTATION); 925 | if (entry) { 926 | im->in.orientation = exif_get_short(entry->data, exif_byte_order); 927 | // do not unref the entry since exif_content_get_entry does not copy the memory, 928 | // it returns the entry pointer from ed, this is the reason way exif_data_unref throws segfault 929 | // exif_entry_unref(entry); 930 | } 931 | } 932 | exif_data_unref(ed); 933 | } 934 | } 935 | return im; 936 | } 937 | 938 | /** 939 | retval 1 - malloc or other 940 | 2 - setjmp error 941 | */ 942 | static int 943 | _epeg_decode(Epeg_Image *im) 944 | { 945 | int scale, scalew, scaleh, y; 946 | JDIMENSION old_output_scanline = 1; 947 | 948 | if (im->pixels) return 1; 949 | if ((im->out.w < 1) || (im->out.h < 1)) return 1; 950 | 951 | scalew = im->in.w / im->out.w; 952 | scaleh = im->in.h / im->out.h; 953 | 954 | scale = scalew; 955 | if (scaleh < scalew) scale = scaleh; 956 | 957 | if (scale > 8) scale = 8; 958 | else if (scale < 1) scale = 1; 959 | 960 | im->in.jinfo.scale_num = 1; 961 | im->in.jinfo.scale_denom = scale; 962 | im->in.jinfo.do_fancy_upsampling = FALSE; 963 | im->in.jinfo.do_block_smoothing = FALSE; 964 | im->in.jinfo.dct_method = JDCT_IFAST; 965 | 966 | switch (im->color_space) 967 | { 968 | case EPEG_GRAY8: 969 | im->in.jinfo.out_color_space = JCS_GRAYSCALE; 970 | im->in.jinfo.output_components = 1; 971 | break; 972 | 973 | case EPEG_YUV8: 974 | im->in.jinfo.out_color_space = JCS_YCbCr; 975 | break; 976 | 977 | case EPEG_RGB8: 978 | case EPEG_BGR8: 979 | case EPEG_RGBA8: 980 | case EPEG_BGRA8: 981 | case EPEG_ARGB32: 982 | im->in.jinfo.out_color_space = JCS_RGB; 983 | break; 984 | 985 | case EPEG_CMYK: 986 | im->in.jinfo.out_color_space = JCS_CMYK; 987 | im->in.jinfo.output_components = 4; 988 | break; 989 | 990 | default: 991 | break; 992 | } 993 | 994 | im->out.jinfo.err = jpeg_std_error(&(im->jerr.pub)); 995 | im->jerr.pub.error_exit = _epeg_fatal_error_handler; 996 | #ifdef NOWARNINGS 997 | im->jerr.pub.emit_message = _emit_message; 998 | im->jerr.pub.output_message = _output_message; 999 | im->jerr.pub.format_message = _format_message; 1000 | #endif 1001 | 1002 | if (setjmp(im->jerr.setjmp_buffer)) 1003 | return 2; 1004 | 1005 | jpeg_calc_output_dimensions(&(im->in.jinfo)); 1006 | 1007 | im->pixels = malloc(im->in.jinfo.output_width * im->in.jinfo.output_height * im->in.jinfo.output_components); 1008 | if (!im->pixels) return 1; 1009 | 1010 | im->lines = malloc(im->in.jinfo.output_height * sizeof(char *)); 1011 | if (!im->lines) 1012 | { 1013 | free(im->pixels); 1014 | im->pixels = NULL; 1015 | return 1; 1016 | } 1017 | 1018 | jpeg_start_decompress(&(im->in.jinfo)); 1019 | 1020 | for (y = 0; y < im->in.jinfo.output_height; y++) 1021 | im->lines[y] = im->pixels + (y * im->in.jinfo.output_components * im->in.jinfo.output_width); 1022 | 1023 | while (im->in.jinfo.output_scanline < im->in.jinfo.output_height) 1024 | { 1025 | if (old_output_scanline == im->in.jinfo.output_scanline) 1026 | { 1027 | jpeg_abort_decompress(&(im->in.jinfo)); 1028 | return 1; 1029 | } 1030 | old_output_scanline = im->in.jinfo.output_scanline; 1031 | jpeg_read_scanlines(&(im->in.jinfo), 1032 | &(im->lines[im->in.jinfo.output_scanline]), 1033 | im->in.jinfo.rec_outbuf_height); 1034 | } 1035 | 1036 | jpeg_finish_decompress(&(im->in.jinfo)); 1037 | 1038 | return 0; 1039 | } 1040 | 1041 | static int 1042 | _epeg_scale(Epeg_Image *im) 1043 | { 1044 | unsigned char *dst, *row, *src; 1045 | int x, y, w, h, i; 1046 | 1047 | if ((im->in.w == im->out.w) && (im->in.h == im->out.h)) return 0; 1048 | if (im->scaled) return 0; 1049 | 1050 | if ((im->out.w < 1) || (im->out.h < 1)) return 0; 1051 | 1052 | im->scaled = 1; 1053 | w = im->out.w; 1054 | h = im->out.h; 1055 | for (y = 0; y < h; y++) 1056 | { 1057 | row = im->pixels + (((y * im->in.jinfo.output_height) / h) * im->in.jinfo.output_components * im->in.jinfo.output_width); 1058 | dst = im->pixels + (y * im->in.jinfo.output_components * im->in.jinfo.output_width); 1059 | 1060 | for (x = 0; x < im->out.w; x++) 1061 | { 1062 | src = row + (((x * im->in.jinfo.output_width) / w) * im->in.jinfo.output_components); 1063 | for (i = 0; i < im->in.jinfo.output_components; i++) 1064 | dst[i] = src[i]; 1065 | dst += im->in.jinfo.output_components; 1066 | } 1067 | } 1068 | return 0; 1069 | } 1070 | 1071 | static int 1072 | _epeg_decode_for_trim(Epeg_Image *im) 1073 | { 1074 | int y; 1075 | 1076 | if (im->pixels) return 1; 1077 | 1078 | im->in.jinfo.scale_num = 1; 1079 | im->in.jinfo.scale_denom = 1; 1080 | im->in.jinfo.do_fancy_upsampling = FALSE; 1081 | im->in.jinfo.do_block_smoothing = FALSE; 1082 | im->in.jinfo.dct_method = JDCT_ISLOW; 1083 | 1084 | switch (im->color_space) 1085 | { 1086 | case EPEG_GRAY8: 1087 | im->in.jinfo.out_color_space = JCS_GRAYSCALE; 1088 | im->in.jinfo.output_components = 1; 1089 | break; 1090 | 1091 | case EPEG_YUV8: 1092 | im->in.jinfo.out_color_space = JCS_YCbCr; 1093 | break; 1094 | 1095 | case EPEG_RGB8: 1096 | case EPEG_BGR8: 1097 | case EPEG_RGBA8: 1098 | case EPEG_BGRA8: 1099 | case EPEG_ARGB32: 1100 | im->in.jinfo.out_color_space = JCS_RGB; 1101 | break; 1102 | 1103 | case EPEG_CMYK: 1104 | im->in.jinfo.out_color_space = JCS_CMYK; 1105 | im->in.jinfo.output_components = 4; 1106 | break; 1107 | 1108 | default: 1109 | break; 1110 | } 1111 | 1112 | im->out.jinfo.err = jpeg_std_error(&(im->jerr.pub)); 1113 | im->jerr.pub.error_exit = _epeg_fatal_error_handler; 1114 | #ifdef NOWARNINGS 1115 | im->jerr.pub.emit_message = _emit_message; 1116 | im->jerr.pub.output_message = _output_message; 1117 | im->jerr.pub.format_message = _format_message; 1118 | #endif 1119 | 1120 | if (setjmp(im->jerr.setjmp_buffer)) 1121 | return 1; 1122 | 1123 | jpeg_calc_output_dimensions(&(im->in.jinfo)); 1124 | 1125 | im->pixels = malloc(im->in.jinfo.output_width * im->in.jinfo.output_height * im->in.jinfo.output_components); 1126 | if (!im->pixels) return 1; 1127 | 1128 | im->lines = malloc(im->in.jinfo.output_height * sizeof(char *)); 1129 | if (!im->lines) 1130 | { 1131 | free(im->pixels); 1132 | im->pixels = NULL; 1133 | return 1; 1134 | } 1135 | 1136 | jpeg_start_decompress(&(im->in.jinfo)); 1137 | 1138 | for (y = 0; y < im->in.jinfo.output_height; y++) 1139 | im->lines[y] = im->pixels + (y * im->in.jinfo.output_components * im->in.jinfo.output_width); 1140 | 1141 | while (im->in.jinfo.output_scanline < im->in.jinfo.output_height) 1142 | jpeg_read_scanlines(&(im->in.jinfo), 1143 | &(im->lines[im->in.jinfo.output_scanline]), 1144 | im->in.jinfo.rec_outbuf_height); 1145 | 1146 | jpeg_finish_decompress(&(im->in.jinfo)); 1147 | 1148 | return 0; 1149 | } 1150 | 1151 | static int 1152 | _epeg_trim(Epeg_Image *im) 1153 | { 1154 | int y, a, b, h; 1155 | 1156 | if ((im->in.w == im->out.w) && (im->in.h == im->out.h)) return 1; 1157 | if (im->scaled) return 1; 1158 | 1159 | im->scaled = 1; 1160 | h = im->out.h; 1161 | a = im->out.x; 1162 | b = im->out.y; 1163 | 1164 | for (y = 0; y < h; y++) 1165 | im->lines[y] = im->pixels + ((y+b) * im->in.jinfo.output_components * im->in.jinfo.output_width) + (a * im->in.jinfo.output_components); 1166 | 1167 | return 0; 1168 | } 1169 | 1170 | struct epeg_destination_mgr 1171 | { 1172 | struct jpeg_destination_mgr dst_mgr; 1173 | Epeg_Image *im; 1174 | unsigned char *buf; 1175 | }; 1176 | 1177 | /* Get an existing tag, or create one if it doesn't exist */ 1178 | static ExifEntry *init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag) 1179 | { 1180 | ExifEntry *entry = exif_content_get_entry (exif->ifd[ifd], tag); 1181 | if (entry) 1182 | return entry; 1183 | entry = exif_entry_new (); 1184 | if (entry) { 1185 | exif_content_add_entry (exif->ifd[ifd], entry); 1186 | exif_entry_initialize (entry, tag); 1187 | } 1188 | return entry; 1189 | } 1190 | 1191 | static int 1192 | _epeg_encode(Epeg_Image *im) 1193 | { 1194 | struct epeg_destination_mgr *dst_mgr = NULL; 1195 | int ok = 0; 1196 | 1197 | if ((im->out.w < 1) || (im->out.h < 1)) return 1; 1198 | if (im->out.f) return 1; 1199 | 1200 | if (im->out.file) 1201 | { 1202 | im->out.f = fopen(im->out.file, "wb"); 1203 | if (!im->out.f) 1204 | { 1205 | im->error = 1; 1206 | return 1; 1207 | } 1208 | } 1209 | else 1210 | im->out.f = NULL; 1211 | 1212 | im->out.jinfo.err = jpeg_std_error(&(im->jerr.pub)); 1213 | im->jerr.pub.error_exit = _epeg_fatal_error_handler; 1214 | #ifdef NOWARNINGS 1215 | im->jerr.pub.emit_message = _emit_message; 1216 | im->jerr.pub.output_message = _output_message; 1217 | im->jerr.pub.format_message = _format_message; 1218 | #endif 1219 | 1220 | if (setjmp(im->jerr.setjmp_buffer)) 1221 | { 1222 | ok = 1; 1223 | im->error = 1; 1224 | goto done; 1225 | } 1226 | 1227 | jpeg_create_compress(&(im->out.jinfo)); 1228 | if (im->out.f) 1229 | jpeg_stdio_dest(&(im->out.jinfo), im->out.f); 1230 | else 1231 | { 1232 | *(im->out.mem.data) = NULL; 1233 | *(im->out.mem.size) = 0; 1234 | /* Setup RAM destination manager */ 1235 | dst_mgr = calloc(1, sizeof(struct epeg_destination_mgr)); 1236 | if (!dst_mgr) return 1; 1237 | dst_mgr->dst_mgr.init_destination = _jpeg_init_destination; 1238 | dst_mgr->dst_mgr.empty_output_buffer = _jpeg_empty_output_buffer; 1239 | dst_mgr->dst_mgr.term_destination = _jpeg_term_destination; 1240 | dst_mgr->im = im; 1241 | dst_mgr->buf = malloc(65536); 1242 | if (!dst_mgr->buf) 1243 | { 1244 | ok = 1; 1245 | im->error = 1; 1246 | goto done; 1247 | } 1248 | im->out.jinfo.dest = (struct jpeg_destination_mgr *)dst_mgr; 1249 | } 1250 | im->out.jinfo.image_width = im->out.w; 1251 | im->out.jinfo.image_height = im->out.h; 1252 | im->out.jinfo.input_components = im->in.jinfo.output_components; 1253 | im->out.jinfo.in_color_space = im->in.jinfo.out_color_space; 1254 | im->out.jinfo.dct_method = im->in.jinfo.dct_method; 1255 | jpeg_set_defaults(&(im->out.jinfo)); 1256 | jpeg_set_quality(&(im->out.jinfo), im->out.quality, TRUE); 1257 | 1258 | if (im->out.quality >= 90) 1259 | { 1260 | im->out.jinfo.comp_info[0].h_samp_factor = 1; 1261 | im->out.jinfo.comp_info[0].v_samp_factor = 1; 1262 | im->out.jinfo.comp_info[1].h_samp_factor = 1; 1263 | im->out.jinfo.comp_info[1].v_samp_factor = 1; 1264 | im->out.jinfo.comp_info[2].h_samp_factor = 1; 1265 | im->out.jinfo.comp_info[2].v_samp_factor = 1; 1266 | } 1267 | jpeg_start_compress(&(im->out.jinfo), TRUE); 1268 | 1269 | /* Set the image options for Exif */ 1270 | ExifData *exif = exif_data_new(); 1271 | exif_data_set_option(exif, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); 1272 | exif_data_set_byte_order(exif, exif_byte_order); 1273 | exif_data_fix(exif); 1274 | /* Add Exif Orientation tag */ 1275 | if (im->in.orientation != 0) { 1276 | ExifEntry *entry = init_tag(exif, EXIF_IFD_0, EXIF_TAG_ORIENTATION); 1277 | exif_set_short(entry->data, exif_byte_order, im->in.orientation); 1278 | exif_entry_unref(entry); 1279 | } 1280 | /* Write Exif data to output jpeg file */ 1281 | unsigned char *exif_data = NULL; 1282 | unsigned int exif_data_len; 1283 | exif_data_save_data(exif, &exif_data, &exif_data_len); 1284 | jpeg_write_marker(&(im->out.jinfo), JPEG_APP0 + 1, exif_data, exif_data_len); 1285 | exif_data_unref(exif); 1286 | free(exif_data); 1287 | 1288 | /* Output comment if there is one */ 1289 | if (im->out.comment && *im->out.comment) 1290 | jpeg_write_marker(&(im->out.jinfo), JPEG_COM, im->out.comment, strlen(im->out.comment)); 1291 | 1292 | /* Output thumbnail info in APP7 */ 1293 | if (im->out.thumbnail_info) 1294 | { 1295 | char buf[8192]; 1296 | 1297 | if (im->in.file) 1298 | { 1299 | snprintf(buf, sizeof(buf), "Thumb::URI\nfile://%s", im->in.file); 1300 | jpeg_write_marker(&(im->out.jinfo), JPEG_APP0 + 7, buf, strlen(buf)); 1301 | snprintf(buf, sizeof(buf), "Thumb::MTime\n%llu", (unsigned long long int)im->stat_info.st_mtime); 1302 | } 1303 | jpeg_write_marker(&(im->out.jinfo), JPEG_APP0 + 7, buf, strlen(buf)); 1304 | snprintf(buf, sizeof(buf), "Thumb::Image::Width\n%i", im->in.w); 1305 | jpeg_write_marker(&(im->out.jinfo), JPEG_APP0 + 7, buf, strlen(buf)); 1306 | snprintf(buf, sizeof(buf), "Thumb::Image::Height\n%i", im->in.h); 1307 | jpeg_write_marker(&(im->out.jinfo), JPEG_APP0 + 7, buf, strlen(buf)); 1308 | snprintf(buf, sizeof(buf), "Thumb::Mimetype\nimage/jpeg"); 1309 | jpeg_write_marker(&(im->out.jinfo), JPEG_APP0 + 7, buf, strlen(buf)); 1310 | } 1311 | 1312 | while (im->out.jinfo.next_scanline < im->out.h) 1313 | jpeg_write_scanlines(&(im->out.jinfo), &(im->lines[im->out.jinfo.next_scanline]), 1); 1314 | jpeg_finish_compress(&(im->out.jinfo)); 1315 | 1316 | done: 1317 | if ((im->in.f) || (im->in.mem.data != NULL)) jpeg_destroy_decompress(&(im->in.jinfo)); 1318 | if ((im->in.f) && (im->in.file)) fclose(im->in.f); 1319 | if (dst_mgr) 1320 | { 1321 | if (dst_mgr->buf) free(dst_mgr->buf); 1322 | free(dst_mgr); 1323 | im->out.jinfo.dest = NULL; 1324 | } 1325 | jpeg_destroy_compress(&(im->out.jinfo)); 1326 | if ((im->out.f) && (im->out.file)) fclose(im->out.f); 1327 | im->in.f = NULL; 1328 | im->out.f = NULL; 1329 | 1330 | return ok; 1331 | } 1332 | 1333 | static void 1334 | _epeg_fatal_error_handler(j_common_ptr cinfo) 1335 | { 1336 | emptr errmgr; 1337 | 1338 | errmgr = (emptr)cinfo->err; 1339 | longjmp(errmgr->setjmp_buffer, 1); 1340 | return; 1341 | } 1342 | 1343 | /* Source manager methods */ 1344 | METHODDEF(void) 1345 | _jpeg_decompress_error_exit(j_common_ptr cinfo) 1346 | { 1347 | } 1348 | 1349 | 1350 | METHODDEF(void) 1351 | _jpeg_init_source(j_decompress_ptr cinfo) 1352 | { 1353 | } 1354 | 1355 | METHODDEF(boolean) 1356 | _jpeg_fill_input_buffer(j_decompress_ptr cinfo) 1357 | { 1358 | WARNMS(cinfo, JWRN_JPEG_EOF); 1359 | 1360 | /* Insert a fake EOI marker */ 1361 | cinfo->src->next_input_byte = fake_EOI; 1362 | cinfo->src->bytes_in_buffer = sizeof(fake_EOI); 1363 | return TRUE; 1364 | } 1365 | 1366 | 1367 | METHODDEF(void) 1368 | _jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) 1369 | { 1370 | if (num_bytes > (long)(cinfo)->src->bytes_in_buffer) 1371 | ERREXIT(cinfo, 0); 1372 | 1373 | (cinfo)->src->next_input_byte += num_bytes; 1374 | (cinfo)->src->bytes_in_buffer -= num_bytes; 1375 | } 1376 | 1377 | METHODDEF(void) 1378 | _jpeg_term_source(j_decompress_ptr cinfo) 1379 | { 1380 | } 1381 | 1382 | 1383 | /* destination manager methods */ 1384 | METHODDEF(void) 1385 | _jpeg_init_destination(j_compress_ptr cinfo) 1386 | { 1387 | struct epeg_destination_mgr *dst_mgr; 1388 | 1389 | dst_mgr = (struct epeg_destination_mgr *)cinfo->dest; 1390 | dst_mgr->dst_mgr.free_in_buffer = 65536; 1391 | dst_mgr->dst_mgr.next_output_byte = (JOCTET *)dst_mgr->buf; 1392 | } 1393 | 1394 | METHODDEF(boolean) 1395 | _jpeg_empty_output_buffer(j_compress_ptr cinfo) 1396 | { 1397 | struct epeg_destination_mgr *dst_mgr; 1398 | unsigned char *p; 1399 | int psize; 1400 | 1401 | dst_mgr = (struct epeg_destination_mgr *)cinfo->dest; 1402 | psize = *(dst_mgr->im->out.mem.size); 1403 | *(dst_mgr->im->out.mem.size) += 65536; 1404 | p = realloc(*(dst_mgr->im->out.mem.data), *(dst_mgr->im->out.mem.size)); 1405 | if (p) 1406 | { 1407 | *(dst_mgr->im->out.mem.data) = p; 1408 | memcpy(p + psize, dst_mgr->buf, 65536); 1409 | dst_mgr->dst_mgr.free_in_buffer = 65536; 1410 | dst_mgr->dst_mgr.next_output_byte = (JOCTET *)dst_mgr->buf; 1411 | } 1412 | else 1413 | return FALSE; 1414 | return TRUE; 1415 | } 1416 | 1417 | METHODDEF(void) 1418 | _jpeg_term_destination(j_compress_ptr cinfo) 1419 | { 1420 | struct epeg_destination_mgr *dst_mgr; 1421 | unsigned char *p; 1422 | int psize; 1423 | 1424 | dst_mgr = (struct epeg_destination_mgr *)cinfo->dest; 1425 | psize = *(dst_mgr->im->out.mem.size); 1426 | *(dst_mgr->im->out.mem.size) += 65536 - dst_mgr->dst_mgr.free_in_buffer; 1427 | p = realloc(*(dst_mgr->im->out.mem.data), *(dst_mgr->im->out.mem.size)); 1428 | if (p) 1429 | { 1430 | *(dst_mgr->im->out.mem.data) = p; 1431 | memcpy(p + psize, dst_mgr->buf, 65536 - dst_mgr->dst_mgr.free_in_buffer); 1432 | } 1433 | } 1434 | 1435 | /* be noisy - not */ 1436 | METHODDEF(void) 1437 | _emit_message(j_common_ptr cinfo, int msg_level) 1438 | { 1439 | } 1440 | 1441 | METHODDEF(void) 1442 | _output_message(j_common_ptr cinfo) 1443 | { 1444 | } 1445 | 1446 | METHODDEF(void) 1447 | _format_message(j_common_ptr cinfo, char * buffer) 1448 | { 1449 | } 1450 | 1451 | -------------------------------------------------------------------------------- /src/lib/epeg_private.h: -------------------------------------------------------------------------------- 1 | #ifndef _EPEG_PRIVATE_H 2 | #define _EPEG_PRIVATE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "config.h" 18 | 19 | typedef struct _epeg_error_mgr *emptr; 20 | 21 | struct _epeg_error_mgr 22 | { 23 | struct jpeg_error_mgr pub; 24 | jmp_buf setjmp_buffer; 25 | }; 26 | 27 | struct _Epeg_Image 28 | { 29 | struct _epeg_error_mgr jerr; 30 | struct stat stat_info; 31 | unsigned char *pixels; 32 | unsigned char **lines; 33 | 34 | char scaled : 1; 35 | 36 | int error; 37 | 38 | Epeg_Colorspace color_space; 39 | 40 | struct { 41 | char *file; 42 | struct { 43 | unsigned char **data; 44 | int size; 45 | } mem; 46 | int w, h; 47 | char *comment; 48 | FILE *f; 49 | J_COLOR_SPACE color_space; 50 | int orientation; /* Exif orientation values 0-8 */ 51 | struct jpeg_decompress_struct jinfo; 52 | struct { 53 | char *uri; 54 | unsigned long long int mtime; 55 | int w, h; 56 | char *mime; 57 | } thumb_info; 58 | } in; 59 | struct { 60 | char *file; 61 | struct { 62 | unsigned char **data; 63 | int *size; 64 | } mem; 65 | int x, y; 66 | int w, h; 67 | char *comment; 68 | FILE *f; 69 | struct jpeg_compress_struct jinfo; 70 | int quality; 71 | char thumbnail_info : 1; 72 | } out; 73 | }; 74 | 75 | METHODDEF(void) _jpeg_decompress_error_exit(j_common_ptr cinfo); 76 | METHODDEF(void) _jpeg_init_source(j_decompress_ptr cinfo); 77 | METHODDEF(boolean) _jpeg_fill_input_buffer(j_decompress_ptr cinfo); 78 | METHODDEF(void) _jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes); 79 | METHODDEF(void) _jpeg_term_source(j_decompress_ptr cinfo); 80 | 81 | METHODDEF(void) _jpeg_init_destination(j_compress_ptr cinfo); 82 | METHODDEF(boolean) _jpeg_empty_output_buffer (j_compress_ptr cinfo); 83 | METHODDEF(void) _jpeg_term_destination (j_compress_ptr cinfo); 84 | 85 | METHODDEF(void) _emit_message (j_common_ptr cinfo, int msg_level); 86 | METHODDEF(void) _output_message (j_common_ptr cinfo); 87 | METHODDEF(void) _format_message (j_common_ptr cinfo, char * buffer); 88 | #endif 89 | --------------------------------------------------------------------------------