/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_JPEG
#include <jpeglib.h>
#endif
#ifdef HAVE_GIF
#include <gif_lib.h>
#endif
#define BUFFER_SIZE 4096
#define DEFAULT_JPEG_QUALITY 90
#define COL(red, green, blue) (((red) << 24) | ((green) << 16) | ((blue) << 8) | 0xFF)
#define COL_FULL(red, green, blue, alpha) (((red) << 24) | ((green) << 16) | ((blue) << 8) | (alpha))
#define COL_RED(col) ((col >> 24) & 0xFF)
#define COL_GREEN(col) ((col >> 16) & 0xFF)
#define COL_BLUE(col) ((col >> 8) & 0xFF)
#define COL_ALPHA(col) (col & 0xFF)
#ifndef MAX
#define MAX(x,y) (x) > (y) ? (x) : (y)
#endif
#ifndef MIN
#define MIN(x,y) (x) < (y) ? (x) : (y)
#endif
#ifndef ABS
#define ABS(x) ((x) < 0 ? -(x) : (x))
#endif
// MSVC does not have lrintf
#ifdef _MSC_VER
static inline int lrintf(float f) {
#ifdef _M_X64
return (int)((f > 0.0f) ? (f + 0.5f) : (f -0.5f));
#else
int i;
_asm {
fld f
fistp i
};
return i;
#endif
}
#endif
#define ROUND_FLOAT_TO_INT(x) lrintf(x)
#define EPSILON 1.0e-12
#define PI 3.14159265358979323846264338327950288419716939937510
#if defined(__GNUC__)
#define ARGUNUSED(arg) arg __attribute__((unused))
#else
#define ARGUNUSED(arg) arg
#endif
typedef uint32_t pix;
enum image_type {
UNKNOWN = 0,
JPEG,
GIF,
PNG,
BMP
};
// Resize algorithms
enum resize_type {
IMAGE_SCALE_TYPE_GD = 0,
IMAGE_SCALE_TYPE_GD_FIXED,
IMAGE_SCALE_TYPE_GM,
IMAGE_SCALE_TYPE_GM_FIXED
};
// Exif Orientation
enum orientation {
ORIENTATION_NORMAL = 1,
ORIENTATION_MIRROR_HORIZ,
ORIENTATION_180,
ORIENTATION_MIRROR_VERT,
ORIENTATION_MIRROR_HORIZ_270_CCW,
ORIENTATION_90_CCW,
ORIENTATION_MIRROR_HORIZ_90_CCW,
ORIENTATION_270_CCW
};
// BMP Compression methods
enum bmp_compression {
BMP_BI_RGB = 0,
BMP_BI_RLE8,
BMP_BI_RLE4,
BMP_BI_BITFIELDS,
BMP_BI_JPEG,
BMP_BI_PNG
};
typedef struct {
int colors[256];
} palette;
typedef struct {
Buffer *buf;
SV *path;
PerlIO *fh;
SV *sv_data;
int32_t sv_offset;
int32_t image_offset;
int32_t image_length;
int32_t type;
int32_t width;
int32_t height;
int32_t width_padding; // empty padding pixels to leave to maintain aspect
int32_t width_inner; // width of inner area when maintaining aspect
int32_t height_padding;
int32_t height_inner;
int32_t flipped;
int32_t bpp;
int32_t compression;
int32_t channels;
int32_t has_alpha;
int32_t orientation;
int32_t orientation_orig;
int32_t memory_used;
int32_t outbuf_size;
int32_t used; // How many times the object has been used to resize
pix *pixbuf; // Source image
pix *outbuf; // Resized image
pix *tmpbuf; // Temporary intermediate image
palette *palette;
// Resize options
int32_t memory_limit;
int32_t target_width;
int32_t target_height;
int32_t keep_aspect;
int32_t resize_type;
int32_t filter;
int32_t bgcolor;
#ifdef HAVE_JPEG
struct jpeg_decompress_struct *cinfo;
struct jpeg_error_mgr *jpeg_error_pub;
#endif
#ifdef HAVE_PNG
png_structp png_ptr;
png_infop info_ptr;
#endif
#ifdef HAVE_GIF
GifFileType *gif;
#endif
} image;
static inline pix
get_pix(image *im, int32_t x, int32_t y)
{
return (im->pixbuf[(y * im->width) + x]);
}
static inline void
put_pix(image *im, int32_t x, int32_t y, pix col)
{
im->outbuf[(y * im->target_width) + x] = col;
}
static inline void
put_pix_rotated(image *im, int32_t x, int32_t y, int32_t rotated_width, pix col)
{
im->outbuf[(y * rotated_width) + x] = col;
}
int image_init(HV *self, image *im);
int image_resize(image *im);
void image_downsize_gd(image *im);
void image_downsize_gd_fixed_point(image *im);
void image_downsize_gm(image *im);
void image_alloc(image *im, int width, int height);
void image_bgcolor_fill(pix *buf, int size, int bgcolor);
void image_finish(image *im);
inline void image_get_rotated_coords(image *im, int x, int y, int *ox, int *oy);
#ifdef HAVE_JPEG
int image_jpeg_read_header(image *im);
int image_jpeg_load(image *im);
void image_jpeg_save(image *im, const char *path, int quality);
void image_jpeg_to_sv(image *im, int quality, SV *sv_buf);
void image_jpeg_finish(image *im);
#endif
int image_bmp_read_header(image *im);
int image_bmp_load(image *im);
void image_bmp_finish(image *im);
#ifdef HAVE_GIF
int image_gif_read_header(image *im);
int image_gif_load(image *im);
void image_gif_finish(image *im);
#endif
#ifdef HAVE_PNG
int image_png_read_header(image *im);
int image_png_load(image *im);
void image_png_save(image *im, const char *path);
void image_png_to_sv(image *im, SV *sv_buf);
void image_png_finish(image *im);
#endif