int convert (MagickWand *input, MagickWand **output, convert_t *opts, unsigned char* data, size_t size) { if (convert_density(input, opts) != MagickPass) return -7; if (MagickReadImageBlob(input, data, size) != MagickPass) return -2; if (convert_adjoin(input, output, opts) != MagickPass) return -8; input = *output; uint32_t quality = 75; if(opts->quality != 0){ quality = opts->quality; } if(convert_quality(input, quality) != MagickPass) return -8; MagickResetIterator(input); MagickNextImage(input); // Has to be called after MagickResetIterator to set the first picture as the current do { if (convert_format(input, opts) != MagickPass) return -3; if (convert_crop(input, opts) != MagickPass) return -6; if (convert_scale(input, opts) != MagickPass) return -4; if (convert_rotate(input, opts) != MagickPass) return -5; } while (MagickNextImage(input)); return 0; }
int main(int argc,char **argv) { #define ThrowWandException(wand) \ { \ char \ *description; \ \ ExceptionType \ severity; \ \ description=MagickGetException(wand,&severity); \ (void) fprintf(stderr,"%s %s %ld %s\n",GetMagickModule(),description); \ description=(char *) MagickRelinquishMemory(description); \ exit(-1); \ } MagickBooleanType status; MagickWand *magick_wand; MagickWand *tmp_magick_wand; /* Read an image. */ size_t len; char *data; data = get_thumbnail(argv[1], argv[2], &len); MagickReadImageBlob(magick_wand, data, len); status=MagickWriteImages(magick_wand,argv[3],MagickTrue); if (status == MagickFalse) ThrowWandException(magick_wand); magick_wand=DestroyMagickWand(magick_wand); MagickWandTerminus(); return(0); }
static PyObject * im_LoadImageBlob(PyObject *self, PyObject *args) { void *magick_pointer; MagickWand *magick_wand; Py_ssize_t size; char *blob; MagickBooleanType status; if (!PyArg_ParseTuple(args, "Os#", &magick_pointer, &blob, &size)){ return Py_BuildValue("i", 0); } magick_wand = (MagickWand *) PyCObject_AsVoidPtr(magick_pointer); status = MagickReadImageBlob(magick_wand, blob, (size_t)size); if (status == MagickFalse){ return Py_BuildValue("i", 0); } return Py_BuildValue("i", 1); }
int convert2jpg(const char *buff, const int len,const char *path){ //http://members.shaw.ca/el.supremo/MagickWand/resize.htm //MagickGetImageFormat MagickWand *m_wand = NULL; m_wand = NewMagickWand(); MagickReadImageBlob(m_wand, buff, len); //strip exif,GPS data MagickStripImage(m_wand); // Set the compression quality to 75 (high quality = low compression) MagickSetImageCompressionQuality(m_wand,75); /* Write the new image */ MagickWriteImage(m_wand,path); /* Clean up */ if(m_wand)m_wand = DestroyMagickWand(m_wand); return ZIMG_OK; }
/** * @brief get_img_mode_db Get image from db mode backend. * * @param req zimg request struct * @param buff_ptr buff pointer * @param img_size buff size * * @return 1 for success and -1 for failed */ int get_img_mode_db(zimg_req_t *req, evhtp_request_t *request) { int result = -1; char cache_key[CACHE_KEY_SIZE]; char *img_format = NULL; char *buff_ptr = NULL; size_t img_size; MagickBooleanType status; MagickWand *magick_wand = NULL; bool got_rsp = true; bool got_color = false; LOG_PRINT(LOG_DEBUG, "get_img() start processing zimg request..."); if(req->gray == 1) { gen_key(cache_key, req->md5, 4, req->width, req->height, req->proportion, req->gray); } else { if(req->proportion == 0 && req->width == 0 && req->height == 0) { gen_key(cache_key, req->md5, 0); } else { gen_key(cache_key, req->md5, 3, req->width, req->height, req->proportion); } } if(find_cache_bin(req->thr_arg, cache_key, &buff_ptr, &img_size) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Cache[Key: %s].", cache_key); goto done; } LOG_PRINT(LOG_DEBUG, "Start to Find the Image..."); if(get_img_db(req->thr_arg, cache_key, &buff_ptr, &img_size) == 1) { LOG_PRINT(LOG_DEBUG, "Get image [%s] from backend db succ.", cache_key); if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } goto done; } magick_wand = NewMagickWand(); got_rsp = false; if(req->gray == 1) { gen_key(cache_key, req->md5, 3, req->width, req->height, req->proportion); if(find_cache_bin(req->thr_arg, cache_key, &buff_ptr, &img_size) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Color Image Cache[Key: %s, len: %d].", cache_key, img_size); status = MagickReadImageBlob(magick_wand, buff_ptr, img_size); free(buff_ptr); buff_ptr = NULL; if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Color Image Cache[Key: %s] is Bad. Remove.", cache_key); del_cache(req->thr_arg, cache_key); } else { got_color = true; LOG_PRINT(LOG_DEBUG, "Read Image from Color Image Cache[Key: %s, len: %d] Succ. Goto Convert.", cache_key, img_size); goto convert; } } if(get_img_db(req->thr_arg, cache_key, &buff_ptr, &img_size) == 1) { LOG_PRINT(LOG_DEBUG, "Get color image [%s] from backend db.", cache_key); status = MagickReadImageBlob(magick_wand, buff_ptr, img_size); if(status == MagickTrue) { got_color = true; LOG_PRINT(LOG_DEBUG, "Read Image from Color Image[%s] Succ. Goto Convert.", cache_key); if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } free(buff_ptr); buff_ptr = NULL; goto convert; } } } gen_key(cache_key, req->md5, 0); if(find_cache_bin(req->thr_arg, cache_key, &buff_ptr, &img_size) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Cache[Key: %s].", cache_key); } else { if(get_img_db(req->thr_arg, cache_key, &buff_ptr, &img_size) == -1) { LOG_PRINT(LOG_DEBUG, "Get image [%s] from backend db failed.", cache_key); goto err; } else if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } } status = MagickReadImageBlob(magick_wand, buff_ptr, img_size); free(buff_ptr); buff_ptr = NULL; if(status == MagickFalse) { ThrowWandException(magick_wand); del_cache(req->thr_arg, cache_key); LOG_PRINT(LOG_DEBUG, "Read image [%s] from blob failed.", cache_key); goto err; } if(req->width == 0 && req->height == 0) { LOG_PRINT(LOG_DEBUG, "Image [%s] needn't resize. Goto Convert.", cache_key); goto convert; } int width, height; width = req->width; height = req->height; float owidth = MagickGetImageWidth(magick_wand); float oheight = MagickGetImageHeight(magick_wand); if(width <= owidth && height <= oheight) { if(req->proportion == 1 || (req->proportion == 0 && req->width * req->height == 0)) { if(req->height == 0) { height = width * oheight / owidth; } else { width = height * owidth / oheight; } } status = MagickResizeImage(magick_wand, width, height, LanczosFilter, 1.0); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Image[%s] Resize Failed!", cache_key); goto err; } LOG_PRINT(LOG_DEBUG, "Resize img succ."); } else { got_rsp = true; LOG_PRINT(LOG_DEBUG, "Args width/height is bigger than real size, return original image."); } convert: //compress image if(got_color == false) { LOG_PRINT(LOG_DEBUG, "Start to Compress the Image!"); img_format = MagickGetImageFormat(magick_wand); LOG_PRINT(LOG_DEBUG, "Image Format is %s", img_format); if(strcmp(img_format, "JPEG") != 0) { LOG_PRINT(LOG_DEBUG, "Convert Image Format from %s to JPEG.", img_format); status = MagickSetImageFormat(magick_wand, "JPEG"); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Image[%s] Convert Format Failed!", cache_key); } LOG_PRINT(LOG_DEBUG, "Compress Image with JPEGCompression"); status = MagickSetImageCompression(magick_wand, JPEGCompression); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Image[%s] Compression Failed!", cache_key); } } size_t quality = MagickGetImageCompressionQuality(magick_wand); LOG_PRINT(LOG_DEBUG, "Image Compression Quality is %u.", quality); if(quality > WAP_QUALITY) { quality = WAP_QUALITY; } LOG_PRINT(LOG_DEBUG, "Set Compression Quality to 75%."); status = MagickSetImageCompressionQuality(magick_wand, quality); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Set Compression Quality Failed!"); } //strip image EXIF infomation LOG_PRINT(LOG_DEBUG, "Start to Remove Exif Infomation of the Image..."); status = MagickStripImage(magick_wand); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Remove Exif Infomation of the ImageFailed!"); } buff_ptr = (char *)MagickGetImageBlob(magick_wand, &img_size); if(buff_ptr == NULL) { LOG_PRINT(LOG_DEBUG, "Magick Get Image Blob Failed!"); goto err; } gen_key(cache_key, req->md5, 3, req->width, req->height, req->proportion); if(got_rsp == false) { save_img_db(req->thr_arg, cache_key, buff_ptr, img_size); } if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } if(req->gray == 1) { free(buff_ptr); buff_ptr = NULL; } else { goto done; } } //gray image if(req->gray == 1) { LOG_PRINT(LOG_DEBUG, "Start to Remove Color!"); status = MagickSetImageColorspace(magick_wand, GRAYColorspace); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Image[%s] Remove Color Failed!", cache_key); goto err; } LOG_PRINT(LOG_DEBUG, "Image Remove Color Finish!"); buff_ptr = (char *)MagickGetImageBlob(magick_wand, &img_size); if(buff_ptr == NULL) { LOG_PRINT(LOG_DEBUG, "Magick Get Image Blob Failed!"); goto err; } gen_key(cache_key, req->md5, 4, req->width, req->height, req->proportion, req->gray); if(got_rsp == false) { save_img_db(req->thr_arg, cache_key, buff_ptr, img_size); } if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } } done: result = evbuffer_add(request->buffer_out, buff_ptr, img_size); if(result != -1) { result = 1; } err: if(magick_wand) { magick_wand=DestroyMagickWand(magick_wand); } if(img_format) free(img_format); if(buff_ptr) free(buff_ptr); return result; }
// output_data apr_status_t small_light_filter_imagemagick_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_imagemagick_output_data"); request_rec *r = f->r; small_light_module_ctx_t* ctx = (small_light_module_ctx_t*)v_ctx; small_light_module_imagemagick_ctx_t *lctx = ctx->lctx; struct timeval t2, t21, t22, t23, t3; MagickBooleanType status = MagickFalse; // check data received. if (lctx->image == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "no data received."); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } // start image modifing. gettimeofday(&t2, NULL); small_light_image_size_t sz; small_light_calc_image_size(&sz, r, ctx, 10000.0, 10000.0); // init wand small_light_filter_imagemagick_output_data_init(); lctx->wand = NewMagickWand(); // prepare. if (sz.jpeghint_flg != 0) { char *jpeg_size_opt = (char *)apr_psprintf(r->pool, "%dx%d", (int)sz.dw, (int)sz.dh); MagickSetOption(lctx->wand, "jpeg:size", jpeg_size_opt); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickSetOption(jpeg:size, %s)", jpeg_size_opt); } // load image. gettimeofday(&t21, NULL); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickReadImageBlob"); status = MagickReadImageBlob(lctx->wand, (void *)lctx->image, lctx->image_len); if (status == MagickFalse) { small_light_filter_imagemagick_output_data_fini(ctx); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "couldn't read image"); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } // calc size. gettimeofday(&t22, NULL); double iw = (double)MagickGetImageWidth(lctx->wand); double ih = (double)MagickGetImageHeight(lctx->wand); small_light_calc_image_size(&sz, r, ctx, iw, ih); // pass through. if (sz.pt_flg != 0) { small_light_filter_imagemagick_output_data_fini(ctx); apr_bucket *b = apr_bucket_pool_create(lctx->image, 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); } // crop, scale. status = MagickTrue; if (sz.scale_flg != 0) { char *crop_geo = (char *)apr_psprintf(r->pool, "%f!x%f!+%f+%f", sz.sw, sz.sh, sz.sx, sz.sy); char *size_geo = (char *)apr_psprintf(r->pool, "%f!x%f!", sz.dw, sz.dh); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickTransformImage(wand, ""%s"", ""%s"")", crop_geo, size_geo); MagickWand *trans_wand; trans_wand = MagickTransformImage(lctx->wand, crop_geo, size_geo); if (trans_wand == NULL || trans_wand == lctx->wand) { small_light_filter_imagemagick_output_data_fini(ctx); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "MagickTransformImage failed"); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } DestroyMagickWand(lctx->wand); lctx->wand = trans_wand; } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "no scale"); } // create canvas then draw image to the canvas. if (sz.cw > 0.0 && sz.ch > 0.0) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "NewMagickWand()"); MagickWand *canvas_wand = NewMagickWand(); PixelWand *canvas_color = NewPixelWand(); PixelSetRed(canvas_color, sz.cc.r / 255.0); PixelSetGreen(canvas_color, sz.cc.g / 255.0); PixelSetBlue(canvas_color, sz.cc.b / 255.0); PixelSetAlpha(canvas_color, sz.cc.a / 255.0); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickNewImage(canvas_wand, %f, %f, bgcolor)", sz.cw, sz.ch); status = MagickNewImage(canvas_wand, sz.cw, sz.ch, canvas_color); DestroyPixelWand(canvas_color); if (status == MagickFalse) { small_light_filter_imagemagick_output_data_fini(ctx); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "MagickNewImage(canvas_wand, %f, %f, bgcolor) failed", sz.cw, sz.ch); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickCompositeImage(canvas_wand, wand, AtopCompositeOp, %f, %f)", sz.dx, sz.dy); status = MagickCompositeImage(canvas_wand, lctx->wand, AtopCompositeOp, sz.dx, sz.dy); if (status == MagickFalse) { small_light_filter_imagemagick_output_data_fini(ctx); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "MagickCompositeImage(canvas_wand, wand, AtopCompositeOp, %f, %f) failed", sz.dx, sz.dy); r->status = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } DestroyMagickWand(lctx->wand); lctx->wand = canvas_wand; } // effects. char *unsharp = (char *)apr_table_get(ctx->prm, "unsharp"); if (unsharp) { GeometryInfo geo; ParseGeometry(unsharp, &geo); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickUnsharpMaskImage(wand, %f, %f, %f, %f)", geo.rho, geo.sigma, geo.xi, geo.psi); status = MagickUnsharpMaskImage(lctx->wand, geo.rho, geo.sigma, geo.xi, geo.psi); if (status == MagickFalse) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unsharp failed"); } } char *sharpen = (char *)apr_table_get(ctx->prm, "sharpen"); if (sharpen) { GeometryInfo geo; ParseGeometry(sharpen, &geo); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickSharpenImage(wand, %f, %f)", geo.rho, geo.sigma); status = MagickSharpenImage(lctx->wand, geo.rho, geo.sigma); if (status == MagickFalse) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "sharpen failed"); } } char *blur = (char *)apr_table_get(ctx->prm, "blur"); if (blur) { GeometryInfo geo; ParseGeometry(blur, &geo); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickBlurImage(wand, %f, %f)", geo.rho, geo.sigma); status = MagickBlurImage(lctx->wand, geo.rho, geo.sigma); if (status == MagickFalse) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "blur failed"); } } // border. if (sz.bw > 0.0 || sz.bh > 0.0) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "draw border"); DrawingWand *border_wand = NewDrawingWand(); PixelWand *border_color; border_color = NewPixelWand(); PixelSetRed(border_color, sz.bc.r / 255.0); PixelSetGreen(border_color, sz.bc.g / 255.0); PixelSetBlue(border_color, sz.bc.b / 255.0); PixelSetAlpha(border_color, sz.bc.a / 255.0); DrawSetFillColor(border_wand, border_color); DrawSetStrokeColor(border_wand, border_color); DrawSetStrokeWidth(border_wand, 1); DrawRectangle(border_wand, 0, 0, sz.cw - 1, sz.bh - 1); DrawRectangle(border_wand, 0, 0, sz.bw - 1, sz.ch - 1); DrawRectangle(border_wand, 0, sz.ch - sz.bh, sz.cw - 1, sz.ch - 1); DrawRectangle(border_wand, sz.cw - sz.bw, 0, sz.cw - 1, sz.ch - 1); MagickDrawImage(lctx->wand, border_wand); DestroyPixelWand(border_color); DestroyDrawingWand(border_wand); } gettimeofday(&t23, NULL); // set params. 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, "MagickSetImageComressionQualty(wand, %f)", q); MagickSetImageCompressionQuality(lctx->wand, q); } char *of = (char *)apr_table_get(ctx->prm, "of"); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "MagickSetFormat(wand, '%s')", of); MagickSetFormat(lctx->wand, of); // get small_lighted image as binary. unsigned char *canvas_buff; const char *sled_image; size_t sled_image_size; canvas_buff = MagickGetImageBlob(lctx->wand, &sled_image_size); sled_image = (const char *)apr_pmemdup(r->pool, canvas_buff, sled_image_size); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "sled_image_size = %d", sled_image_size); // free buffer and wand. MagickRelinquishMemory(canvas_buff); small_light_filter_imagemagick_output_data_fini(ctx); // insert new bucket to bucket brigade. apr_bucket *b = apr_bucket_pool_create(sled_image, sled_image_size, r->pool, ctx->bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(ctx->bb, b); // insert eos to bucket brigade. APR_BRIGADE_INSERT_TAIL(ctx->bb, apr_bucket_eos_create(ctx->bb->bucket_alloc)); // set correct Content-Type and Content-Length. char *cont_type = apr_psprintf(r->pool, "image/%s", of); ap_set_content_type(r, cont_type); ap_set_content_length(r, sled_image_size); // end. gettimeofday(&t3, NULL); // http header. 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 = (char *)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); }
/** * @brief get_img The function of getting a image buffer and it's length. * * @param req The zimg_req_t from zhttp and it has the params of a request. * @param buff_ptr This function return image buffer in it. * @param img_size Get_img will change this number to return the size of image buffer. * * @return 1 for success and -1 for fail. */ int get_img(zimg_req_t *req, evhtp_request_t *request) { int result = -1; char cache_key[CACHE_KEY_SIZE]; char *img_format = NULL; int fd = -1; struct stat f_stat; char *buff_ptr; size_t img_size; MagickBooleanType status; MagickWand *magick_wand = NULL; bool got_rsp = true; bool got_color = false; LOG_PRINT(LOG_DEBUG, "get_img() start processing zimg request..."); // to gen cache_key like this: 926ee2f570dc50b2575e35a6712b08ce:0:0:1:0 gen_key(cache_key, req->md5, 4, req->width, req->height, req->proportion, req->gray); if(find_cache_bin(req->thr_arg, cache_key, &buff_ptr, &img_size) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Cache[Key: %s].", cache_key); goto done; } LOG_PRINT(LOG_DEBUG, "Start to Find the Image..."); char whole_path[512]; int lvl1 = str_hash(req->md5); int lvl2 = str_hash(req->md5 + 3); snprintf(whole_path, 512, "%s/%d/%d/%s", settings.img_path, lvl1, lvl2, req->md5); LOG_PRINT(LOG_DEBUG, "docroot: %s", settings.img_path); LOG_PRINT(LOG_DEBUG, "req->md5: %s", req->md5); LOG_PRINT(LOG_DEBUG, "whole_path: %s", whole_path); char name[128]; if(req->proportion && req->gray) snprintf(name, 128, "%d*%dpg", req->width, req->height); else if(req->proportion && !req->gray) snprintf(name, 128, "%d*%dp", req->width, req->height); else if(!req->proportion && req->gray) snprintf(name, 128, "%d*%dg", req->width, req->height); else snprintf(name, 128, "%d*%d", req->width, req->height); char color_name[128]; if(req->proportion) snprintf(color_name, 128, "%d*%dp", req->width, req->height); else snprintf(color_name, 128, "%d*%d", req->width, req->height); char orig_path[512]; snprintf(orig_path, strlen(whole_path) + 6, "%s/0*0", whole_path); LOG_PRINT(LOG_DEBUG, "0rig File Path: %s", orig_path); char rsp_path[512]; if(req->width == 0 && req->height == 0 && req->proportion == 0 && req->gray == 0) { LOG_PRINT(LOG_DEBUG, "Return original image."); strncpy(rsp_path, orig_path, 512); } else { snprintf(rsp_path, 512, "%s/%s", whole_path, name); } LOG_PRINT(LOG_DEBUG, "Got the rsp_path: %s", rsp_path); char color_path[512]; snprintf(color_path, 512, "%s/%s", whole_path, color_name); //status=MagickReadImage(magick_wand, rsp_path); if((fd = open(rsp_path, O_RDONLY)) == -1) { magick_wand = NewMagickWand(); got_rsp = false; if(req->gray == 1) { gen_key(cache_key, req->md5, 3, req->width, req->height, req->proportion); if(find_cache_bin(req->thr_arg, cache_key, &buff_ptr, &img_size) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Color Image Cache[Key: %s, len: %d].", cache_key, img_size); status = MagickReadImageBlob(magick_wand, buff_ptr, img_size); free(buff_ptr); buff_ptr = NULL; if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Color Image Cache[Key: %s] is Bad. Remove.", cache_key); del_cache(req->thr_arg, cache_key); } else { got_color = true; LOG_PRINT(LOG_DEBUG, "Read Image from Color Image Cache[Key: %s, len: %d] Succ. Goto Convert.", cache_key, img_size); goto convert; } } status=MagickReadImage(magick_wand, color_path); if(status == MagickTrue) { got_color = true; LOG_PRINT(LOG_DEBUG, "Read Image from Color Image[%s] Succ. Goto Convert.", rsp_path); buff_ptr = (char *)MagickGetImageBlob(magick_wand, &img_size); if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } free(buff_ptr); buff_ptr = NULL; goto convert; } } // to gen cache_key like this: rsp_path-/926ee2f570dc50b2575e35a6712b08ce gen_key(cache_key, req->md5, 0); if(find_cache_bin(req->thr_arg, cache_key, &buff_ptr, &img_size) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Orignal Image Cache[Key: %s].", cache_key); status = MagickReadImageBlob(magick_wand, buff_ptr, img_size); free(buff_ptr); buff_ptr = NULL; if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Open Original Image From Blob Failed! Begin to Open it From Disk."); ThrowWandException(magick_wand); del_cache(req->thr_arg, cache_key); status = MagickReadImage(magick_wand, orig_path); if(status == MagickFalse) { ThrowWandException(magick_wand); goto err; } else { buff_ptr = (char *)MagickGetImageBlob(magick_wand, &img_size); if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } free(buff_ptr); buff_ptr = NULL; } } } else { LOG_PRINT(LOG_DEBUG, "Not Hit Original Image Cache. Begin to Open it."); status = MagickReadImage(magick_wand, orig_path); if(status == MagickFalse) { ThrowWandException(magick_wand); goto err; } else { buff_ptr = (char *)MagickGetImageBlob(magick_wand, &img_size); if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } free(buff_ptr); buff_ptr = NULL; } } int width, height; width = req->width; height = req->height; if(width == 0 && height == 0) { LOG_PRINT(LOG_DEBUG, "Image[%s] needn't resize. Goto Convert.", orig_path); goto convert; } float owidth = MagickGetImageWidth(magick_wand); float oheight = MagickGetImageHeight(magick_wand); if(width <= owidth && height <= oheight) { if(req->proportion == 1 || (req->proportion == 0 && req->width * req->height == 0)) { if(req->height == 0) { height = width * oheight / owidth; } else { width = height * owidth / oheight; } } status = MagickResizeImage(magick_wand, width, height, LanczosFilter, 1.0); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Image[%s] Resize Failed!", orig_path); goto err; } LOG_PRINT(LOG_DEBUG, "Resize img succ."); } else { // Note this strcpy because rsp_path is not useful. We needn't to save the new image. got_rsp = true; LOG_PRINT(LOG_DEBUG, "Args width/height is bigger than real size, return original image."); } } else { fstat(fd, &f_stat); size_t rlen = 0; img_size = f_stat.st_size; if(img_size <= 0) { LOG_PRINT(LOG_DEBUG, "File[%s] is Empty.", rsp_path); goto err; } if((buff_ptr = (char *)malloc(img_size)) == NULL) { LOG_PRINT(LOG_DEBUG, "buff_ptr Malloc Failed!"); goto err; } LOG_PRINT(LOG_DEBUG, "img_size = %d", img_size); if((rlen = read(fd, buff_ptr, img_size)) == -1) { LOG_PRINT(LOG_DEBUG, "File[%s] Read Failed.", rsp_path); LOG_PRINT(LOG_DEBUG, "Error: %s.", strerror(errno)); goto err; } else if(rlen < img_size) { LOG_PRINT(LOG_DEBUG, "File[%s] Read Not Compeletly.", rsp_path); goto err; } if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } goto done; } convert: if(got_color == false) { //compress image LOG_PRINT(LOG_DEBUG, "Start to Compress the Image!"); img_format = MagickGetImageFormat(magick_wand); LOG_PRINT(LOG_DEBUG, "Image Format is %s", img_format); if(strcmp(img_format, "JPEG") != 0) { LOG_PRINT(LOG_DEBUG, "Convert Image Format from %s to JPEG.", img_format); status = MagickSetImageFormat(magick_wand, "JPEG"); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Image[%s] Convert Format Failed!", orig_path); } LOG_PRINT(LOG_DEBUG, "Compress Image with JPEGCompression"); status = MagickSetImageCompression(magick_wand, JPEGCompression); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Image[%s] Compression Failed!", orig_path); } } size_t quality = MagickGetImageCompressionQuality(magick_wand); LOG_PRINT(LOG_DEBUG, "Image Compression Quality is %u.", quality); if(quality > WAP_QUALITY) { quality = WAP_QUALITY; } LOG_PRINT(LOG_DEBUG, "Set Compression Quality to 75%."); status = MagickSetImageCompressionQuality(magick_wand, quality); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Set Compression Quality Failed!"); } //strip image EXIF infomation LOG_PRINT(LOG_DEBUG, "Start to Remove Exif Infomation of the Image..."); status = MagickStripImage(magick_wand); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Remove Exif Infomation of the ImageFailed!"); } buff_ptr = (char *)MagickGetImageBlob(magick_wand, &img_size); if(buff_ptr == NULL) { LOG_PRINT(LOG_DEBUG, "Magick Get Image Blob Failed!"); goto err; } gen_key(cache_key, req->md5, 3, req->width, req->height, req->proportion); if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } if(got_rsp == false) { LOG_PRINT(LOG_DEBUG, "Color Image[%s] is Not Existed. Begin to Save it.", color_path); if(new_img(buff_ptr, img_size, color_path) == -1) { LOG_PRINT(LOG_DEBUG, "Color Image[%s] Save Failed!", color_path); LOG_PRINT(LOG_WARNING, "fail save %s", color_path); } } if(req->gray == 1) { free(buff_ptr); buff_ptr = NULL; } else { goto done; } } //gray image if(req->gray == 1) { LOG_PRINT(LOG_DEBUG, "Start to Remove Color!"); status = MagickSetImageColorspace(magick_wand, GRAYColorspace); if(status == MagickFalse) { LOG_PRINT(LOG_DEBUG, "Image[%s] Remove Color Failed!", orig_path); goto err; } LOG_PRINT(LOG_DEBUG, "Image Remove Color Finish!"); buff_ptr = (char *)MagickGetImageBlob(magick_wand, &img_size); if(buff_ptr == NULL) { LOG_PRINT(LOG_DEBUG, "Magick Get Image Blob Failed!"); goto err; } gen_key(cache_key, req->md5, 4, req->width, req->height, req->proportion, req->gray); if(img_size < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, cache_key, buff_ptr, img_size); } if(got_rsp == false) { if(new_img(buff_ptr, img_size, rsp_path) == -1) { LOG_PRINT(LOG_DEBUG, "New Image[%s] Save Failed!", rsp_path); LOG_PRINT(LOG_WARNING, "fail save %s", rsp_path); } } else LOG_PRINT(LOG_DEBUG, "Image Needn't to Storage.", rsp_path); } done: result = evbuffer_add(request->buffer_out, buff_ptr, img_size); if(result != -1) { result = 1; } err: if(fd != -1) close(fd); if(magick_wand) { magick_wand=DestroyMagickWand(magick_wand); } if(img_format) free(img_format); if(buff_ptr) free(buff_ptr); return result; }
/** * @brief get_img get image from disk mode through the request * * @param req the zimg request * @param request the evhtp request * * @return 1 for OK, 2 for 304 needn't response buffer and -1 for failed */ int get_img(zimg_req_t *req, evhtp_request_t *request) { int result = -1; char rsp_cache_key[CACHE_KEY_SIZE]; int fd = -1; struct stat f_stat; char *buff = NULL; char *orig_buff = NULL; MagickWand *im = NULL; size_t len = 0; bool to_save = true; LOG_PRINT(LOG_DEBUG, "get_img() start processing zimg request..."); int lvl1 = str_hash(req->md5); int lvl2 = str_hash(req->md5 + 3); char whole_path[512]; snprintf(whole_path, 512, "%s/%d/%d/%s", settings.img_path, lvl1, lvl2, req->md5); LOG_PRINT(LOG_DEBUG, "whole_path: %s", whole_path); if(is_dir(whole_path) == -1) { LOG_PRINT(LOG_DEBUG, "Image %s is not existed!", req->md5); goto err; } if(settings.script_on == 1 && req->type != NULL) snprintf(rsp_cache_key, CACHE_KEY_SIZE, "%s:%s", req->md5, req->type); else { if(req->proportion == 0 && req->width == 0 && req->height == 0) str_lcpy(rsp_cache_key, req->md5, CACHE_KEY_SIZE); else gen_key(rsp_cache_key, req->md5, 9, req->width, req->height, req->proportion, req->gray, req->x, req->y, req->rotate, req->quality, req->fmt); } if(find_cache_bin(req->thr_arg, rsp_cache_key, &buff, &len) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Cache[Key: %s].", rsp_cache_key); to_save = false; goto done; } LOG_PRINT(LOG_DEBUG, "Start to Find the Image..."); char orig_path[512]; snprintf(orig_path, 512, "%s/0*0", whole_path); LOG_PRINT(LOG_DEBUG, "0rig File Path: %s", orig_path); char rsp_path[512]; if(settings.script_on == 1 && req->type != NULL) snprintf(rsp_path, 512, "%s/t_%s", whole_path, req->type); else { char name[128]; snprintf(name, 128, "%d*%d_p%d_g%d_%d*%d_r%d_q%d.%s", req->width, req->height, req->proportion, req->gray, req->x, req->y, req->rotate, req->quality, req->fmt); if(req->width == 0 && req->height == 0 && req->proportion == 0) { LOG_PRINT(LOG_DEBUG, "Return original image."); strncpy(rsp_path, orig_path, 512); } else { snprintf(rsp_path, 512, "%s/%s", whole_path, name); } } LOG_PRINT(LOG_DEBUG, "Got the rsp_path: %s", rsp_path); if((fd = open(rsp_path, O_RDONLY)) == -1) { im = NewMagickWand(); if (im == NULL) goto err; int ret; if(find_cache_bin(req->thr_arg, req->md5, &orig_buff, &len) == 1) { LOG_PRINT(LOG_DEBUG, "Hit Orignal Image Cache[Key: %s].", req->md5); ret = MagickReadImageBlob(im, (const unsigned char *)orig_buff, len); if (ret != MagickTrue) { LOG_PRINT(LOG_DEBUG, "Open Original Image From Blob Failed! Begin to Open it From Disk."); del_cache(req->thr_arg, req->md5); ret = MagickReadImage(im, orig_path); if (ret != MagickTrue) { LOG_PRINT(LOG_DEBUG, "Open Original Image From Disk Failed!"); goto err; } else { MagickSizeType size = MagickGetImageSize(im); LOG_PRINT(LOG_DEBUG, "image size = %d", size); if(size < CACHE_MAX_SIZE) { MagickResetIterator(im); char *new_buff = (char *)MagickWriteImageBlob(im, &len); if (new_buff == NULL) { LOG_PRINT(LOG_DEBUG, "Webimg Get Original Blob Failed!"); goto err; } set_cache_bin(req->thr_arg, req->md5, new_buff, len); free(new_buff); } } } } else { LOG_PRINT(LOG_DEBUG, "Not Hit Original Image Cache. Begin to Open it."); ret = MagickReadImage(im, orig_path); if (ret != MagickTrue) { LOG_PRINT(LOG_DEBUG, "Open Original Image From Disk Failed! %d != %d", ret, MagickTrue); LOG_PRINT(LOG_DEBUG, "Open Original Image From Disk Failed!"); goto err; } else { MagickSizeType size = MagickGetImageSize(im); LOG_PRINT(LOG_DEBUG, "image size = %d", size); if(size < CACHE_MAX_SIZE) { MagickResetIterator(im); char *new_buff = (char *)MagickWriteImageBlob(im, &len); if (new_buff == NULL) { LOG_PRINT(LOG_DEBUG, "Webimg Get Original Blob Failed!"); goto err; } set_cache_bin(req->thr_arg, req->md5, new_buff, len); free(new_buff); } } } if(settings.script_on == 1 && req->type != NULL) ret = lua_convert(im, req); else ret = convert(im, req); if(ret == -1) goto err; if(ret == 0) to_save = false; buff = (char *)MagickWriteImageBlob(im, &len); if (buff == NULL) { LOG_PRINT(LOG_DEBUG, "Webimg Get Blob Failed!"); goto err; } } else { to_save = false; fstat(fd, &f_stat); size_t rlen = 0; len = f_stat.st_size; if(len <= 0) { LOG_PRINT(LOG_DEBUG, "File[%s] is Empty.", rsp_path); goto err; } if((buff = (char *)malloc(len)) == NULL) { LOG_PRINT(LOG_DEBUG, "buff Malloc Failed!"); goto err; } LOG_PRINT(LOG_DEBUG, "img_size = %d", len); if((rlen = read(fd, buff, len)) == -1) { LOG_PRINT(LOG_DEBUG, "File[%s] Read Failed: %s", rsp_path, strerror(errno)); goto err; } else if(rlen < len) { LOG_PRINT(LOG_DEBUG, "File[%s] Read Not Compeletly.", rsp_path); goto err; } } //LOG_PRINT(LOG_INFO, "New Image[%s]", rsp_path); int save_new = 0; if(to_save == true) { if(req->sv == 1 || settings.save_new == 1 || (settings.save_new == 2 && req->type != NULL)) { save_new = 1; } } if(save_new == 1) { LOG_PRINT(LOG_DEBUG, "Image[%s] is Not Existed. Begin to Save it.", rsp_path); if(new_img(buff, len, rsp_path) == -1) { LOG_PRINT(LOG_DEBUG, "New Image[%s] Save Failed!", rsp_path); LOG_PRINT(LOG_WARNING, "fail save %s", rsp_path); } } else LOG_PRINT(LOG_DEBUG, "Image [%s] Needn't to Storage.", rsp_path); if(len < CACHE_MAX_SIZE) { set_cache_bin(req->thr_arg, rsp_cache_key, buff, len); } done: if(settings.etag == 1) { result = zimg_etag_set(request, buff, len); if(result == 2) goto err; } result = evbuffer_add(request->buffer_out, buff, len); if(result != -1) { result = 1; } err: if(fd != -1) close(fd); if(im != NULL) DestroyMagickWand(im); free(buff); free(orig_buff); return result; }
unsigned char* generate_thumbnail( const void *image, const size_t size, size_t *new_size ) { MagickWand *magick_wand, *magick_wand_canvas; PixelWand *pixel_wand; unsigned int cols, rows, ncols, nrows; unsigned char *new_blob; // Initialize MagickWand: MagickWandGenesis(); magick_wand = NewMagickWand(); magick_wand_canvas = NewMagickWand(); pixel_wand = NewPixelWand(); // Read image from memory: DoMagick( magick_wand, MagickReadImageBlob( magick_wand, image, size ) ); // If input consists of several images, we'll only take the first one: MagickResetIterator( magick_wand ); MagickSetFirstIterator( magick_wand ); // Get image size: cols = MagickGetImageWidth( magick_wand ); rows = MagickGetImageHeight( magick_wand ); printf("Image size: %ix%i\n", (int)cols, (int)rows); if (cols==0 || rows==0) { fprintf(stderr, "generateThumbnail: Warning, imagesize==0, skipping image...\n"); pixel_wand = DestroyPixelWand( pixel_wand ); magick_wand_canvas = DestroyMagickWand( magick_wand_canvas ); magick_wand = DestroyMagickWand( magick_wand ); MagickWandTerminus(); return NULL; } if (cols >= rows) { ncols = 98; nrows = (rows*98)/cols; } else { nrows = 98; ncols = (cols*98)/rows; } // Convert the image into a thumbnail: DoMagick( magick_wand, MagickThumbnailImage( magick_wand, ncols, nrows ) ); PixelSetColor( pixel_wand, "#8f7f6f" ); DoMagick( magick_wand, MagickBorderImage( magick_wand, pixel_wand, 1, 1 ) ); DoMagick( magick_wand, MagickSetImageBackgroundColor( magick_wand, pixel_wand ) ); PixelSetColor( pixel_wand, "white" ); DoMagick( magick_wand_canvas, MagickNewImage( magick_wand_canvas, 100, 100, pixel_wand ) ); DoMagick( magick_wand_canvas, MagickCompositeImage( magick_wand_canvas, magick_wand, OverCompositeOp, 49-(ncols/2), 49-(nrows/2) ) ); // DoMagick( magick_wand_canvas, MagickWriteImage( magick_wand_canvas, "thumbnail.png" ) ); DoMagick( magick_wand_canvas, MagickSetImageFormat( magick_wand_canvas, "PNG" ) ); new_blob = MagickGetImageBlob( magick_wand_canvas, new_size ); // unsigned char *MagickGetImageBlob(MagickWand *wand,size_t *length) pixel_wand = DestroyPixelWand( pixel_wand ); magick_wand = DestroyMagickWand( magick_wand ); magick_wand_canvas = DestroyMagickWand( magick_wand_canvas ); MagickWandTerminus(); return new_blob; }
/** * @brief get_img The function of getting a image buffer and it's length. * * @param req The zimg_req_t from zhttp and it has the params of a request. * @param buff_ptr This function return image buffer in it. * @param img_size Get_img will change this number to return the size of image buffer. * * @return ZIMG_OK for success and ZIMG_ERR for fail. */ int get_img(zimg_req_t *req, char **buff_ptr, size_t *img_size) { int result = -1; char *rsp_path = NULL; char *whole_path = NULL; char *orig_path = NULL; char *color_path = NULL; char *img_format = NULL; size_t len; int fd = -1; struct stat f_stat; MagickBooleanType status; MagickWand *magick_wand = NULL; LOG_PRINT(LOG_INFO, "get_img() start processing zimg request..."); char *cache_key = (char *)malloc(strlen(req->md5) + 32); if(cache_key == NULL){ LOG_PRINT(LOG_INFO, "malloc failed!"); return ZIMG_ERR; } // to gen cache_key like this: img:926ee2f570dc50b2575e35a6712b08ce:0:0:1:0 sprintf(cache_key, "img:%s:%d:%d:%d:%d", req->md5, req->width, req->height, req->proportion, req->gray); if(find_cache_bin(cache_key, buff_ptr, img_size) == 1){ LOG_PRINT(LOG_INFO, "Hit Cache[Key: %s].", cache_key); // sprintf(cache_key, "type:%s:%d:%d:%d:%d", req->md5, req->width, req->height, req->proportion, req->gray); // if(find_cache(cache_key, img_format) == -1) // { // LOG_PRINT(LOG_WARNING, "Cannot Hit Type Cache[Key: %s]. Use jpeg As Default.", cache_key); // strcpy(img_format, "jpeg"); // } free(cache_key); return ZIMG_OK; } free(cache_key); LOG_PRINT(LOG_INFO, "Start to Find the Image..."); //check img dir // /1023/1023/xxxxxxxxxxxxxxx.png len = strlen(req->md5) + strlen(settings.img_path) + 12; whole_path = malloc(len); if (whole_path == NULL){ LOG_PRINT(LOG_ERROR, "whole_path malloc failed!"); return ZIMG_ERR; } int lvl1 = str_hash(req->md5); int lvl2 = str_hash(req->md5 + 3); sprintf(whole_path, "%s/%d/%d/%s", settings.img_path, lvl1, lvl2, req->md5); LOG_PRINT(LOG_INFO, "docroot: %s", settings.img_path); LOG_PRINT(LOG_INFO, "req->md5: %s", req->md5); LOG_PRINT(LOG_INFO, "whole_path: %s", whole_path); char name[128]; if(req->proportion && req->gray) sprintf(name, "%d*%dpg", req->width, req->height); else if(req->proportion && !req->gray) sprintf(name, "%d*%dp", req->width, req->height); else if(!req->proportion && req->gray) sprintf(name, "%d*%dg", req->width, req->height); else sprintf(name, "%d*%d", req->width, req->height); orig_path = (char *)malloc(strlen(whole_path) + 6); sprintf(orig_path, "%s/0*0p", whole_path); LOG_PRINT(LOG_INFO, "0rig File Path: %s", orig_path); rsp_path = (char *)malloc(512); if(req->width == 0 && req->height == 0 && req->gray == 0) { LOG_PRINT(LOG_INFO, "Return original image."); strcpy(rsp_path, orig_path); } else { sprintf(rsp_path, "%s/%s", whole_path, name); } LOG_PRINT(LOG_INFO, "Got the rsp_path: %s", rsp_path); bool got_rsp = true; bool got_color = false; //status=MagickReadImage(magick_wand, rsp_path); if((fd = open(rsp_path, O_RDONLY)) == -1) //if(status == MagickFalse) { magick_wand = NewMagickWand(); got_rsp = false; if(req->gray == 1) { sprintf(cache_key, "img:%s:%d:%d:%d:0", req->md5, req->width, req->height, req->proportion); if(find_cache_bin(cache_key, buff_ptr, img_size) == 1) { LOG_PRINT(LOG_INFO, "Hit Color Image Cache[Key: %s, len: %d].", cache_key, *img_size); status = MagickReadImageBlob(magick_wand, *buff_ptr, *img_size); if(status == MagickFalse) { LOG_PRINT(LOG_WARNING, "Color Image Cache[Key: %s] is Bad. Remove.", cache_key); del_cache(cache_key); } else { got_color = true; LOG_PRINT(LOG_INFO, "Read Image from Color Image Cache[Key: %s, len: %d] Succ. Goto Convert.", cache_key, *img_size); goto convert; } } len = strlen(rsp_path); color_path = (char *)malloc(len); strncpy(color_path, rsp_path, len); color_path[len - 1] = '\0'; LOG_PRINT(LOG_INFO, "color_path: %s", color_path); status=MagickReadImage(magick_wand, color_path); if(status == MagickTrue) { got_color = true; LOG_PRINT(LOG_INFO, "Read Image from Color Image[%s] Succ. Goto Convert.", color_path); *buff_ptr = (char *)MagickGetImageBlob(magick_wand, img_size); if(*img_size < CACHE_MAX_SIZE) { set_cache_bin(cache_key, *buff_ptr, *img_size); // img_format = MagickGetImageFormat(magick_wand); // sprintf(cache_key, "type:%s:%d:%d:%d:0", req->md5, req->width, req->height, req->proportion); // set_cache(cache_key, img_format); } goto convert; } } // to gen cache_key like this: rsp_path-/926ee2f570dc50b2575e35a6712b08ce sprintf(cache_key, "img:%s:0:0:1:0", req->md5); if(find_cache_bin(cache_key, buff_ptr, img_size) == 1) { LOG_PRINT(LOG_INFO, "Hit Orignal Image Cache[Key: %s].", cache_key); status = MagickReadImageBlob(magick_wand, *buff_ptr, *img_size); if(status == MagickFalse) { LOG_PRINT(LOG_WARNING, "Open Original Image From Blob Failed! Begin to Open it From Disk."); ThrowWandException(magick_wand); del_cache(cache_key); status = MagickReadImage(magick_wand, orig_path); if(status == MagickFalse) { ThrowWandException(magick_wand); goto err; } else { *buff_ptr = (char *)MagickGetImageBlob(magick_wand, img_size); if(*img_size < CACHE_MAX_SIZE) { set_cache_bin(cache_key, *buff_ptr, *img_size); // img_format = MagickGetImageFormat(magick_wand); // sprintf(cache_key, "type:%s:0:0:1:0", req->md5); // set_cache(cache_key, img_format); } } } } else { LOG_PRINT(LOG_INFO, "Not Hit Original Image Cache. Begin to Open it."); status = MagickReadImage(magick_wand, orig_path); if(status == MagickFalse) { ThrowWandException(magick_wand); goto err; } else { *buff_ptr = (char *)MagickGetImageBlob(magick_wand, img_size); if(*img_size < CACHE_MAX_SIZE) { set_cache_bin(cache_key, *buff_ptr, *img_size); // img_format = MagickGetImageFormat(magick_wand); // sprintf(cache_key, "type:%s:0:0:1:0", req->md5); // set_cache(cache_key, img_format); } } } int width, height; width = req->width; height = req->height; float owidth = MagickGetImageWidth(magick_wand); float oheight = MagickGetImageHeight(magick_wand); if(width <= owidth && height <= oheight) { if(req->proportion == 1) { if(req->width != 0 && req->height == 0) { height = width * oheight / owidth; } //else if(height != 0 && width == 0) else { width = height * owidth / oheight; } } status = MagickResizeImage(magick_wand, width, height, LanczosFilter, 1.0); if(status == MagickFalse) { LOG_PRINT(LOG_ERROR, "Image[%s] Resize Failed!", orig_path); goto err; } LOG_PRINT(LOG_INFO, "Resize img succ."); } /* this section can caculate the correct rsp_path, but not use, so I note them else if(req->gray == true) { strcpy(rsp_path, orig_path); rsp_path[strlen(orig_path)] = 'g'; rsp_path[strlen(orig_path) + 1] = '\0'; got_rsp = true; LOG_PRINT(LOG_INFO, "Args width/height is bigger than real size, return original gray image."); LOG_PRINT(LOG_INFO, "Original Gray Image: %s", rsp_path); } */ else { // Note this strcpy because rsp_path is not useful. We needn't to save the new image. //strcpy(rsp_path, orig_path); got_rsp = true; LOG_PRINT(LOG_INFO, "Args width/height is bigger than real size, return original image."); } } else { fstat(fd, &f_stat); size_t rlen = 0; *img_size = f_stat.st_size; if(*img_size <= 0) { LOG_PRINT(LOG_ERROR, "File[%s] is Empty.", rsp_path); goto err; } if((*buff_ptr = (char *)malloc(*img_size)) == NULL) { LOG_PRINT(LOG_ERROR, "buff_ptr Malloc Failed!"); goto err; } LOG_PRINT(LOG_INFO, "img_size = %d", *img_size); //*buff_ptr = (char *)MagickGetImageBlob(magick_wand, img_size); if((rlen = read(fd, *buff_ptr, *img_size)) == -1) { LOG_PRINT(LOG_ERROR, "File[%s] Read Failed.", rsp_path); LOG_PRINT(LOG_ERROR, "Error: %s.", strerror(errno)); goto err; } else if(rlen < *img_size) { LOG_PRINT(LOG_ERROR, "File[%s] Read Not Compeletly.", rsp_path); goto err; } goto done; } convert: //gray image if(req->gray == true) { LOG_PRINT(LOG_INFO, "Start to Remove Color!"); status = MagickSetImageColorspace(magick_wand, GRAYColorspace); if(status == MagickFalse) { LOG_PRINT(LOG_ERROR, "Image[%s] Remove Color Failed!", orig_path); goto err; } LOG_PRINT(LOG_INFO, "Image Remove Color Finish!"); } if(got_color == false || (got_color == true && req->width == 0) ) { //compress image LOG_PRINT(LOG_INFO, "Start to Compress the Image!"); img_format = MagickGetImageFormat(magick_wand); LOG_PRINT(LOG_INFO, "Image Format is %s", img_format); if(strcmp(img_format, "JPEG") != 0) { LOG_PRINT(LOG_INFO, "Convert Image Format from %s to JPEG.", img_format); status = MagickSetImageFormat(magick_wand, "JPEG"); if(status == MagickFalse) { LOG_PRINT(LOG_WARNING, "Image[%s] Convert Format Failed!", orig_path); } LOG_PRINT(LOG_INFO, "Compress Image with JPEGCompression"); status = MagickSetImageCompression(magick_wand, JPEGCompression); if(status == MagickFalse) { LOG_PRINT(LOG_WARNING, "Image[%s] Compression Failed!", orig_path); } } size_t quality = MagickGetImageCompressionQuality(magick_wand) * 0.75; LOG_PRINT(LOG_INFO, "Image Compression Quality is %u.", quality); if(quality == 0) { quality = 75; } LOG_PRINT(LOG_INFO, "Set Compression Quality to 75%."); status = MagickSetImageCompressionQuality(magick_wand, quality); if(status == MagickFalse) { LOG_PRINT(LOG_WARNING, "Set Compression Quality Failed!"); } //strip image EXIF infomation LOG_PRINT(LOG_INFO, "Start to Remove Exif Infomation of the Image..."); status = MagickStripImage(magick_wand); if(status == MagickFalse) { LOG_PRINT(LOG_WARNING, "Remove Exif Infomation of the ImageFailed!"); } } *buff_ptr = (char *)MagickGetImageBlob(magick_wand, img_size); if(*buff_ptr == NULL) { LOG_PRINT(LOG_ERROR, "Magick Get Image Blob Failed!"); goto err; } done: if(*img_size < CACHE_MAX_SIZE) { // to gen cache_key like this: rsp_path-/926ee2f570dc50b2575e35a6712b08ce sprintf(cache_key, "img:%s:%d:%d:%d:%d", req->md5, req->width, req->height, req->proportion, req->gray); set_cache_bin(cache_key, *buff_ptr, *img_size); // sprintf(cache_key, "type:%s:%d:%d:%d:%d", req->md5, req->width, req->height, req->proportion, req->gray); // set_cache(cache_key, img_format); } result = 1; if(got_rsp == false) { LOG_PRINT(LOG_INFO, "Image[%s] is Not Existed. Begin to Save it.", rsp_path); result = 2; } else LOG_PRINT(LOG_INFO, "Image Needn't to Storage.", rsp_path); err: if(fd != -1) close(fd); req->rsp_path = rsp_path; if(magick_wand) { magick_wand=DestroyMagickWand(magick_wand); } if(img_format) free(img_format); if(cache_key) free(cache_key); if (orig_path) free(orig_path); if (whole_path) free(whole_path); return result; }
ngx_int_t ngx_http_small_light_imagemagick_process(ngx_http_request_t *r, ngx_http_small_light_ctx_t *ctx) { ngx_http_small_light_imagemagick_ctx_t *ictx; ngx_http_small_light_image_size_t sz; MagickBooleanType status; int rmprof_flg, progressive_flg, cmyk2rgb_flg; double iw, ih, q; char *unsharp, *sharpen, *blur, *of, *of_orig; MagickWand *trans_wand, *canvas_wand; DrawingWand *border_wand; PixelWand *bg_color, *canvas_color, *border_color; GeometryInfo geo; ngx_fd_t fd; MagickWand *icon_wand; u_char *p, *embedicon; size_t embedicon_path_len, embedicon_len, sled_image_size; ngx_int_t type; u_char jpeg_size_opt[32], crop_geo[128], size_geo[128], embedicon_path[256]; ColorspaceType color_space; #if MagickLibVersion >= 0x690 int autoorient_flg; #endif status = MagickFalse; ictx = (ngx_http_small_light_imagemagick_ctx_t *)ctx->ictx; /* adjust image size */ ngx_http_small_light_calc_image_size(r, ctx, &sz, 10000.0, 10000.0); /* prepare */ if (sz.jpeghint_flg != 0) { p = ngx_snprintf((u_char *)jpeg_size_opt, sizeof(jpeg_size_opt) - 1, "%dx%d", (ngx_int_t)sz.dw, (ngx_int_t)sz.dh); *p = '\0'; ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "jpeg_size_opt:%s", jpeg_size_opt); MagickSetOption(ictx->wand, "jpeg:size", (char *)jpeg_size_opt); } /* load image. */ status = MagickReadImageBlob(ictx->wand, (void *)ictx->image, ictx->image_len); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "couldn't read image %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } MagickSetFirstIterator(ictx->wand); color_space = MagickGetImageColorspace(ictx->wand); /* remove all profiles */ rmprof_flg = ngx_http_small_light_parse_flag(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "rmprof")); if (rmprof_flg != 0) { status = MagickProfileImage(ictx->wand, "*", NULL, 0); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "couldn't profiling image %s:%d", __FUNCTION__, __LINE__); } } of_orig = MagickGetImageFormat(ictx->wand); status = MagickTrue; #if MagickLibVersion >= 0x690 /* auto-orient */ autoorient_flg = ngx_http_small_light_parse_flag(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "autoorient")); if (autoorient_flg != 0) { status = MagickAutoOrientImage(ictx->wand); if (status == MagickFalse) { r->err_status = NGX_HTTP_INTERNAL_SERVER_ERROR; DestroyString(of_orig); return NGX_ERROR; } } #endif /* rotate. */ if (sz.angle) { bg_color = NewPixelWand(); PixelSetRed(bg_color, sz.cc.r / 255.0); PixelSetGreen(bg_color, sz.cc.g / 255.0); PixelSetBlue(bg_color, sz.cc.b / 255.0); PixelSetAlpha(bg_color, sz.cc.a / 255.0); switch (sz.angle) { case 90: case 180: case 270: MagickRotateImage(ictx->wand, bg_color, sz.angle); break; default: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "image not rotated. 'angle'(%ui) must be 90 or 180 or 270. %s:%d", sz.angle, __FUNCTION__, __LINE__); break; } DestroyPixelWand(bg_color); } /* calc size. */ iw = (double)MagickGetImageWidth(ictx->wand); ih = (double)MagickGetImageHeight(ictx->wand); ngx_http_small_light_calc_image_size(r, ctx, &sz, iw, ih); /* pass through. */ if (sz.pt_flg != 0) { ctx->of = ctx->inf; DestroyString(of_orig); return NGX_OK; } /* crop, scale. */ if (sz.scale_flg != 0) { p = ngx_snprintf(crop_geo, sizeof(crop_geo) - 1, "%f!x%f!+%f+%f", sz.sw, sz.sh, sz.sx, sz.sy); *p = '\0'; p = ngx_snprintf(size_geo, sizeof(size_geo) - 1, "%f!x%f!", sz.dw, sz.dh); *p = '\0'; ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "crop_geo:%s", crop_geo); ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "size_geo:%s", size_geo); MagickResetImagePage(ictx->wand, "+0+0"); trans_wand = MagickTransformImage(ictx->wand, (char *)crop_geo, (char *)size_geo); if (trans_wand == NULL || trans_wand == ictx->wand) { r->err_status = NGX_HTTP_INTERNAL_SERVER_ERROR; DestroyString(of_orig); return NGX_ERROR; } DestroyMagickWand(ictx->wand); ictx->wand = trans_wand; } /* create canvas then draw image to the canvas. */ if (sz.cw > 0.0 && sz.ch > 0.0) { canvas_wand = NewMagickWand(); canvas_color = NewPixelWand(); PixelSetRed(canvas_color, sz.cc.r / 255.0); PixelSetGreen(canvas_color, sz.cc.g / 255.0); PixelSetBlue(canvas_color, sz.cc.b / 255.0); PixelSetAlpha(canvas_color, sz.cc.a / 255.0); status = MagickNewImage(canvas_wand, sz.cw, sz.ch, canvas_color); DestroyPixelWand(canvas_color); if (status == MagickFalse) { r->err_status = NGX_HTTP_INTERNAL_SERVER_ERROR; DestroyMagickWand(canvas_wand); DestroyString(of_orig); return NGX_ERROR; } status = MagickTransformImageColorspace(canvas_wand, color_space); if (status == MagickFalse) { r->err_status = NGX_HTTP_INTERNAL_SERVER_ERROR; DestroyMagickWand(canvas_wand); DestroyString(of_orig); return NGX_ERROR; } status = MagickCompositeImage(canvas_wand, ictx->wand, AtopCompositeOp, sz.dx, sz.dy); if (status == MagickFalse) { r->err_status = NGX_HTTP_INTERNAL_SERVER_ERROR; DestroyMagickWand(canvas_wand); DestroyString(of_orig); return NGX_ERROR; } DestroyMagickWand(ictx->wand); ictx->wand = canvas_wand; } /* CMYK to sRGB */ cmyk2rgb_flg = ngx_http_small_light_parse_flag(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "cmyk2rgb")); if (cmyk2rgb_flg != 0 && color_space == CMYKColorspace) { status = MagickTransformImageColorspace(ictx->wand, sRGBColorspace); if (status == MagickFalse) { r->err_status = NGX_HTTP_INTERNAL_SERVER_ERROR; DestroyString(of_orig); return NGX_ERROR; } } /* effects. */ unsharp = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "unsharp"); if (ngx_strlen(unsharp) > 0) { ParseGeometry(unsharp, &geo); if (geo.rho > ctx->radius_max || geo.sigma > ctx->sigma_max) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "As unsharp geometry is too large, ignored. %s:%d", __FUNCTION__, __LINE__); } else { status = MagickUnsharpMaskImage(ictx->wand, geo.rho, geo.sigma, geo.xi, geo.psi); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unsharp failed %s:%d", __FUNCTION__, __LINE__); } } } sharpen = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "sharpen"); if (ngx_strlen(sharpen) > 0) { ParseGeometry(sharpen, &geo); if (geo.rho > ctx->radius_max || geo.sigma > ctx->sigma_max) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "As sharpen geometry is too large, ignored. %s:%d", __FUNCTION__, __LINE__); } else { status = MagickSharpenImage(ictx->wand, geo.rho, geo.sigma); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "sharpen failed %s:%d", __FUNCTION__, __LINE__); } } } blur = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "blur"); if (ngx_strlen(blur) > 0) { ParseGeometry(blur, &geo); if (geo.rho > ctx->radius_max || geo.sigma > ctx->sigma_max) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "As blur geometry is too large, ignored. %s:%d", __FUNCTION__, __LINE__); } else { status = MagickBlurImage(ictx->wand, geo.rho, geo.sigma); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "blur failed %s:%d", __FUNCTION__, __LINE__); } } } /* border. */ if (sz.bw > 0.0 || sz.bh > 0.0) { border_wand = NewDrawingWand(); border_color = NewPixelWand(); PixelSetRed(border_color, sz.bc.r / 255.0); PixelSetGreen(border_color, sz.bc.g / 255.0); PixelSetBlue(border_color, sz.bc.b / 255.0); PixelSetAlpha(border_color, sz.bc.a / 255.0); DrawSetFillColor(border_wand, border_color); DrawSetStrokeColor(border_wand, border_color); DrawSetStrokeWidth(border_wand, 1); if (sz.cw > 0.0 && sz.ch > 0.0) { DrawRectangle(border_wand, 0, 0, sz.cw - 1, sz.bh - 1); DrawRectangle(border_wand, 0, 0, sz.bw - 1, sz.ch - 1); DrawRectangle(border_wand, 0, sz.ch - sz.bh, sz.cw - 1, sz.ch - 1); DrawRectangle(border_wand, sz.cw - sz.bw, 0, sz.cw - 1, sz.ch - 1); } else { DrawRectangle(border_wand, 0, 0, sz.dw - 1, sz.bh - 1); DrawRectangle(border_wand, 0, 0, sz.bw - 1, sz.dh - 1); DrawRectangle(border_wand, 0, sz.dh - sz.bh, sz.dw - 1, sz.dh - 1); DrawRectangle(border_wand, sz.dw - sz.bw, 0, sz.dw - 1, sz.dh - 1); } MagickDrawImage(ictx->wand, border_wand); DestroyPixelWand(border_color); DestroyDrawingWand(border_wand); } /* embed icon */ embedicon = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "embedicon"); if (ctx->material_dir->len > 0 && ngx_strlen(embedicon) > 0) { if (ngx_strstrn((u_char *)embedicon, "/", 1 - 1)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid parameter 'embedicon':%s %s:%d", embedicon, __FUNCTION__, __LINE__); DestroyString(of_orig); return NGX_ERROR; } embedicon_len = ngx_strlen(embedicon); embedicon_path_len = ctx->material_dir->len + ngx_strlen("/") + embedicon_len; if (embedicon_path_len > sizeof(embedicon_path) - 1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "embedicon path is too long. maximun value is %z %s:%d", sizeof(embedicon_path) - 1, __FUNCTION__, __LINE__); DestroyString(of_orig); return NGX_ERROR; } p = embedicon_path; p = ngx_cpystrn(p, ctx->material_dir->data, ctx->material_dir->len + 1); p = ngx_cpystrn(p, (u_char *)"/", 1 + 1); p = ngx_cpystrn(p, embedicon, embedicon_len + 1); if ((fd = ngx_open_file(embedicon_path, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0)) == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to open embeddedicon file:%s %s:%d", embedicon_path, __FUNCTION__, __LINE__); DestroyString(of_orig); return NGX_ERROR; } if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to close:%s %s:%d", embedicon_path, __FUNCTION__, __LINE__); DestroyString(of_orig); return NGX_ERROR; } if (ngx_strstrn(embedicon_path, "..", 2 - 1)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid embeddedicon_path:%s %s:%d", embedicon_path, __FUNCTION__, __LINE__); DestroyString(of_orig); return NGX_ERROR; } icon_wand = NewMagickWand(); if (MagickReadImage(icon_wand, (char *)embedicon_path) == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to read embed icon image file:%s %s:%d", embedicon_path, __FUNCTION__, __LINE__); DestroyMagickWand(icon_wand); DestroyString(of_orig); return NGX_ERROR; } MagickCompositeImageChannel(ictx->wand, AllChannels, icon_wand, OverCompositeOp, sz.ix, sz.iy); DestroyMagickWand(icon_wand); } /* set params. */ q = ngx_http_small_light_parse_double(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "q")); if (q > 0.0) { MagickSetImageCompressionQuality(ictx->wand, q); } progressive_flg = ngx_http_small_light_parse_flag(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "progressive")); if (progressive_flg != 0) { MagickSetInterlaceScheme(ictx->wand, LineInterlace); } of = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "of"); if (ngx_strlen(of) > 0) { type = ngx_http_small_light_type(of); if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_NONE) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "of is invalid(%s) %s:%d", of, __FUNCTION__, __LINE__); of = (char *)ngx_http_small_light_image_exts[ictx->type - 1]; } else if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_WEBP) { #if defined(MAGICKCORE_WEBP_DELEGATE) ictx->type = type; #else ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "WebP is not supported %s:%d", __FUNCTION__, __LINE__); of = (char *)ngx_http_small_light_image_exts[ictx->type - 1]; #endif } else { ictx->type = type; } MagickSetFormat(ictx->wand, of); ctx->of = ngx_http_small_light_image_types[ictx->type - 1]; } else { MagickSetFormat(ictx->wand, of_orig); ctx->of = ctx->inf; } DestroyString(of_orig); ctx->content = MagickGetImageBlob(ictx->wand, &sled_image_size); ctx->content_length = sled_image_size; ngx_pfree(r->pool, ctx->content_orig); ictx->complete = 1; return NGX_OK; }
MagickWand* MerlinImage::ReadImage(MerlinImage *img) { MagickWand* wand = NewMagickWand(); MagickReadImageBlob(wand, reinterpret_cast<unsigned char*>(BufferData(img->buffer)), BufferLength(img->buffer)); return wand; }
// Open Image ptImage* ptImage::ptGMCOpenImage(const char* FileName, short ColorSpace, short Intent, short ScaleFactor, bool IsRAW, TImage8RawData* ImgData, bool& Success) { Success = 0; MagickWand* image = NewMagickWand(); ExceptionType MagickExcept; if (IsRAW) { MagickReadImageBlob(image, (const uchar*)ImgData->data(), (const size_t)ImgData->size()); } else { if (!QFile::exists(QString::fromLocal8Bit(FileName))) return this; MagickReadImage(image, FileName); } MagickGetException(image, &MagickExcept); if (MagickExcept != UndefinedException) { return this; } Success = 1; // Get the embedded profile cmsHPROFILE InProfile = NULL; if (MagickGetImageType(image) != GrayscaleType) { ulong ProfileLength = 0; uchar* IccProfile = MagickGetImageProfile(image, "ICC", &ProfileLength); if (ProfileLength > 0) { InProfile = cmsOpenProfileFromMem(IccProfile, ProfileLength); } } if (!InProfile) { InProfile = cmsCreate_sRGBProfile(); } MagickSetImageType(image, TrueColorType); MagickSetImageFormat(image, "RGB"); MagickSetImageDepth(image, 16); uint16_t NewWidth = MagickGetImageWidth(image); uint16_t NewHeight = MagickGetImageHeight(image); // Buffer for the data from Magick std::vector<std::array<float, 3> > ImageBuffer; ImageBuffer.resize((size_t) NewWidth*NewHeight); MagickGetImagePixels(image, 0, 0, NewWidth, NewHeight, "RGB", FloatPixel, (uchar*)ImageBuffer.data()); m_Width = NewWidth; DestroyMagickWand(image); // Image before color transform, may be binned std::vector<std::array<float, 3> > NewImage; if (ScaleFactor != 0) { // Binning NewHeight >>= ScaleFactor; NewWidth >>= ScaleFactor; short Step = 1 << ScaleFactor; int Average = pow(2,2 * ScaleFactor); NewImage.resize((size_t)NewWidth*NewHeight); #pragma omp parallel for schedule(static) for (uint16_t Row=0; Row < NewHeight*Step; Row+=Step) { for (uint16_t Col=0; Col < NewWidth*Step; Col+=Step) { float PixelValue[3] = {0.0f,0.0f,0.0f}; for (uint8_t sRow=0; sRow < Step; sRow++) { for (uint8_t sCol=0; sCol < Step; sCol++) { int32_t index = (Row+sRow)*m_Width+Col+sCol; for (short c=0; c < 3; c++) { PixelValue[c] += ImageBuffer[index][c]; } } } for (short c=0; c < 3; c++) { NewImage[Row/Step*NewWidth+Col/Step][c] = PixelValue[c] / Average; } } } } else {
ngx_int_t ngx_http_small_light_imagemagick_process(ngx_http_request_t *r, ngx_http_small_light_ctx_t *ctx) { ngx_http_small_light_imagemagick_ctx_t *ictx; ngx_http_small_light_image_size_t sz; MagickBooleanType status; int rmprof_flg, progressive_flg; double iw, ih, q; char *jpeg_size_opt, *of_orig, *crop_geo, *size_geo; char *unsharp, *sharpen, *blur, *dealpha, *of; MagickWand *trans_wand, *canvas_wand; DrawingWand *border_wand; PixelWand *bg_color, *canvas_color, *border_color; GeometryInfo geo; ngx_fd_t fd; MagickWand *icon_wand; u_char *p, *embedicon, *embedicon_path; size_t embedicon_path_len, embedicon_len, sled_image_size; ngx_int_t type; status = MagickFalse; ictx = (ngx_http_small_light_imagemagick_ctx_t *)ctx->ictx; /* adjust image size */ ngx_http_small_light_calc_image_size(r, ctx, &sz, 10000.0, 10000.0); /* init */ ictx->wand = NewMagickWand(); /* prepare */ if (sz.jpeghint_flg != 0) { jpeg_size_opt = ngx_pcalloc(r->pool, 32 + 1); if (jpeg_size_opt == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to allocate memory from r->pool %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } ngx_snprintf((u_char *)jpeg_size_opt, 32 + 1, "%dx%d", (ngx_int_t)sz.dw, (ngx_int_t)sz.dh); MagickSetOption(ictx->wand, "jpeg:size", jpeg_size_opt); } /* load image. */ status = MagickReadImageBlob(ictx->wand, (void *)ictx->image, ictx->image_len); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "couldn't read image %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } /* remove all profiles */ rmprof_flg = ngx_http_small_light_parse_flag(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "rmprof")); if (rmprof_flg != 0) { status = MagickProfileImage(ictx->wand, "*", NULL, 0); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "couldn't profiling image %s:%d", __FUNCTION__, __LINE__); } } /* calc size. */ iw = (double)MagickGetImageWidth(ictx->wand); ih = (double)MagickGetImageHeight(ictx->wand); ngx_http_small_light_calc_image_size(r, ctx, &sz, iw, ih); /* pass through. */ if (sz.pt_flg != 0) { return NGX_OK; } of_orig = MagickGetImageFormat(ictx->wand); /* crop, scale. */ status = MagickTrue; if (sz.scale_flg != 0) { crop_geo = ngx_pcalloc(r->pool, 128 + 1); if (crop_geo == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to allocate memory from r->pool %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } size_geo = ngx_pcalloc(r->pool, 128 + 1); if (size_geo == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to allocate memory from r->pool %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } ngx_snprintf((u_char *)crop_geo, 128 + 1, "%f!x%f!+%f+%f", sz.sw, sz.sh, sz.sx, sz.sy); ngx_snprintf((u_char *)size_geo, 128 + 1, "%f!x%f!", sz.dw, sz.dh); trans_wand = MagickTransformImage(ictx->wand, crop_geo, size_geo); if (trans_wand == NULL || trans_wand == ictx->wand) { r->err_status = NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_ERROR; } DestroyMagickWand(ictx->wand); ictx->wand = trans_wand; } /* rotate */ if (sz.angle) { bg_color = NewPixelWand(); PixelSetRed(bg_color, sz.cc.r / 255.0); PixelSetGreen(bg_color, sz.cc.g / 255.0); PixelSetBlue(bg_color, sz.cc.b / 255.0); PixelSetAlpha(bg_color, sz.cc.a / 255.0); switch (sz.angle) { case 90: case 180: case 270: MagickRotateImage(ictx->wand, bg_color, sz.angle); break; } DestroyPixelWand(bg_color); } /* create canvas then draw image to the canvas. */ if (sz.cw > 0.0 && sz.ch > 0.0) { canvas_wand = NewMagickWand(); canvas_color = NewPixelWand(); PixelSetRed(canvas_color, sz.cc.r / 255.0); PixelSetGreen(canvas_color, sz.cc.g / 255.0); PixelSetBlue(canvas_color, sz.cc.b / 255.0); PixelSetAlpha(canvas_color, sz.cc.a / 255.0); status = MagickNewImage(canvas_wand, sz.cw, sz.ch, canvas_color); DestroyPixelWand(canvas_color); if (status == MagickFalse) { r->err_status = NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_ERROR; } status = MagickCompositeImage(canvas_wand, ictx->wand, AtopCompositeOp, sz.dx, sz.dy); if (status == MagickFalse) { r->err_status = NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_ERROR; } DestroyMagickWand(ictx->wand); ictx->wand = canvas_wand; } /* effects. */ unsharp = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "unsharp"); if (unsharp != NULL) { ParseGeometry(unsharp, &geo); status = MagickUnsharpMaskImage(ictx->wand, geo.rho, geo.sigma, geo.xi, geo.psi); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unsharp failed %s:%d", __FUNCTION__, __LINE__); } } sharpen = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "sharpen"); if (sharpen != NULL) { ParseGeometry(sharpen, &geo); status = MagickSharpenImage(ictx->wand, geo.rho, geo.sigma); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "sharpen failed %s:%d", __FUNCTION__, __LINE__); } } blur = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "blur"); if (blur) { ParseGeometry(blur, &geo); status = MagickBlurImage(ictx->wand, geo.rho, geo.sigma); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "blur failed %s:%d", __FUNCTION__, __LINE__); } } dealpha = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "dealpha"); if (dealpha != NULL) { status = MagickSetImageAlphaChannel(ictx->wand, DeactivateAlphaChannel); if (status == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "dealpha failed %s:%d", __FUNCTION__, __LINE__); } } /* border. */ if (sz.bw > 0.0 || sz.bh > 0.0) { border_wand = NewDrawingWand(); border_color = NewPixelWand(); PixelSetRed(border_color, sz.bc.r / 255.0); PixelSetGreen(border_color, sz.bc.g / 255.0); PixelSetBlue(border_color, sz.bc.b / 255.0); PixelSetAlpha(border_color, sz.bc.a / 255.0); DrawSetFillColor(border_wand, border_color); DrawSetStrokeColor(border_wand, border_color); DrawSetStrokeWidth(border_wand, 1); if (sz.cw > 0.0 && sz.ch > 0.0) { DrawRectangle(border_wand, 0, 0, sz.cw - 1, sz.bh - 1); DrawRectangle(border_wand, 0, 0, sz.bw - 1, sz.ch - 1); DrawRectangle(border_wand, 0, sz.ch - sz.bh, sz.cw - 1, sz.ch - 1); DrawRectangle(border_wand, sz.cw - sz.bw, 0, sz.cw - 1, sz.ch - 1); } else { DrawRectangle(border_wand, 0, 0, sz.dw - 1, sz.bh - 1); DrawRectangle(border_wand, 0, 0, sz.bw - 1, sz.dh - 1); DrawRectangle(border_wand, 0, sz.dh - sz.bh, sz.dw - 1, sz.dh - 1); DrawRectangle(border_wand, sz.dw - sz.bw, 0, sz.dw - 1, sz.dh - 1); } MagickDrawImage(ictx->wand, border_wand); DestroyPixelWand(border_color); DestroyDrawingWand(border_wand); } /* embed icon */ embedicon = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "embedicon"); if (ngx_strlen(ctx->material_dir) > 0 && ngx_strlen(embedicon) > 0) { if (ngx_strstrn((u_char *)embedicon, "/", 1 - 1)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid parameter 'embedicon':%s %s:%d", embedicon, __FUNCTION__, __LINE__); return NGX_ERROR; } icon_wand = NewMagickWand(); embedicon_len = ngx_strlen(embedicon); embedicon_path_len = ctx->material_dir->len + ngx_strlen("/") + embedicon_len; embedicon_path = ngx_palloc(r->pool, embedicon_path_len + 1); if (embedicon_path == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to allocate memory from r->pool %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } p = embedicon_path; p = ngx_cpystrn(p, ctx->material_dir->data, ctx->material_dir->len + 1); p = ngx_cpystrn(p, (u_char *)"/", 1 + 1); p = ngx_cpystrn(p, embedicon, embedicon_len + 1); if ((fd = ngx_open_file(embedicon_path, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0)) == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to open embeddedicon file:%s %s:%d", embedicon_path, __FUNCTION__, __LINE__); return NGX_ERROR; } if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to close:%s %s:%d", embedicon_path, __FUNCTION__, __LINE__); return NGX_ERROR; } if (ngx_strstrn(embedicon_path, "..", 2 - 1)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid embeddedicon_path:%s %s:%d", embedicon_path, __FUNCTION__, __LINE__); return NGX_ERROR; } if (MagickReadImage(icon_wand, (char *)embedicon_path) == MagickFalse) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to read embed icon image file:%s %s:%d", embedicon_path, __FUNCTION__, __LINE__); return NGX_ERROR; } MagickCompositeImageChannel(ictx->wand, AllChannels, icon_wand, OverCompositeOp, sz.ix, sz.iy); ClearMagickWand(icon_wand); } /* set params. */ q = ngx_http_small_light_parse_double(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "q")); if (q > 0.0) { MagickSetImageCompressionQuality(ictx->wand, q); } progressive_flg = ngx_http_small_light_parse_flag(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "progressive")); if (progressive_flg != 0) { MagickSetInterlaceScheme(ictx->wand, LineInterlace); } of = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "of"); if (ngx_strlen(of) > 0) { type = ngx_http_small_light_type(of); if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_NONE) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "of is invalid(%s) %s:%d", of, __FUNCTION__, __LINE__); of = (char *)ngx_http_small_light_image_exts[ictx->type - 1]; } else if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_WEBP) { #if defined(MAGICKCORE_WEBP_DELEGATE) ictx->type = type; #else ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "WebP is not supported %s:%d", __FUNCTION__, __LINE__); of = (char *)ngx_http_small_light_image_exts[ictx->type - 1]; #endif } else { ictx->type = type; } MagickSetFormat(ictx->wand, of); ctx->of = ngx_http_small_light_image_types[ictx->type - 1]; } else { MagickSetFormat(ictx->wand, of_orig); ctx->of = ctx->inf; } ctx->content = MagickGetImageBlob(ictx->wand, &sled_image_size); ctx->content_length = sled_image_size; ictx->complete = 1; return NGX_OK; }
static void doit(const char *src, const char *dst, size_t oldsize, const struct imgmin_options *opt) { MagickWand *mw, *tmp; MagickBooleanType status; double ks; size_t newsize = oldsize + 1; MagickWandGenesis(); mw = NewMagickWand(); /* load image... */ if (0 == strcmp("-", src)) { /* ...from stdin */ # define BIGBUF (16 * 1024 * 1024) char *blob = malloc(BIGBUF); oldsize = read(STDIN_FILENO, blob, BIGBUF); if (BIGBUF == oldsize) { fprintf(stderr, "Image too large for hardcoded imgmin stdin buffer\n"); exit(1); } MagickReadImageBlob(mw, blob, oldsize); free(blob); } else { /* ...from disk */ status = MagickReadImage(mw, src); if (status == MagickFalse) ThrowWandException(mw); } ks = oldsize / 1024.; fprintf(stderr, "Before quality:%lu colors:%lu size:%5.1fkB type:%s ", quality(mw), (unsigned long)unique_colors(mw), ks, type2str(MagickGetImageType(mw))); tmp = search_quality(mw, dst, opt); /* output image... */ { unsigned char *blob = MagickGetImageBlob(tmp, &newsize); /* if resulting image is larger than original, use original instead */ if (newsize > oldsize) { (void) MagickRelinquishMemory(blob); blob = MagickGetImageBlob(mw, &newsize); } { int fd; if (0 == strcmp("-", dst)) { fd = STDOUT_FILENO; } else { fd = open(dst, O_WRONLY | O_CREAT, 0644); if (-1 == fd) { perror("open"); exit(1); } } if ((ssize_t)newsize != write(fd, blob, newsize)) { perror("write"); exit(1); } (void) MagickRelinquishMemory(blob); if (fd != STDOUT_FILENO) close(fd); } } { double kd = newsize / 1024.; double ksave = ks - kd; double kpct = ksave * 100. / ks; fprintf(stderr, "After quality:%lu colors:%lu size:%5.1fkB saved:%5.1fkB (%.1f%%)\n", (unsigned long)quality(tmp), (unsigned long)unique_colors(tmp), kd, ksave, kpct); } /* tear it down */ DestroyMagickWand(tmp); DestroyMagickWand(mw); MagickWandTerminus(); }