This source file includes following definitions.
- _JPEGFatalErrorHandler
- _JPEGErrorHandler
- _JPEGErrorHandler2
- load_jpeg
- small_light_filter_imlib2_init
- small_light_filter_imlib2_receive_data
- small_light_filter_imlib2_output_data
#include "mod_small_light.h"
#include "mod_small_light_ext_jpeg.h"
#define X_DISPLAY_MISSING
#include "Imlib2.h"
#ifdef ENABLE_JPEG
#include "jpeglib.h"
#include <setjmp.h>
#endif
small_light_filter_prototype(imlib2);
#ifndef ENABLE_IMLIB2
small_light_filter_dummy_template(imlib2);
#else
#ifdef ENABLE_JPEG
# define IMAGE_DIMENSIONS_OK(w, h) \
( ((w) > 0) && ((h) > 0) && \
((unsigned long long)(w) * (unsigned long long)(h) <= (1ULL << 29) - 1) )
struct ImLib_JPEG_error_mgr {
struct jpeg_error_mgr pub;
sigjmp_buf setjmp_buffer;
};
typedef struct ImLib_JPEG_error_mgr *emptr;
static void
_JPEGFatalErrorHandler(j_common_ptr cinfo)
{
emptr errmgr;
errmgr = (emptr) cinfo->err;
siglongjmp(errmgr->setjmp_buffer, 1);
return;
}
static void
_JPEGErrorHandler(j_common_ptr cinfo)
{
emptr errmgr;
errmgr = (emptr) cinfo->err;
return;
}
static void
_JPEGErrorHandler2(j_common_ptr cinfo, int msg_level)
{
emptr errmgr;
errmgr = (emptr) cinfo->err;
return;
msg_level = 0;
}
static int
load_jpeg(
void **dest_data, int *width, int *height, const request_rec *r,
const char *filename, int hint_w, int hint_h)
{
int w, h;
struct jpeg_decompress_struct cinfo;
struct ImLib_JPEG_error_mgr jerr;
FILE *f;
apr_status_t rv;
apr_file_t *file;
apr_os_file_t os_file;
*dest_data = NULL;
*width = *height = 0;
rv = apr_file_open(
&file, filename, APR_READ | APR_BINARY | APR_BUFFERED,
APR_UREAD, r->pool);
if (rv != APR_SUCCESS) {
return 0;
}
rv = apr_os_file_get(&os_file, file);
if (rv != APR_SUCCESS) {
return 0;
}
f = fdopen(os_file, "rb");
cinfo.err = jpeg_std_error(&(jerr.pub));
jerr.pub.error_exit = _JPEGFatalErrorHandler;
jerr.pub.emit_message = _JPEGErrorHandler2;
jerr.pub.output_message = _JPEGErrorHandler;
if (sigsetjmp(jerr.setjmp_buffer, 1))
{
jpeg_destroy_decompress(&cinfo);
apr_file_close(file);
return 0;
}
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, f);
jpeg_read_header(&cinfo, TRUE);
cinfo.do_fancy_upsampling = FALSE;
cinfo.do_block_smoothing = FALSE;
jpeg_start_decompress(&cinfo);
w = cinfo.output_width;
h = cinfo.output_height;
int denom;
denom = w / hint_w;
if (denom > h / hint_h) {
denom = h / hint_h;
}
denom = denom >= 1 ? denom : 1;
denom = denom <= 8 ? denom : 8;
jpeg_destroy_decompress(&cinfo);
fseek(f, 0, SEEK_SET);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, f);
jpeg_read_header(&cinfo, TRUE);
cinfo.do_fancy_upsampling = FALSE;
cinfo.do_block_smoothing = FALSE;
cinfo.scale_denom = denom;
jpeg_start_decompress(&cinfo);
DATA8 *ptr, *line[16], *data;
DATA32 *ptr2, *dest;
int x, y, l, i, scans, count, prevy;
w = cinfo.output_width;
h = cinfo.output_height;
if ((cinfo.rec_outbuf_height > 16) || (cinfo.output_components <= 0) ||
!IMAGE_DIMENSIONS_OK(w, h))
{
jpeg_destroy_decompress(&cinfo);
apr_file_close(file);
return 0;
}
data = apr_palloc(r->pool, w * 16 * cinfo.output_components);
if (!data)
{
jpeg_destroy_decompress(&cinfo);
apr_file_close(file);
return 0;
}
ptr2 = dest = apr_palloc(r->pool, w * h * sizeof(DATA32));
if (!dest)
{
jpeg_destroy_decompress(&cinfo);
apr_file_close(file);
return 0;
}
count = 0;
prevy = 0;
if (cinfo.output_components > 1)
{
for (i = 0; i < cinfo.rec_outbuf_height; i++)
line[i] = data + (i * w * cinfo.output_components);
for (l = 0; l < h; l += cinfo.rec_outbuf_height)
{
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
scans = cinfo.rec_outbuf_height;
if ((h - l) < scans)
scans = h - l;
ptr = data;
for (y = 0; y < scans; y++)
{
for (x = 0; x < w; x++)
{
*ptr2 =
(0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) <<
8) |
(ptr[2]);
ptr += cinfo.output_components;
ptr2++;
}
}
}
}
else if (cinfo.output_components == 1)
{
for (i = 0; i < cinfo.rec_outbuf_height; i++)
line[i] = data + (i * w);
for (l = 0; l < h; l += cinfo.rec_outbuf_height)
{
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
scans = cinfo.rec_outbuf_height;
if ((h - l) < scans)
scans = h - l;
ptr = data;
for (y = 0; y < scans; y++)
{
for (x = 0; x < w; x++)
{
*ptr2 =
(0xff000000) | ((ptr[0]) << 16) | ((ptr[0]) <<
8) |
(ptr[0]);
ptr++;
ptr2++;
}
}
}
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
apr_file_close(file);
*dest_data = dest;
*width = w;
*height = h;
return 1;
}
#endif
static const char temp_file_template[] = "small_light.XXXXXX";
typedef struct {
const char *temp_dir;
char *filename;
apr_file_t *file;
apr_size_t image_len;
} small_light_module_imlib2_ctx_t;
apr_status_t small_light_filter_imlib2_init(
ap_filter_t *f,
apr_bucket_brigade *bb,
void *v_ctx)
{
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "small_light_filter_imlib2_init");
request_rec *r = f->r;
small_light_module_ctx_t *ctx = (small_light_module_ctx_t*)v_ctx;
small_light_module_imlib2_ctx_t *lctx = ctx->lctx;
if (ctx->lctx == NULL) {
ctx->lctx = lctx =
(small_light_module_imlib2_ctx_t *)apr_pcalloc(
r->pool, sizeof(small_light_module_imlib2_ctx_t));
}
return APR_SUCCESS;
}
apr_status_t small_light_filter_imlib2_receive_data(
ap_filter_t *f,
apr_bucket_brigade *bb,
void *v_ctx,
apr_bucket *e,
const char *data,
apr_size_t len)
{
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "small_light_filter_imlib2_receive_data %d", len);
request_rec *r = f->r;
small_light_module_ctx_t* ctx = (small_light_module_ctx_t*)v_ctx;
small_light_module_imlib2_ctx_t *lctx = ctx->lctx;
apr_status_t rv;
if (lctx->file == NULL) {
rv = apr_temp_dir_get(&lctx->temp_dir, r->pool);
if (rv == APR_SUCCESS) {
rv = apr_filepath_merge(&lctx->filename, lctx->temp_dir, temp_file_template, APR_FILEPATH_TRUENAME, r->pool);
}
if (rv == APR_SUCCESS) {
rv = apr_file_mktemp(&lctx->file, lctx->filename, 0, r->pool);
}
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "could not create temporary file. %s", lctx->filename);
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
}
if (len > 0) {
apr_size_t num_writes = len;
apr_file_write(lctx->file, data, &num_writes);
if (num_writes < 0) {
ap_log_rerror(
APLOG_MARK, APLOG_ERR, 0, r,
"an error occured while writing data to temporary file %d", num_writes);
apr_file_close(lctx->file);
lctx->file = NULL;
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
}
lctx->image_len += len;
return APR_SUCCESS;
}
apr_status_t small_light_filter_imlib2_output_data(
ap_filter_t *f,
apr_bucket_brigade *bb,
void *v_ctx,
apr_bucket *e)
{
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, "small_light_filter_imlib2_output_data");
request_rec *r = f->r;
small_light_module_ctx_t *ctx = (small_light_module_ctx_t*)v_ctx;
small_light_module_imlib2_ctx_t *lctx = ctx->lctx;
apr_status_t rv;
struct timeval t2, t21, t22, t23, t3;
if (lctx->file == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "no data received");
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
gettimeofday(&t2, NULL);
small_light_image_size_t sz;
small_light_calc_image_size(&sz, r, ctx, 10000.0, 10000.0);
gettimeofday(&t21, NULL);
Imlib_Image image_org;
#ifdef ENABLE_JPEG
if (sz.jpeghint_flg != 0) {
void *data;
int w, h;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "load_jpeg");
if (!load_jpeg((void**)&data, &w, &h, r, lctx->filename, sz.dw, sz.dh)) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "load_jpeg_mem failed. uri=%s", r->uri);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "imlib_load_image_immediately_without_cache(%s)", lctx->filename);
image_org = imlib_load_image_immediately_without_cache(lctx->filename);
if (image_org == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "imlib_load_image failed. uri=%s", r->uri);
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
} else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "imlib_create_image_using_data(%d, %d, data)", w, h);
image_org = imlib_create_image_using_data(w, h, data);
}
} else {
#endif
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "imlib_load_image_immediately_without_cache(%s)", lctx->filename);
image_org = imlib_load_image_immediately_without_cache(lctx->filename);
if (image_org == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "imlib_load_image failed. uri=%s", r->uri);
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
#ifdef ENABLE_JPEG
}
#endif
gettimeofday(&t22, NULL);
imlib_context_set_image(image_org);
double iw = (double)imlib_image_get_width();
double ih = (double)imlib_image_get_height();
small_light_calc_image_size(&sz, r, ctx, iw, ih);
unsigned char *exif_data = NULL;
unsigned int exif_size = 0;
if (sz.inhexif_flg != 0) {
apr_mmap_t *org_image_mmap = NULL;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "open mmap");
rv = apr_mmap_create(&org_image_mmap, lctx->file, 0, lctx->image_len, APR_MMAP_READ, r->pool);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "open mmap failed. uri=%s", r->uri);
r->status = HTTP_INTERNAL_SERVER_ERROR;
return rv;
}
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "load exif");
load_exif_from_memory(&exif_data, &exif_size, r, org_image_mmap->mm, lctx->image_len);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "close mmap");
apr_mmap_delete(org_image_mmap);
if (exif_size > 0) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Exif found. size = %d", exif_size);
}
}
if (sz.pt_flg != 0) {
apr_mmap_t *org_image_mmap = NULL;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "open mmap");
rv = apr_mmap_create(&org_image_mmap, lctx->file, 0, lctx->image_len, APR_MMAP_READ, r->pool);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "open mmap failed. uri=%s", r->uri);
r->status = HTTP_INTERNAL_SERVER_ERROR;
return rv;
}
apr_bucket *b = apr_bucket_pool_create(org_image_mmap->mm, lctx->image_len, r->pool, ctx->bb->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
APR_BRIGADE_INSERT_TAIL(ctx->bb, apr_bucket_eos_create(ctx->bb->bucket_alloc));
return ap_pass_brigade(f->next, ctx->bb);
}
apr_file_close(lctx->file);
lctx->file = NULL;
Imlib_Image image_dst;
if (sz.scale_flg != 0) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"imlib_create_cropped_scaled_image(%f,%f,%f,%f,%f,%f)",
sz.sx, sz.sy, sz.sw, sz.sh, sz.dw, sz.dh);
image_dst = imlib_create_cropped_scaled_image(
(int)sz.sx, (int)sz.sy, (int)sz.sw, (int)sz.sh, (int)sz.dw, (int)sz.dh
);
imlib_context_set_image(image_org);
imlib_free_image();
} else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "no scale");
image_dst = image_org;
}
if (image_dst == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "imlib_create_cropped_scaled_image failed. uri=%s", r->uri);
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
if (sz.cw > 0.0 && sz.ch > 0.0) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "imlib_create_image(%f, %f)", sz.cw, sz.ch);
Imlib_Image image_tmp = imlib_create_image(sz.cw, sz.ch);
if (image_tmp == NULL) {
imlib_context_set_image(image_dst);
imlib_free_image();
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"imlib_create_image failed. uri=%s", r->uri);
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
imlib_context_set_image(image_tmp);
imlib_context_set_color(sz.cc.r, sz.cc.g, sz.cc.b, sz.cc.a);
imlib_image_fill_rectangle(0, 0, sz.cw, sz.ch);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"imlib_blend_image_onto_image(image_dst,255,0,0,%f,%f,%f,%f,%f,%f)",
sz.dw, sz.dh, sz.dx, sz.dy, sz.dw, sz.dh);
imlib_blend_image_onto_image(image_dst, 255, 0, 0,
(int)sz.dw, (int)sz.dh, (int)sz.dx, (int)sz.dy, (int)sz.dw, (int)sz.dh);
imlib_context_set_image(image_dst);
imlib_free_image();
image_dst = image_tmp;
}
char *sharpen = (char *)apr_table_get(ctx->prm, "sharpen");
if (sharpen) {
int radius = small_light_parse_int(r, sharpen);
if (radius > 0) {
imlib_context_set_image(image_dst);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"imlib_image_sharpen(%df)", radius);
imlib_image_sharpen(radius);
}
}
char *blur = (char *)apr_table_get(ctx->prm, "blur");
if (blur) {
int radius = small_light_parse_int(r, blur);
if (blur > 0) {
imlib_context_set_image(image_dst);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"imlib_image_sharpen(%df)", radius);
imlib_image_blur(radius);
}
}
if (sz.bw > 0.0 || sz.bh > 0.0) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "draw border");
imlib_context_set_color(sz.bc.r, sz.bc.g, sz.bc.b, sz.bc.a);
imlib_context_set_image(image_dst);
imlib_image_fill_rectangle(0, 0, sz.cw, sz.bh);
imlib_image_fill_rectangle(0, 0, sz.bw, sz.ch);
imlib_image_fill_rectangle(0, sz.ch - sz.bh, sz.cw, sz.bh);
imlib_image_fill_rectangle(sz.cw - sz.bw, 0, sz.bw, sz.ch);
}
gettimeofday(&t23, NULL);
imlib_context_set_image(image_dst);
double q = small_light_parse_double(r, (char *)apr_table_get(ctx->prm, "q"));
if (q > 0.0) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"imlib_image_attach_data_value('quality', NULL, %f, NULL)", q);
imlib_image_attach_data_value("quality", NULL, q, NULL);
}
char *of = (char *)apr_table_get(ctx->prm, "of");
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"imlib_image_set_format('%s')", of);
imlib_image_set_format(of);
char *sled_image_filename;
apr_file_t *sled_image_fp = NULL;
rv = apr_filepath_merge(&sled_image_filename, lctx->temp_dir, temp_file_template, APR_FILEPATH_TRUENAME, r->pool);
if (rv == APR_SUCCESS) {
rv = apr_file_mktemp(&sled_image_fp, sled_image_filename, 0, r->pool);
}
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "could not create temporary file.");
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
Imlib_Load_Error err;
imlib_save_image_with_error_return(sled_image_filename, &err);
imlib_free_image();
if (err != IMLIB_LOAD_ERROR_NONE) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "imlib_save_error failed. uri=%s", r->uri);
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
apr_finfo_t sled_image_finfo;
apr_mmap_t *sled_image_mmap = NULL;
rv = apr_file_info_get(&sled_image_finfo, APR_FINFO_SIZE, sled_image_fp);
if (rv == APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "sled_image_finfo.size = %d", (int)sled_image_finfo.size);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "open mmap");
rv = apr_mmap_create(&sled_image_mmap, sled_image_fp, 0, sled_image_finfo.size, APR_MMAP_READ, r->pool);
}
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "open mmap failed. %s", r->uri);
r->status = HTTP_INTERNAL_SERVER_ERROR;
return APR_EGENERAL;
}
if (exif_size > 0 && exif_data) {
exif_brigade_insert_tail(exif_data, exif_size, sled_image_mmap->mm, sled_image_finfo.size, r, ctx->bb);
apr_bucket *b = apr_bucket_pool_create(sled_image_mmap->mm + 2, sled_image_finfo.size - 2, r->pool, ctx->bb->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
} else {
apr_bucket *b = apr_bucket_pool_create(sled_image_mmap->mm, sled_image_finfo.size, r->pool, ctx->bb->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
}
APR_BRIGADE_INSERT_TAIL(ctx->bb, apr_bucket_eos_create(ctx->bb->bucket_alloc));
char *cont_type = apr_psprintf(r->pool, "image/%s", of);
ap_set_content_type(r, cont_type);
ap_set_content_length(r, sled_image_finfo.size);
gettimeofday(&t3, NULL);
int info = small_light_parse_int(r, (char *)apr_table_get(ctx->prm, "info"));
if (info != SMALL_LIGHT_INT_INVALID_VALUE && info != 0) {
char *info = apr_psprintf(r->pool,
"transfer=%ldms, modify image=%ldms (load=%ldms, scale=%ldms, save=%ldms)",
small_light_timeval_diff(&ctx->t, &t2) / 1000L,
small_light_timeval_diff(&t2, &t3) / 1000L,
small_light_timeval_diff(&t21, &t22) / 1000L,
small_light_timeval_diff(&t22, &t23) / 1000L,
small_light_timeval_diff(&t23, &t3) / 1000L
);
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
"uri=%s, info=%s)", r->unparsed_uri, info);
apr_table_setn(r->headers_out, "X-SmallLight-Description", info);
}
return ap_pass_brigade(f->next, ctx->bb);
}
#endif