refactored resizer to use imagemagick, fixed some tests
This commit is contained in:
5
Gemfile
5
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "ConvertToRGB.h"
|
||||
#include "Filter.h"
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
ConvertToRGB::ConvertToRGB(auto_ptr<Filter> 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);
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef CONVERT_TO_RGB_H
|
||||
#define CONVERT_TO_RGB_H
|
||||
|
||||
#include "Filter.h"
|
||||
#include <memory>
|
||||
using namespace std;
|
||||
|
||||
class ConvertToRGB: public Filter
|
||||
{
|
||||
public:
|
||||
ConvertToRGB(auto_ptr<Filter> 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<Filter> m_pCompressor;
|
||||
int m_iSourceWidth;
|
||||
int m_iBPP;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef FILTER_H
|
||||
#define FILTER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
@@ -1,60 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <gd.h>
|
||||
#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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -1,48 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "Histogram.h"
|
||||
#include "Filter.h"
|
||||
#include <algorithm>
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef HISTOGRAM_H
|
||||
#define HISTOGRAM_H
|
||||
|
||||
#include "Filter.h"
|
||||
#include <memory>
|
||||
using namespace std;
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
@@ -1,180 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "JPEGReader.h"
|
||||
#include "Resize.h"
|
||||
#include <algorithm>
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#ifndef JPEG_READER_H
|
||||
#define JPEG_READER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <setjmp.h>
|
||||
#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
|
||||
@@ -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
|
||||
@@ -1,139 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "PNGReader.h"
|
||||
#include "Resize.h"
|
||||
#include <algorithm>
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#ifndef PNG_READER_H
|
||||
#define PNG_READER_H
|
||||
|
||||
#include <png.h>
|
||||
#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<uint8_t> 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
|
||||
@@ -1,14 +0,0 @@
|
||||
#ifndef READER_H
|
||||
#define READER_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class Filter;
|
||||
class Reader
|
||||
{
|
||||
public:
|
||||
virtual ~Reader() { }
|
||||
virtual bool Read(FILE *f, Filter *rp, char errorbuf[1024]) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,286 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "Resize.h"
|
||||
#include "Filter.h"
|
||||
#include <algorithm>
|
||||
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<m_iTaps; ++i)
|
||||
pOutput[i] /= fSum;
|
||||
|
||||
pOutput += m_iTaps;
|
||||
}
|
||||
}
|
||||
|
||||
const float *LanczosFilter::GetFilter(float fOffset) const
|
||||
{
|
||||
int iOffset = int(fOffset * 256.0f);
|
||||
iOffset %= 256;
|
||||
return m_pFilters + iOffset*m_iTaps;
|
||||
}
|
||||
|
||||
Resizer::Resizer(auto_ptr<Filter> 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;
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef RESIZE_H
|
||||
#define RESIZE_H
|
||||
|
||||
#include "RowBuffer.h"
|
||||
#include "Filter.h"
|
||||
#include <memory>
|
||||
using namespace std;
|
||||
#include <stdint.h>
|
||||
|
||||
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<Filter> 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<Filter> m_pCompressor;
|
||||
uint8_t *m_OutBuf;
|
||||
RowBuffer<float> 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
|
||||
@@ -1,137 +0,0 @@
|
||||
#ifndef ROW_BUFFER_H
|
||||
#define ROW_BUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "RowBuffer.h"
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
template<typename T>
|
||||
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
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
#include <ruby.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <memory>
|
||||
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<Reader> pReader(GetReader(file_ext));
|
||||
if(pReader.get() == NULL)
|
||||
{
|
||||
strcpy(error, "unknown filetype");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
auto_ptr<Filter> pFilter(NULL);
|
||||
|
||||
{
|
||||
auto_ptr<JPEGCompressor> pCompressor(new JPEGCompressor(write_file));
|
||||
pCompressor->SetQuality(output_quality);
|
||||
pFilter.reset(pCompressor.release());
|
||||
}
|
||||
|
||||
{
|
||||
auto_ptr<Resizer> pResizer(new Resizer(pFilter));
|
||||
pResizer->SetDest(output_width, output_height);
|
||||
pFilter.reset(pResizer.release());
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
auto_ptr<ConvertToRGB> 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<Reader> pReader(GetReader(file_ext));
|
||||
if(pReader.get() == NULL)
|
||||
{
|
||||
strcpy(error, "unknown filetype");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
auto_ptr<Filter> pFilter(NULL);
|
||||
|
||||
Histogram *pHistogram = new Histogram();
|
||||
pFilter.reset(pHistogram);
|
||||
|
||||
{
|
||||
auto_ptr<ConvertToRGB> 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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")
|
||||
@@ -1,16 +0,0 @@
|
||||
// Needed for OS X
|
||||
|
||||
#ifndef JPEGLIB_EXTERN_H
|
||||
#define JPEGLIB_EXTERN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <jpeglib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'danbooru_image_resizer'
|
||||
Danbooru.resize_image("jpg", "test.jpg", "test-out.jpg", 2490, 3500, 95)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user