diff --git a/Gemfile b/Gemfile index 19d3fed03..f3c22f909 100644 --- a/Gemfile +++ b/Gemfile @@ -28,11 +28,8 @@ gem "meta_search", :git => "git://github.com/ernie/meta_search.git" gem "silent-postgres" gem "whenever", :require => false gem "sanitize", :git => "git://github.com/rgrove/sanitize.git" +gem 'rmagick' group :development do gem 'pry' end - -group :osx do - gem 'mini_magick' -end diff --git a/Gemfile.lock b/Gemfile.lock index e551de988..15437be37 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -85,8 +85,6 @@ GEM method_source (0.6.0) ruby_parser (>= 2.0.5) mime-types (1.16) - mini_magick (3.3) - subexec (~> 0.1.0) mocha (0.10.0) metaclass (~> 0.0.1) multi_json (1.0.3) @@ -128,6 +126,7 @@ GEM thor (~> 0.14.6) rake (0.9.2) rdoc (3.9.4) + rmagick (2.13.1) ruby_parser (2.2.0) sexp_processor (~> 3.0) sexp_processor (3.0.6) @@ -144,7 +143,6 @@ GEM hike (~> 1.2) rack (~> 1.0) tilt (!= 1.3.0, ~> 1.1) - subexec (0.1.0) super_exception_notifier (3.0.13) actionmailer rake @@ -180,12 +178,12 @@ DEPENDENCIES mechanize memcache-client meta_search! - mini_magick mocha nokogiri pg pry rails (= 3.1.0) + rmagick sanitize! shoulda silent-postgres diff --git a/INSTALL.debian b/INSTALL.debian index 905298222..e91ee3dc4 100644 --- a/INSTALL.debian +++ b/INSTALL.debian @@ -35,7 +35,7 @@ fi # Install packages echo "Installing packages..." -apt-get -y install build-essential automake openssl libssl-dev libyaml-dev libxml2-dev libxslt-dev autoconf ncurses-dev sudo gcc g++ libreadline-dev zlib1g-dev flex bison libgd2-noxpm libgd2-noxpm-dev bzip2 ragel memcached libmemcache-dev git curl libcurl4-openssl-dev emacs-nox postfix +apt-get -y install build-essential automake openssl libssl-dev libyaml-dev libxml2-dev libxslt-dev autoconf ncurses-dev sudo gcc g++ libreadline-dev zlib1g-dev flex bison bzip2 ragel memcached libmemcache-dev git curl libcurl4-openssl-dev emacs-nox imagemagick libmagickcore-dev libmagickwand-dev postfix # Install PostgreSQL 9.1 apt-get -y install python-software-properties diff --git a/app/models/upload.rb b/app/models/upload.rb index 5dd90a33d..2d7d8042a 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -126,12 +126,12 @@ class Upload < ActiveRecord::Base module ResizerMethods def generate_resizes(source_path) - generate_resize_for(Danbooru.config.small_image_width, Danbooru.config.small_image_width, source_path) + generate_resize_for(Danbooru.config.small_image_width, Danbooru.config.small_image_width, source_path, 80) generate_resize_for(Danbooru.config.medium_image_width, nil, source_path) generate_resize_for(Danbooru.config.large_image_width, nil, source_path) end - def generate_resize_for(width, height, source_path) + def generate_resize_for(width, height, source_path, quality = 90) return if width.nil? return unless image_width > width return unless height.nil? || image_height > height @@ -140,15 +140,7 @@ class Upload < ActiveRecord::Base raise Error.new("file not found") end - size = Danbooru.reduce_to({:width => image_width, :height => image_height}, {:width => width, :height => height}) - - # If we're not reducing the resolution, only reencode if the source image larger than - # 200 kilobytes. - if size[:width] == image_width && size[:height] == image_height && File.size?(source_path) < 200.kilobytes - return - end - - Danbooru.resize(file_ext, source_path, resized_file_path_for(width), size, 90) + Danbooru.resize(source_path, resized_file_path_for(width), width, height, quality) end end diff --git a/config/deploy.rb b/config/deploy.rb index 7dc205399..1624ed79a 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -79,11 +79,6 @@ namespace :deploy do task :restart do run "touch #{current_path}/tmp/restart.txt" end - - desc "Compile the image resizer" - task :compile_image_resizer do - run "cd #{release_path}/lib/danbooru_image_resizer ; ruby extconf.rb ; make" - end end namespace :delayed_job do @@ -109,7 +104,6 @@ after "deploy:setup", "local_config:setup_local_files" after "deploy:setup", "data:setup_directories" after "deploy:symlink", "local_config:link_local_files" after "deploy:symlink", "data:link_directories" -after "deploy:symlink", "deploy:compile_image_resizer" after "deploy:start", "delayed_job:start" after "deploy:stop", "delayed_job:stop" after "deploy:restart", "delayed_job:restart" diff --git a/lib/danbooru_image_resizer/ConvertToRGB.cpp b/lib/danbooru_image_resizer/ConvertToRGB.cpp deleted file mode 100644 index eb1e950d3..000000000 --- a/lib/danbooru_image_resizer/ConvertToRGB.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include "ConvertToRGB.h" -#include "Filter.h" -#include -using namespace std; - -ConvertToRGB::ConvertToRGB(auto_ptr pCompressor): - m_pCompressor(pCompressor) -{ - m_pBuffer = NULL; -} - -ConvertToRGB::~ConvertToRGB() -{ - delete[] m_pBuffer; -} - -bool ConvertToRGB::Init(int iSourceWidth, int iSourceHeight, int iBPP) -{ - m_iSourceWidth = iSourceWidth; - // m_iSourceHeight = iSourceHeight; - m_iBPP = iBPP; - m_pBuffer = new uint8_t[iSourceWidth * 3]; - assert(m_iBPP == 1 || m_iBPP == 3 || m_iBPP == 4); // greyscale, RGB or RGBA - - return m_pCompressor->Init(iSourceWidth, iSourceHeight, 3); -} - -bool ConvertToRGB::WriteRow(uint8_t *pNewRow) -{ - if(m_iBPP == 3) - return m_pCompressor->WriteRow(pNewRow); - if(m_iBPP == 1) - { - uint8_t *pBuffer = m_pBuffer; - for(int i = 0; i < m_iSourceWidth; ++i) - { - *pBuffer++ = *pNewRow; - *pBuffer++ = *pNewRow; - *pBuffer++ = *pNewRow; - ++pNewRow; - } - } - else if(m_iBPP == 4) - { - uint8_t *pBuffer = m_pBuffer; - for(int i = 0; i < m_iSourceWidth; ++i) - { - uint8_t iR = *pNewRow++; - uint8_t iG = *pNewRow++; - uint8_t iB = *pNewRow++; - uint8_t iA = *pNewRow++; - iR = uint8_t((iR * iA) / 255.0f); - iG = uint8_t((iG * iA) / 255.0f); - iB = uint8_t((iB * iA) / 255.0f); - *pBuffer++ = iR; - *pBuffer++ = iG; - *pBuffer++ = iB; - } - } - - return m_pCompressor->WriteRow(m_pBuffer); -} - diff --git a/lib/danbooru_image_resizer/ConvertToRGB.h b/lib/danbooru_image_resizer/ConvertToRGB.h deleted file mode 100644 index be117c90f..000000000 --- a/lib/danbooru_image_resizer/ConvertToRGB.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CONVERT_TO_RGB_H -#define CONVERT_TO_RGB_H - -#include "Filter.h" -#include -using namespace std; - -class ConvertToRGB: public Filter -{ -public: - ConvertToRGB(auto_ptr pCompressor); - ~ConvertToRGB(); - - bool Init(int iSourceWidth, int iSourceHeight, int BPP); - bool WriteRow(uint8_t *pNewRow); - bool Finish() { return true; } - - const char *GetError() const { return NULL; } - -private: - uint8_t *m_pBuffer; - auto_ptr m_pCompressor; - int m_iSourceWidth; - int m_iBPP; -}; - -#endif diff --git a/lib/danbooru_image_resizer/Filter.h b/lib/danbooru_image_resizer/Filter.h deleted file mode 100644 index 03b1093e6..000000000 --- a/lib/danbooru_image_resizer/Filter.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef FILTER_H -#define FILTER_H - -#include - -class Filter -{ -public: - virtual ~Filter() { } - virtual bool Init(int iSourceWidth, int iSourceHeight, int iSourceBPP) = 0; - virtual bool WriteRow(uint8_t *row) = 0; - virtual bool Finish() = 0; - virtual const char *GetError() const = 0; -}; - -#endif diff --git a/lib/danbooru_image_resizer/GIFReader.cpp b/lib/danbooru_image_resizer/GIFReader.cpp deleted file mode 100644 index b4bbc9eb4..000000000 --- a/lib/danbooru_image_resizer/GIFReader.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include "GIFReader.h" -#include "Resize.h" - -bool GIF::Read(FILE *f, Filter *pOutput, char error[1024]) -{ - bool Ret = false; - gdImage *image = gdImageCreateFromGif(f); - - if(!image) - { - strcpy(error, "couldn't read GIF"); - return false; - } - - uint8_t *pBuf = NULL; - pBuf = (uint8_t *) malloc(image->sx * 3); - if(pBuf == NULL) - { - strcpy(error, "out of memory"); - goto cleanup; - } - - pOutput->Init(image->sx, image->sy, 3); - for(int y = 0; y < image->sy; ++y) - { - uint8_t *p = pBuf; - - for(int x = 0; x < image->sx; ++x) - { - int c = gdImageGetTrueColorPixel(image, x, y); - (*p++) = gdTrueColorGetRed(c); - (*p++) = gdTrueColorGetGreen(c); - (*p++) = gdTrueColorGetBlue(c); - } - - if(!pOutput->WriteRow(pBuf)) - { - strcpy(error, pOutput->GetError()); - goto cleanup; - } - } - - if(!pOutput->Finish()) - { - strcpy(error, pOutput->GetError()); - goto cleanup; - } - - Ret = true; - -cleanup: - if(pBuf != NULL) - free(pBuf); - - gdImageDestroy(image); - return Ret; -} diff --git a/lib/danbooru_image_resizer/GIFReader.h b/lib/danbooru_image_resizer/GIFReader.h deleted file mode 100644 index 42488c1b1..000000000 --- a/lib/danbooru_image_resizer/GIFReader.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef GIF_READER_H -#define GIF_READER_H - -#include "Reader.h" -class Filter; -class GIF: public Reader -{ -public: - bool Read(FILE *f, Filter *pOutput, char error[1024]); -}; - -#endif diff --git a/lib/danbooru_image_resizer/Histogram.cpp b/lib/danbooru_image_resizer/Histogram.cpp deleted file mode 100644 index 49da2e107..000000000 --- a/lib/danbooru_image_resizer/Histogram.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include -#include -#include "Histogram.h" -#include "Filter.h" -#include -using namespace std; - -Histogram::Histogram() -{ - memset(m_Histogram, 0, sizeof(m_Histogram)); -} - -bool Histogram::Init(int iSourceWidth, int iSourceHeight, int iBPP) -{ - assert(iBPP >= 3); - m_SourceWidth = iSourceWidth; - m_SourceBPP = iBPP; - - return true; -} -int Histogram::GetChannels() const -{ - return min(m_SourceBPP, 3); -} - -bool Histogram::WriteRow(uint8_t *pNewRow) -{ - uint8_t *pInput = pNewRow; - int channels = GetChannels(); - for(int x = 0; x < m_SourceWidth; ++x) - { - for(int c = 0; c < channels; ++c) - { - int color = pInput[c]; - if(m_SourceBPP == 3) - color = (color * pInput[3]) / 255; - ++m_Histogram[c][color]; - } - - pInput += m_SourceBPP; - } - - return true; -} - diff --git a/lib/danbooru_image_resizer/Histogram.h b/lib/danbooru_image_resizer/Histogram.h deleted file mode 100644 index dbbef1ea5..000000000 --- a/lib/danbooru_image_resizer/Histogram.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef HISTOGRAM_H -#define HISTOGRAM_H - -#include "Filter.h" -#include -using namespace std; -#include - -class Histogram: public Filter -{ -public: - Histogram(); - - bool Init(int iSourceWidth, int iSourceHeight, int BPP); - bool WriteRow(uint8_t *pNewRow); - bool Finish() { return true; } - - const char *GetError() const { return NULL; } - int GetChannels() const; - const unsigned *GetHistogram(int iChannel) const { return m_Histogram[iChannel]; } - -private: - unsigned m_Histogram[3][256]; - - int m_SourceWidth; - int m_SourceBPP; -}; - -#endif diff --git a/lib/danbooru_image_resizer/JPEGReader.cpp b/lib/danbooru_image_resizer/JPEGReader.cpp deleted file mode 100644 index d235940b9..000000000 --- a/lib/danbooru_image_resizer/JPEGReader.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include -#include -#include "JPEGReader.h" -#include "Resize.h" -#include -using namespace std; - -static void jpeg_error_exit(j_common_ptr CInfo) -{ - jpeg_error *myerr = (jpeg_error *) CInfo->err; - (*CInfo->err->format_message) (CInfo, myerr->buffer); - longjmp(myerr->setjmp_buffer, 1); -} - -static void jpeg_warning(j_common_ptr cinfo, int msg_level) -{ -} - -JPEGCompressor::JPEGCompressor(FILE *f) -{ - m_File = f; - memset(&m_CInfo, 0, sizeof(m_CInfo)); -} - -JPEGCompressor::~JPEGCompressor() -{ - jpeg_destroy_compress(&m_CInfo); -} - -const char *JPEGCompressor::GetError() const -{ - return m_JErr.buffer; -} - -void JPEGCompressor::SetQuality(int quality) -{ - m_iQuality = quality; -} - -bool JPEGCompressor::Init(int width, int height, int bpp) -{ - assert(bpp == 3); - m_CInfo.err = jpeg_std_error(&m_JErr.pub); - - m_JErr.pub.error_exit = jpeg_error_exit; - m_JErr.pub.emit_message = jpeg_warning; - - if(setjmp(m_JErr.setjmp_buffer)) - return false; - - jpeg_create_compress(&m_CInfo); - - jpeg_stdio_dest(&m_CInfo, m_File); - - m_CInfo.image_width = width; - m_CInfo.image_height = height; - m_CInfo.input_components = 3; /* # of color components per pixel */ - m_CInfo.in_color_space = JCS_RGB; /* colorspace of input image */ - - jpeg_set_defaults(&m_CInfo); - jpeg_set_quality(&m_CInfo, m_iQuality, TRUE); // limit to baseline-JPEG values - - /* For high-quality compression, disable color subsampling. */ - if(m_iQuality >= 95) - { - m_CInfo.comp_info[0].h_samp_factor = 1; - m_CInfo.comp_info[0].v_samp_factor = 1; - m_CInfo.comp_info[1].h_samp_factor = 1; - m_CInfo.comp_info[1].v_samp_factor = 1; - m_CInfo.comp_info[2].h_samp_factor = 1; - m_CInfo.comp_info[2].v_samp_factor = 1; - } - - jpeg_start_compress(&m_CInfo, TRUE); - - return true; -} - -int JPEGCompressor::GetWidth() const -{ - return m_CInfo.image_width; -} - -int JPEGCompressor::GetHeight() const -{ - return m_CInfo.image_height; -} - -bool JPEGCompressor::WriteRow(uint8_t *row) -{ - if(setjmp(m_JErr.setjmp_buffer)) - return false; - - jpeg_write_scanlines(&m_CInfo, (JSAMPLE **) &row, 1); - return true; -} - -bool JPEGCompressor::Finish() -{ - if(setjmp(m_JErr.setjmp_buffer)) - return false; - - jpeg_finish_compress(&m_CInfo); - return true; -} - -bool JPEG::Read(FILE *f, Filter *pOutput, char error[1024]) -{ - // JMSG_LENGTH_MAX <= sizeof(error) - m_pOutputFilter = pOutput; - - struct jpeg_decompress_struct CInfo; - CInfo.err = jpeg_std_error(&m_JErr.pub); - m_JErr.pub.error_exit = jpeg_error_exit; - m_JErr.pub.emit_message = jpeg_warning; - - bool Ret = false; - uint8_t *pBuf = NULL; - if(setjmp(m_JErr.setjmp_buffer)) - { - memcpy(error, m_JErr.buffer, JMSG_LENGTH_MAX); - goto cleanup; - } - - jpeg_create_decompress(&CInfo); - - jpeg_stdio_src(&CInfo, f); - jpeg_read_header(&CInfo, TRUE); - CInfo.out_color_space = JCS_RGB; - if(CInfo.jpeg_color_space == JCS_CMYK || CInfo.jpeg_color_space == JCS_YCCK) - { - strcpy(error, "CMYK JPEGs are not supported; please convert to RGB"); - goto cleanup; - } - - jpeg_start_decompress(&CInfo); - - if(!m_pOutputFilter->Init(CInfo.output_width, CInfo.output_height, 3)) - { - strncpy(error, m_pOutputFilter->GetError(), sizeof(error)); - error[sizeof(error)-1] = 0; - goto cleanup; - } - - pBuf = (uint8_t *) malloc(CInfo.output_width * 3); - if(pBuf == NULL) - { - strcpy(error, "out of memory"); - goto cleanup; - } - - while(CInfo.output_scanline < CInfo.output_height) - { - jpeg_read_scanlines(&CInfo, &pBuf, 1); - - if(!m_pOutputFilter->WriteRow(pBuf)) - { - strcpy(error, m_pOutputFilter->GetError()); - goto cleanup; - } - } - - if(!m_pOutputFilter->Finish()) - { - strcpy(error, m_pOutputFilter->GetError()); - goto cleanup; - } - - jpeg_finish_decompress(&CInfo); - - Ret = true; - -cleanup: - if(pBuf != NULL) - free(pBuf); - jpeg_destroy_decompress(&CInfo); - - return Ret; -} - diff --git a/lib/danbooru_image_resizer/JPEGReader.h b/lib/danbooru_image_resizer/JPEGReader.h deleted file mode 100644 index 06c8625c6..000000000 --- a/lib/danbooru_image_resizer/JPEGReader.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef JPEG_READER_H -#define JPEG_READER_H - -#include -#include -#include -#include "jpeglib-extern.h" -#include "Reader.h" -#include "Filter.h" - -struct jpeg_error -{ - struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; - char buffer[JMSG_LENGTH_MAX]; -}; - -class JPEG: public Reader -{ -public: - bool Read(FILE *f, Filter *pOutput, char error[1024]); - -private: - Filter *m_pOutputFilter; - struct jpeg_error m_JErr; -}; - -class JPEGCompressor: public Filter -{ -public: - JPEGCompressor(FILE *f); - ~JPEGCompressor(); - - bool Init(int iSourceWidth, int iSourceHeight, int iBPP); - void SetQuality(int quality); - bool WriteRow(uint8_t *row); - bool Finish(); - - int GetWidth() const; - int GetHeight() const; - const char *GetError() const; - -private: - FILE *m_File; - int m_iQuality; - struct jpeg_compress_struct m_CInfo; - struct jpeg_error m_JErr; -}; - -#endif diff --git a/lib/danbooru_image_resizer/Makefile b/lib/danbooru_image_resizer/Makefile deleted file mode 100644 index b4690b847..000000000 --- a/lib/danbooru_image_resizer/Makefile +++ /dev/null @@ -1,187 +0,0 @@ - -SHELL = /bin/sh - -#### Start of system configuration section. #### - -srcdir = . -topdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1 -hdrdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1 -arch_hdrdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1/$(arch) -VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby -prefix = $(DESTDIR)/Users/ayi/.rvm/rubies/ruby-1.9.2-p0 -rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) -exec_prefix = $(prefix) -vendorhdrdir = $(rubyhdrdir)/vendor_ruby -sitehdrdir = $(rubyhdrdir)/site_ruby -rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version) -vendordir = $(rubylibprefix)/vendor_ruby -sitedir = $(rubylibprefix)/site_ruby -ridir = $(datarootdir)/$(RI_BASE_NAME) -mandir = $(datarootdir)/man -localedir = $(datarootdir)/locale -libdir = $(exec_prefix)/lib -psdir = $(docdir) -pdfdir = $(docdir) -dvidir = $(docdir) -htmldir = $(docdir) -infodir = $(datarootdir)/info -docdir = $(datarootdir)/doc/$(PACKAGE) -oldincludedir = $(DESTDIR)/usr/include -includedir = $(prefix)/include -localstatedir = $(prefix)/var -sharedstatedir = $(prefix)/com -sysconfdir = $(prefix)/etc -datadir = $(datarootdir) -datarootdir = $(prefix)/share -libexecdir = $(exec_prefix)/libexec -sbindir = $(exec_prefix)/sbin -bindir = $(exec_prefix)/bin -rubylibdir = $(rubylibprefix)/$(ruby_version) -archdir = $(rubylibdir)/$(arch) -sitelibdir = $(sitedir)/$(ruby_version) -sitearchdir = $(sitelibdir)/$(sitearch) -vendorlibdir = $(vendordir)/$(ruby_version) -vendorarchdir = $(vendorlibdir)/$(sitearch) - -CC = g++ -CXX = g++ -LIBRUBY = $(LIBRUBY_SO) -LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a -LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) -LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -OUTFLAG = -o -COUTFLAG = -o - -RUBY_EXTCONF_H = -cflags = $(optflags) $(debugflags) $(warnflags) -optflags = -O3 -debugflags = -ggdb -warnflags = -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -CFLAGS = -fno-common -O2 -Wall -INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) -DEFS = -CPPFLAGS = -DHAVE_GD_H -DHAVE_GDIMAGECREATEFROMGIF -DHAVE_GDIMAGEJPEG -DHAVE_JPEG_SET_QUALITY -DHAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8 -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags) -CXXFLAGS = $(CFLAGS) $(cxxflags) -ldflags = -L. -dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace -ARCH_FLAG = -DLDFLAGS = $(ldflags) $(dldflags) -LDSHARED = $(CC) -dynamic -bundle -LDSHAREDXX = $(CXX) -dynamic -bundle -AR = ar -EXEEXT = - -RUBY_BASE_NAME = ruby -RUBY_INSTALL_NAME = ruby -RUBY_SO_NAME = ruby.1.9.1 -arch = x86_64-darwin10.4.0 -sitearch = $(arch) -ruby_version = 1.9.1 -ruby = /Users/ayi/.rvm/rubies/ruby-1.9.2-p0/bin/ruby -RUBY = $(ruby) -RM = rm -f -RM_RF = $(RUBY) -run -e rm -- -rf -RMDIRS = $(RUBY) -run -e rmdir -- -p -MAKEDIRS = mkdir -p -INSTALL = /usr/bin/install -c -INSTALL_PROG = $(INSTALL) -m 0755 -INSTALL_DATA = $(INSTALL) -m 644 -COPY = cp - -#### End of system configuration section. #### - -preload = - -libpath = . $(libdir) /opt/local/lib -LIBPATH = -L. -L$(libdir) -L/opt/local/lib -DEFFILE = - -CLEANFILES = mkmf.log -DISTCLEANFILES = -DISTCLEANDIRS = - -extout = -extout_prefix = -target_prefix = -LOCAL_LIBS = -LIBS = $(LIBRUBYARG_SHARED) -lpng -ljpeg -lgd -lpthread -ldl -lobjc -SRCS = ConvertToRGB.cpp danbooru_image_resizer.cpp GIFReader.cpp Histogram.cpp JPEGReader.cpp PNGReader.cpp Resize.cpp -OBJS = ConvertToRGB.o danbooru_image_resizer.o GIFReader.o Histogram.o JPEGReader.o PNGReader.o Resize.o -TARGET = danbooru_image_resizer -DLLIB = $(TARGET).bundle -EXTSTATIC = -STATIC_LIB = - -BINDIR = $(bindir) -RUBYCOMMONDIR = $(sitedir)$(target_prefix) -RUBYLIBDIR = $(sitelibdir)$(target_prefix) -RUBYARCHDIR = $(sitearchdir)$(target_prefix) -HDRDIR = $(rubyhdrdir)/ruby$(target_prefix) -ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix) - -TARGET_SO = $(DLLIB) -CLEANLIBS = $(TARGET).bundle -CLEANOBJS = *.o *.bak - -all: $(DLLIB) -static: $(STATIC_LIB) -.PHONY: all install static install-so install-rb -.PHONY: clean clean-so clean-rb - -clean-rb-default:: -clean-rb:: -clean-so:: -clean: clean-so clean-rb-default clean-rb - @-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) - -distclean-rb-default:: -distclean-rb:: -distclean-so:: -distclean: clean distclean-so distclean-rb-default distclean-rb - @-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log - @-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) - @-$(RMDIRS) $(DISTCLEANDIRS) - -realclean: distclean -install: install-so install-rb - -install-so: $(RUBYARCHDIR) -install-so: $(RUBYARCHDIR)/$(DLLIB) -$(RUBYARCHDIR)/$(DLLIB): $(DLLIB) - @-$(MAKEDIRS) $(@D) - $(INSTALL_PROG) $(DLLIB) $(@D) -install-rb: pre-install-rb install-rb-default -install-rb-default: pre-install-rb-default -pre-install-rb: Makefile -pre-install-rb-default: Makefile -$(RUBYARCHDIR): - $(MAKEDIRS) $@ - -site-install: site-install-so site-install-rb -site-install-so: install-so -site-install-rb: install-rb - -.SUFFIXES: .c .m .cc .cxx .cpp .C .o - -.cc.o: - $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.cxx.o: - $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.cpp.o: - $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.C.o: - $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $< - -.c.o: - $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $< - -$(DLLIB): $(OBJS) Makefile - @-$(RM) $(@) - $(LDSHAREDXX) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) - - - -$(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h diff --git a/lib/danbooru_image_resizer/PNGReader.cpp b/lib/danbooru_image_resizer/PNGReader.cpp deleted file mode 100644 index 7fa1bd7a7..000000000 --- a/lib/danbooru_image_resizer/PNGReader.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include -#include "PNGReader.h" -#include "Resize.h" -#include -using namespace std; - -void PNG::Error(png_struct *png, const char *error) -{ - png_error_info *info = (png_error_info *) png->error_ptr; - strncpy(info->err, error, 1024); - info->err[1023] = 0; - longjmp(png->jmpbuf, 1); -} - -void PNG::Warning(png_struct *png, const char *warning) -{ -} - -void PNG::InfoCallback(png_struct *png, png_info *info_ptr) -{ - PNG *data = (PNG *) png_get_progressive_ptr(png); - - png_uint_32 width, height; - int bit_depth, color_type; - png_get_IHDR(png, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); - - png_set_palette_to_rgb(png); - png_set_tRNS_to_alpha(png); - png_set_filler(png, 0xFF, PNG_FILLER_AFTER); - if(bit_depth < 8) - png_set_packing(png); - if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand_gray_1_2_4_to_8(png); - if(bit_depth == 16) - png_set_strip_16(png); - data->m_Passes = png_set_interlace_handling(png); - - if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png); - - if(!data->m_Rows.Init(width, height, 4)) - Error(png, "out of memory"); - - png_read_update_info(png, info_ptr); - - data->m_pOutputFilter->Init(width, height, 4); -} - -void PNG::RowCallback(png_struct *png, png_byte *new_row, png_uint_32 row_num, int pass) -{ - PNG *data = (PNG *) png_get_progressive_ptr(png); - - uint8_t *p = data->m_Rows.GetRow(row_num); - if(p == NULL) - Error(png, "out of memory"); - - png_progressive_combine_row(png, p, new_row); - - if(pass != data->m_Passes - 1) - return; - - /* We've allocated data->m_RowsAllocated, but if we're doing multiple passes, only - * rows 0 to row_num will actually have usable data. */ - if(!data->m_pOutputFilter->WriteRow(p)) - Error(png, data->m_pOutputFilter->GetError()); - - /* If we're interlaced, never discard rows. */ - if(data->m_Passes == 1) - data->m_Rows.DiscardRows(row_num+1); -} - -void PNG::EndCallback(png_struct *png, png_info *info) -{ - PNG *data = (PNG *) png_get_progressive_ptr(png); - data->m_Done = true; -} - - -bool PNG::Read(FILE *f, Filter *pOutput, char error[1024]) -{ - m_pOutputFilter = pOutput; - - png_error_info err; - err.err = error; - - png_struct *png = png_create_read_struct(PNG_LIBPNG_VER_STRING, &err, Error, Warning); - if(png == NULL) - { - sprintf(error, "creating png_create_read_struct failed"); - return false; - } - - png_info *info_ptr = png_create_info_struct(png); - if(info_ptr == NULL) - { - png_destroy_read_struct(&png, NULL, NULL); - sprintf(error, "creating png_create_info_struct failed"); - return false; - } - - if(setjmp(png->jmpbuf)) - { - png_destroy_read_struct(&png, &info_ptr, NULL); - return false; - } - - png_set_progressive_read_fn(png, this, InfoCallback, RowCallback, EndCallback); - - while(1) - { - png_byte buf[1024*16]; - int ret = fread(buf, 1, sizeof(buf), f); - if(ret == 0) - break; - if(ferror(f)) - { - strcpy(error, strerror(errno)); - png_destroy_read_struct(&png, &info_ptr, NULL); - return false; - } - - png_process_data(png, info_ptr, buf, ret); - } - - if(!m_pOutputFilter->Finish()) - Error(png, m_pOutputFilter->GetError()); - - if(!m_Done) - { - strcpy(error, "incomplete file"); - png_destroy_read_struct(&png, &info_ptr, NULL); - return false; - } - - png_destroy_read_struct(&png, &info_ptr, NULL); - return true; -} - diff --git a/lib/danbooru_image_resizer/PNGReader.h b/lib/danbooru_image_resizer/PNGReader.h deleted file mode 100644 index a065152d3..000000000 --- a/lib/danbooru_image_resizer/PNGReader.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef PNG_READER_H -#define PNG_READER_H - -#include -#include "Reader.h" -#include "Filter.h" -#include "RowBuffer.h" - -struct png_error_info -{ - char *err; -}; - -class PNG: public Reader -{ -public: - PNG() - { - m_Done = false; - } - - bool Read(FILE *f, Filter *pOutput, char error[1024]); - -private: - RowBuffer m_Rows; - Filter *m_pOutputFilter; - - bool m_Done; - int m_Passes; - - static void Error(png_struct *png, const char *error); - static void Warning(png_struct *png, const char *warning); - static void InfoCallback(png_struct *png, png_info *info_ptr); - static void RowCallback(png_struct *png, png_byte *new_row, png_uint_32 row_num, int pass); - static void EndCallback(png_struct *png, png_info *info); -}; - -#endif diff --git a/lib/danbooru_image_resizer/Reader.h b/lib/danbooru_image_resizer/Reader.h deleted file mode 100644 index eb217ccfd..000000000 --- a/lib/danbooru_image_resizer/Reader.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef READER_H -#define READER_H - -#include - -class Filter; -class Reader -{ -public: - virtual ~Reader() { } - virtual bool Read(FILE *f, Filter *rp, char errorbuf[1024]) = 0; -}; - -#endif diff --git a/lib/danbooru_image_resizer/Resize.cpp b/lib/danbooru_image_resizer/Resize.cpp deleted file mode 100644 index 353f0b8ae..000000000 --- a/lib/danbooru_image_resizer/Resize.cpp +++ /dev/null @@ -1,286 +0,0 @@ -#include -#include -#include -#include -#include -#include "Resize.h" -#include "Filter.h" -#include -using namespace std; - -namespace -{ - inline float sincf(float x) - { - if(fabsf(x) < 1e-9) - return 1.0; - - return sinf(x) / x; - } - - inline double fract(double f) - { - return f - floor(f); - } -} - -static const int KERNEL_SIZE = 3; - -LanczosFilter::LanczosFilter() -{ - m_pFilters = NULL; -} - -LanczosFilter::~LanczosFilter() -{ - delete[] m_pFilters; -} - -void LanczosFilter::Init(float fFactor) -{ - /* If we're reducing the image, each output pixel samples each input pixel in the - * range once, so we step one pixel. If we're enlarging it by 2x, each output pixel - * samples each input pixel twice, so we step half a pixel. */ - m_fStep = 1; - if(fFactor > 1.0) - m_fStep = 1.0 / fFactor; - - /* If we're sampling each pixel twice (m_fStep is .5), then we need twice as many taps - * to sample KERNEL_SIZE pixels. */ - m_iTaps = (int) ceil(KERNEL_SIZE / m_fStep) * 2; - - delete[] m_pFilters; - m_pFilters = NULL; // in case of exception - m_pFilters = new float[m_iTaps * 256]; - - float *pOutput = m_pFilters; - for(int i=0; i < 256; ++i) - { - float fOffset = i / 256.0f; - - float fSum = 0; - for(int i = 0; i < m_iTaps; ++i) - { - float fPos = -(m_iTaps/2-1) - fOffset + i; - fPos *= m_fStep; - - float fValue = 0; - if(fabs(fPos) < KERNEL_SIZE) - fValue = sincf(M_PI*fPos) * sincf(M_PI / KERNEL_SIZE * fPos); - - pOutput[i] = fValue; - fSum += fValue; - } - - /* Scale the filter so it sums to 1. */ - for(int i = 0; i pOutput): - m_pCompressor(pOutput) -{ - m_DestWidth = -1; - m_DestHeight = -1; - m_CurrentY = 0; - m_OutBuf = NULL; - m_szError = NULL; - m_iInputY = 0; -} - -Resizer::~Resizer() -{ - if(m_OutBuf) - free(m_OutBuf); -} - -const char *Resizer::GetError() const -{ - if(m_szError != NULL) - return m_szError; - return m_pCompressor->GetError(); -} - -bool Resizer::Init(int iSourceWidth, int iSourceHeight, int iBPP) -{ - assert(m_DestWidth != -1); - assert(m_DestHeight != -1); - assert(iBPP == 3); - m_SourceWidth = iSourceWidth; - m_SourceHeight = iSourceHeight; - m_SourceBPP = iBPP; - - float fXFactor = float(m_SourceWidth) / m_DestWidth; - m_XFilter.Init(fXFactor); - - float fYFactor = float(m_SourceHeight) / m_DestHeight; - m_YFilter.Init(fYFactor); - - if(!m_Rows.Init(m_DestWidth, m_SourceHeight, m_SourceBPP, m_YFilter.m_iTaps)) - { - m_szError = "out of memory"; - return false; - } - - m_OutBuf = (uint8_t *) malloc(m_DestWidth * m_SourceBPP); - if(m_OutBuf == NULL) - { - m_szError = "out of memory"; - return false; - } - - return m_pCompressor->Init(m_DestWidth, m_DestHeight, m_SourceBPP); -} - -void Resizer::SetDest(int iDestWidth, int iDestHeight) -{ - m_DestWidth = iDestWidth; - m_DestHeight = iDestHeight; -} - -static uint8_t *PadRow(const uint8_t *pSourceRow, int iWidth, int iBPP, int iPadding) -{ - uint8_t *pRow = new uint8_t[(iWidth + iPadding*2) * iBPP]; - uint8_t *pDest = pRow; - for(int x = 0; x < iPadding; ++x) - { - for(int i = 0; i < iBPP; ++i) - pDest[i] = pSourceRow[i]; - pDest += iBPP; - } - - memcpy(pDest, pSourceRow, iWidth*iBPP*sizeof(uint8_t)); - pDest += iWidth*iBPP; - - for(int x = 0; x < iPadding; ++x) - { - for(int i = 0; i < iBPP; ++i) - pDest[i] = pSourceRow[i]; - pDest += iBPP; - } - - return pRow; -} - -bool Resizer::WriteRow(uint8_t *pNewRow) -{ - if(m_SourceWidth == m_DestWidth && m_SourceHeight == m_DestHeight) - { - ++m_CurrentY; - - /* We don't actually have any resizing to do, so short-circuit. */ - if(!m_pCompressor->WriteRow((uint8_t *) pNewRow)) - return false; - - if(m_CurrentY != m_DestHeight) - return true; - - return m_pCompressor->Finish(); - } - - /* Make a copy of pNewRow with the first and last pixel duplicated, so we don't have to do - * bounds checking in the inner loop below. */ - uint8_t *pActualPaddedRow = PadRow(pNewRow, m_SourceWidth, m_SourceBPP, m_XFilter.m_iTaps/2); - const uint8_t *pPaddedRow = pActualPaddedRow + (m_XFilter.m_iTaps/2)*m_SourceBPP; - - const float fXFactor = float(m_SourceWidth) / m_DestWidth; - const float fYFactor = float(m_SourceHeight) / m_DestHeight; - - /* Run the horizontal filter on the incoming row, and drop the result into m_Rows. */ - { - float *pRow = m_Rows.GetRow(m_iInputY); - ++m_iInputY; - - float *pOutput = pRow; - for(int x = 0; x < m_DestWidth; ++x) - { - const double fSourceX = (x + 0.5f) * fXFactor; - const double fOffset = fract(fSourceX + 0.5); - const float *pFilter = m_XFilter.GetFilter(fOffset); - const int iStartX = lrint(fSourceX - m_XFilter.m_iTaps/2 + 1e-6); - - const uint8_t *pSource = pPaddedRow + iStartX*3; - - float fR = 0, fG = 0, fB = 0; - for(int i = 0; i < m_XFilter.m_iTaps; ++i) - { - float fWeight = *pFilter++; - - fR += pSource[0] * fWeight; - fG += pSource[1] * fWeight; - fB += pSource[2] * fWeight; - pSource += 3; - } - - pOutput[0] = fR; - pOutput[1] = fG; - pOutput[2] = fB; - - pOutput += m_SourceBPP; - } - } - delete[] pActualPaddedRow; - - const float *const *pSourceRows = m_Rows.GetRows(); - while(m_CurrentY < m_DestHeight) - { - const double fSourceY = (m_CurrentY + 0.5) * fYFactor; - const double fOffset = fract(fSourceY + 0.5); - const int iStartY = lrint(fSourceY - m_YFilter.m_iTaps/2 + 1e-6); - - /* iStartY is the first row we'll need, and we never move backwards. Discard rows - * before it to save memory. */ - m_Rows.DiscardRows(iStartY); - - if(m_iInputY != m_SourceHeight && iStartY+m_YFilter.m_iTaps >= m_iInputY) - return true; - - /* Process the next output row. */ - uint8_t *pOutput = m_OutBuf; - for(int x = 0; x < m_DestWidth; ++x) - { - const float *pFilter = m_YFilter.GetFilter(fOffset); - - float fR = 0, fG = 0, fB = 0; - for(int i = 0; i < m_YFilter.m_iTaps; ++i) - { - const float *pSource = pSourceRows[iStartY+i]; - pSource += x * m_SourceBPP; - - float fWeight = *pFilter++; - fR += pSource[0] * fWeight; - fG += pSource[1] * fWeight; - fB += pSource[2] * fWeight; - } - - pOutput[0] = (uint8_t) max(0, min(255, (int) lrintf(fR))); - pOutput[1] = (uint8_t) max(0, min(255, (int) lrintf(fG))); - pOutput[2] = (uint8_t) max(0, min(255, (int) lrintf(fB))); - - pOutput += 3; - } - - if(!m_pCompressor->WriteRow((uint8_t *) m_OutBuf)) - return false; - ++m_CurrentY; - } - - if(m_CurrentY == m_DestHeight) - { - if(!m_pCompressor->Finish()) - return false; - } - - return true; -} - diff --git a/lib/danbooru_image_resizer/Resize.h b/lib/danbooru_image_resizer/Resize.h deleted file mode 100644 index 946daada9..000000000 --- a/lib/danbooru_image_resizer/Resize.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef RESIZE_H -#define RESIZE_H - -#include "RowBuffer.h" -#include "Filter.h" -#include -using namespace std; -#include - -struct LanczosFilter -{ - LanczosFilter(); - ~LanczosFilter(); - void Init(float fFactor); - const float *GetFilter(float fOffset) const; - - float m_fStep; - int m_iTaps; - float *m_pFilters; -}; - -class Resizer: public Filter -{ -public: - Resizer(auto_ptr pCompressor); - ~Resizer(); - - // BPP is 3 or 4, indicating RGB or RGBA. - bool Init(int iSourceWidth, int iSourceHeight, int BPP); - void SetDest(int iDestWidth, int iDestHeight); - bool WriteRow(uint8_t *pNewRow); - bool Finish() { return true; } - - const char *GetError() const; - -private: - auto_ptr m_pCompressor; - uint8_t *m_OutBuf; - RowBuffer m_Rows; - const char *m_szError; - - int m_SourceWidth; - int m_SourceHeight; - int m_SourceBPP; - - int m_DestWidth; - int m_DestHeight; - - LanczosFilter m_XFilter; - LanczosFilter m_YFilter; - - int m_iInputY; - int m_CurrentY; -}; - -#endif diff --git a/lib/danbooru_image_resizer/RowBuffer.h b/lib/danbooru_image_resizer/RowBuffer.h deleted file mode 100644 index 2c9618302..000000000 --- a/lib/danbooru_image_resizer/RowBuffer.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef ROW_BUFFER_H -#define ROW_BUFFER_H - -#include -#include -#include -#include -#include "RowBuffer.h" -#include -using namespace std; - -template -class RowBuffer -{ -public: - RowBuffer() - { - m_Rows = NULL; - m_ActualRows = NULL; - m_StartRow = 0; - m_EndRow = 0; - m_BPP = 0; - m_Height = 0; - } - - ~RowBuffer() - { - for(int i = 0; i < m_Height; ++i) - delete [] m_Rows[i]; - - delete [] m_ActualRows; - } - - /* - * If iVertPadding is non-zero, simulate padding on the top and bottom of the image. After - * row 0 is written, rows [-1 ... -iVertPadding] will point to the same row. After the bottom - * row is written, the following iVertPadding will also point to the last row. These rows - * are discarded when the row they refer to is discarded. - */ - bool Init(int iWidth, int iHeight, int iBPP, int iVertPadding = 0) - { - m_Width = iWidth; - m_Height = iHeight; - m_BPP = iBPP; - m_iVertPadding = iVertPadding; - - m_ActualRows = new T *[iHeight + iVertPadding*2]; - m_Rows = m_ActualRows + iVertPadding; - memset(m_ActualRows, 0, sizeof(T *) * (iHeight + iVertPadding*2)); - - return true; - } - - /* Return row, allocating if necessary. */ - T *GetRow(int Row) - { - assert(m_BPP > 0); - - if(m_Rows[Row] == NULL) - { - m_Rows[Row] = new T[m_Width*m_BPP]; - if(Row == 0) - { - for(int i = -m_iVertPadding; i < 0; ++i) - m_Rows[i] = m_Rows[0]; - } - if(Row == m_Height - 1) - { - for(int i = m_Height; i < m_Height + m_iVertPadding; ++i) - m_Rows[i] = m_Rows[m_Height - 1]; - } - if(m_Rows[Row] == NULL) - return NULL; - if(m_StartRow == m_EndRow) - { - m_StartRow = Row; - m_EndRow = m_StartRow + 1; - } - } - - if(int(Row) == m_StartRow+1) - { - while(m_StartRow != 0 && m_Rows[m_StartRow-1]) - --m_StartRow; - } - - if(int(Row) == m_EndRow) - { - while(m_EndRow < m_Height && m_Rows[m_EndRow]) - ++m_EndRow; - } - return m_Rows[Row]; - } - - // Free rows [0,DiscardRow). - void DiscardRows(int DiscardRow) - { - assert(m_BPP > 0); - if(DiscardRow > m_Height) - DiscardRow = m_Height; - - for(int i = m_StartRow; i < DiscardRow; ++i) - { - delete [] m_Rows[i]; - m_Rows[i] = NULL; - } - - m_StartRow = max(m_StartRow, DiscardRow); - m_EndRow = max(m_EndRow, DiscardRow); - } - - /* Get a range of rows allocated in m_Rows: [m_StartRow,m_EndRow). If - * more than one allocated range exists, which range is returned is undefined. */ - int GetStartRow() const { return m_StartRow; } - int GetEndRow() const { return m_EndRow; } - const T *const *GetRows() const { return m_Rows; } - -private: - /* Array of image rows. These are allocated as needed. */ - T **m_Rows; - - /* The actual pointer m_Rows is contained in. m_Rows may be offset from this to - * implement padding. */ - T **m_ActualRows; - - /* in m_Rows is allocated: */ - int m_StartRow; - int m_EndRow; - - int m_Width; - int m_Height; - int m_BPP; - int m_iVertPadding; -}; - -#endif - diff --git a/lib/danbooru_image_resizer/danbooru_image_resizer.cpp b/lib/danbooru_image_resizer/danbooru_image_resizer.cpp deleted file mode 100644 index cca12b6e0..000000000 --- a/lib/danbooru_image_resizer/danbooru_image_resizer.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include -#include -#include -#include -using namespace std; -#include "PNGReader.h" -#include "GIFReader.h" -#include "JPEGReader.h" -#include "Resize.h" -#include "Histogram.h" -#include "ConvertToRGB.h" - -static VALUE danbooru_module; - -static Reader *GetReader(const char *file_ext) -{ - if (!strcmp(file_ext, "jpg") || !strcmp(file_ext, "jpeg")) - return new JPEG; - if (!strcmp(file_ext, "gif")) - return new GIF; - if (!strcmp(file_ext, "png")) - return new PNG; - return NULL; -} - -static VALUE danbooru_resize_image(VALUE module, VALUE file_ext_val, VALUE read_path_val, VALUE write_path_val, - VALUE output_width_val, VALUE output_height_val, - VALUE output_quality_val) -{ - const char * file_ext = StringValueCStr(file_ext_val); - const char * read_path = StringValueCStr(read_path_val); - const char * write_path = StringValueCStr(write_path_val); - int output_width = NUM2INT(output_width_val); - int output_height = NUM2INT(output_height_val); - int output_quality = NUM2INT(output_quality_val); - - FILE *read_file = fopen(read_path, "rb"); - if(read_file == NULL) - rb_raise(rb_eIOError, "can't open %s\n", read_path); - - FILE *write_file = fopen(write_path, "wb"); - if(write_file == NULL) - { - fclose(read_file); - rb_raise(rb_eIOError, "can't open %s\n", write_path); - } - - bool ret = false; - char error[1024]; - - try - { - auto_ptr pReader(GetReader(file_ext)); - if(pReader.get() == NULL) - { - strcpy(error, "unknown filetype"); - goto cleanup; - } - - auto_ptr pFilter(NULL); - - { - auto_ptr pCompressor(new JPEGCompressor(write_file)); - pCompressor->SetQuality(output_quality); - pFilter.reset(pCompressor.release()); - } - - { - auto_ptr pResizer(new Resizer(pFilter)); - pResizer->SetDest(output_width, output_height); - pFilter.reset(pResizer.release()); - } - - - { - auto_ptr pConverter(new ConvertToRGB(pFilter)); - pFilter.reset(pConverter.release()); - } - - ret = pReader->Read(read_file, pFilter.get(), error); - } - catch(const std::bad_alloc &e) - { - strcpy(error, "out of memory"); - } - -cleanup: - fclose(read_file); - fclose(write_file); - - if(!ret) - rb_raise(rb_eException, "%s", error); - - return INT2FIX(0); -} - -static VALUE danbooru_histogram(VALUE module, VALUE file_ext_val, VALUE read_path_val) -{ - const char * file_ext = StringValueCStr(file_ext_val); - const char * read_path = StringValueCStr(read_path_val); - - FILE *read_file = fopen(read_path, "rb"); - if(read_file == NULL) - rb_raise(rb_eIOError, "can't open %s\n", read_path); - - bool ret = false; - char error[1024]; - VALUE results = Qnil; - - try - { - auto_ptr pReader(GetReader(file_ext)); - if(pReader.get() == NULL) - { - strcpy(error, "unknown filetype"); - goto cleanup; - } - - auto_ptr pFilter(NULL); - - Histogram *pHistogram = new Histogram(); - pFilter.reset(pHistogram); - - { - auto_ptr pConverter(new ConvertToRGB(pFilter)); - pFilter.reset(pConverter.release()); - } - - ret = pReader->Read(read_file, pFilter.get(), error); - - results = rb_ary_new(); - int channels = pHistogram->GetChannels(); - for(int channel = 0; channel < channels; ++channel) - { - const unsigned *pChannelData = pHistogram->GetHistogram(channel); - VALUE channel_array = rb_ary_new(); - rb_ary_push(results, channel_array); - - for(int i = 0; i < 256; ++i) - rb_ary_push(channel_array, INT2NUM(pChannelData[i])); - } - } - catch(const std::bad_alloc &e) - { - strcpy(error, "out of memory"); - } - -cleanup: - fclose(read_file); - - if(!ret) - rb_raise(rb_eException, "%s", error); - - return results; -} - -extern "C" void Init_danbooru_image_resizer() { - danbooru_module = rb_define_module("Danbooru"); - rb_define_module_function(danbooru_module, "resize_image", (VALUE(*)(...))danbooru_resize_image, 6); - rb_define_module_function(danbooru_module, "histogram", (VALUE(*)(...))danbooru_histogram, 2); -} diff --git a/lib/danbooru_image_resizer/danbooru_image_resizer.rb b/lib/danbooru_image_resizer/danbooru_image_resizer.rb index c7da3dc4c..badfe6163 100644 --- a/lib/danbooru_image_resizer/danbooru_image_resizer.rb +++ b/lib/danbooru_image_resizer/danbooru_image_resizer.rb @@ -1,34 +1,49 @@ -begin - require 'danbooru_image_resizer/danbooru_image_resizer.so' -rescue LoadError - require 'danbooru_image_resizer/danbooru_image_resizer_fallback' -end - module Danbooru - def resize(file_ext, read_path, write_path, output_size, output_quality) - Danbooru.resize_image(file_ext, read_path, write_path, output_size[:width], output_size[:height], output_quality) - end - - def reduce_to(size, max_size, ratio = 1) - ret = size.dup + def resize(read_path, write_path, width, height, resize_quality = 90) + image = Magick::Image.read(read_path).first - if ret[:width] > ratio * max_size[:width] - scale = max_size[:width].to_f / ret[:width].to_f - ret[:width] = ret[:width] * scale - ret[:height] = ret[:height] * scale - end - - if max_size[:height] && (ret[:height] > ratio * max_size[:height]) - scale = max_size[:height].to_f / ret[:height].to_f - ret[:width] = ret[:width] * scale - ret[:height] = ret[:height] * scale + if width == Danbooru.config.small_image_width + image.change_geometry("#{width}x#{height}>") do |small_width, small_height, img| + img.thumbnail!(small_width, small_height) + width = small_width + height = small_height + end + else + image.change_geometry("#{width}x>") do |new_width, new_height, img| + img.resize!(new_width, new_height) + width = new_width + height = new_height + end end - ret[:width] = ret[:width].to_i - ret[:height] = ret[:height].to_i - ret + image = flatten(image, width, height) + + image.write(write_path) do + self.quality = resize_quality + end + + image.destroy! + end + + def flatten(image, width, height) + if image.alpha? + # since jpeg can't represent transparency, we need to create an image list, + # put a white image on the bottom, then flatten it. + + list = Magick::ImageList.new + list.new_image(width, height) do + self.background_color = "#FFFFFF" + end + list << image + flattened_image = list.flatten_images + list.each do |image| + image.destroy! + end + return flattened_image + else + return image + end end - module_function :resize - module_function :reduce_to + module_function :resize, :flatten end diff --git a/lib/danbooru_image_resizer/danbooru_image_resizer_fallback.rb b/lib/danbooru_image_resizer/danbooru_image_resizer_fallback.rb deleted file mode 100644 index e305cc066..000000000 --- a/lib/danbooru_image_resizer/danbooru_image_resizer_fallback.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Danbooru - def resize_image(extension, original_path, destination_path, width, height, quality) - require 'mini_magick' - image = MiniMagick::Image.open(original_path) - image.resize "#{width}x#{height}" - image.format extension - image.write destination_path - end - - def is_fallback - end - - module_function :resize_image, :is_fallback -end diff --git a/lib/danbooru_image_resizer/extconf.rb b/lib/danbooru_image_resizer/extconf.rb deleted file mode 100644 index a690b9141..000000000 --- a/lib/danbooru_image_resizer/extconf.rb +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/env ruby - -require 'mkmf' - -CONFIG['CC'] = "g++" -CONFIG['LDSHARED'] = CONFIG['LDSHARED'].sub(/^cc /,'g++ ') # otherwise we would not link with the C++ runtime - -dir_config("gd") -dir_config("jpeg") -dir_config("png") - -have_header("gd.h") - -have_library("gd") -have_library("jpeg") -have_library("png") - -have_func("gdImageCreateFromGif", "gd.h") -have_func("gdImageJpeg", "gd.h") -have_func("jpeg_set_quality", ["stdlib.h", "stdio.h", "jpeglib-extern.h"]) -have_func("png_set_expand_gray_1_2_4_to_8", "png.h") - -with_cflags("-O2 -Wall") {true} -#with_cflags("-O0 -g -fno-exceptions -Wall") {true} - -create_makefile("danbooru_image_resizer") diff --git a/lib/danbooru_image_resizer/jpeglib-extern.h b/lib/danbooru_image_resizer/jpeglib-extern.h deleted file mode 100644 index de92d4009..000000000 --- a/lib/danbooru_image_resizer/jpeglib-extern.h +++ /dev/null @@ -1,16 +0,0 @@ -// Needed for OS X - -#ifndef JPEGLIB_EXTERN_H -#define JPEGLIB_EXTERN_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/danbooru_image_resizer/test.rb b/lib/danbooru_image_resizer/test.rb deleted file mode 100644 index c0d41cf66..000000000 --- a/lib/danbooru_image_resizer/test.rb +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env ruby - -require 'danbooru_image_resizer' -Danbooru.resize_image("jpg", "test.jpg", "test-out.jpg", 2490, 3500, 95) - diff --git a/test/unit/download_test.rb b/test/unit/download_test.rb index f8debf26e..708d0b9a3 100644 --- a/test/unit/download_test.rb +++ b/test/unit/download_test.rb @@ -38,4 +38,17 @@ class DownloadTest < ActiveSupport::TestCase assert_match(/image\/gif/, @download.content_type) end end + + context "a post download for a pixiv manga page" do + setup do + @source = "http://img65.pixiv.net/img/kiyoringo/21755794_p2.png" + @tempfile = Tempfile.new("danbooru-test") + @download = Download.new(@source, @tempfile.path) + end + + should "download the big version" do + @download.download! + assert_equal("http://img65.pixiv.net/img/kiyoringo/21755794_big_p2.png", @download.source) + end + end end diff --git a/test/unit/note_test.rb b/test/unit/note_test.rb index 1719dee83..8927eacf1 100644 --- a/test/unit/note_test.rb +++ b/test/unit/note_test.rb @@ -60,7 +60,7 @@ class NoteTest < ActiveSupport::TestCase assert_nil(@post.last_noted_at) @note.update_attributes(:x => 1000) @post.reload - assert_equal(@post.last_noted_at, @note.updated_at) + assert_equal(@post.last_noted_at.to_i, @note.updated_at.to_i) end should "create a version" do diff --git a/test/unit/pixiv_proxy_test.rb b/test/unit/pixiv_proxy_test.rb index 3e4f0ba69..1e5452a24 100644 --- a/test/unit/pixiv_proxy_test.rb +++ b/test/unit/pixiv_proxy_test.rb @@ -13,16 +13,5 @@ class PixivProxyTest < ActiveSupport::TestCase assert(first_tag[0] =~ /./) assert(first_tag[1] =~ /tags\.php\?tag=/) end - - should "get a manga page" do - url ="http://img65.pixiv.net/img/kiyoringo/21755794_p2.png" - results = PixivProxy.get_single(url) - assert_equal("member.php?id=4015", results[:profile_url]) - assert(results[:jp_tags].size > 0) - first_tag = results[:jp_tags][0] - assert_equal(2, first_tag.size) - assert(first_tag[0] =~ /./) - assert(first_tag[1] =~ /tags\.php\?tag=/) - end end end diff --git a/test/unit/upload_test.rb b/test/unit/upload_test.rb index 360f00644..271783bb3 100644 --- a/test/unit/upload_test.rb +++ b/test/unit/upload_test.rb @@ -110,22 +110,12 @@ class UploadTest < ActiveSupport::TestCase @upload.calculate_hash(@upload.file_path) @upload.calculate_dimensions(@upload.file_path) assert_nothing_raised {@upload.generate_resizes(@upload.file_path)} - unless Danbooru.respond_to? :is_fallback - assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.small_image_width))) - assert_equal(7265, File.size(@upload.resized_file_path_for(Danbooru.config.small_image_width))) - assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.medium_image_width))) - assert_equal(43474, File.size(@upload.resized_file_path_for(Danbooru.config.medium_image_width))) - assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.large_image_width))) - assert_equal(198583, File.size(@upload.resized_file_path_for(Danbooru.config.large_image_width))) - else - # Different set of expected file sizes due to using a different compression algorithm - assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.small_image_width))) - assert_equal(7405, File.size(@upload.resized_file_path_for(Danbooru.config.small_image_width))) - assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.medium_image_width))) - assert_equal(43577, File.size(@upload.resized_file_path_for(Danbooru.config.medium_image_width))) - assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.large_image_width))) - assert_equal(198666, File.size(@upload.resized_file_path_for(Danbooru.config.large_image_width))) - end + assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.small_image_width))) + assert_equal(4817, File.size(@upload.resized_file_path_for(Danbooru.config.small_image_width))) + assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.medium_image_width))) + assert_equal(42990, File.size(@upload.resized_file_path_for(Danbooru.config.medium_image_width))) + assert(File.exists?(@upload.resized_file_path_for(Danbooru.config.large_image_width))) + assert_equal(197046, File.size(@upload.resized_file_path_for(Danbooru.config.large_image_width))) end end