// Adds or removes a ICC, IPTC, or generic profile from an image. // If the profile is NULL, it is removed from the image otherwise added. // Use a name of '*' and a profile of NULL to remove all profiles from the image. Object c_Gmagick::t_profileimage(CStrRef name, CStrRef profile) { INSTANCE_METHOD_INJECTION_BUILTIN(Gmagick, Gmagick::profileimage); checkNotEmpty(); int result; if (profile.isNull()) { result = MagickProfileImage(magick_wand, name, NULL, 0); } else { result = MagickProfileImage(magick_wand, name, (const unsigned char *)profile->data(), profile.size()); } checkResult(result); return this; }
int convert_rotate (MagickWand *input, convert_t *opts) { if (!opts->rotate_degrees) return MagickPass; if (opts->rotate_degrees == 360) opts->rotate_degrees = 0; char* exif_orientation = MagickGetImageAttribute(input, "EXIF:Orientation"); if (exif_orientation != NULL) { switch (atoi(exif_orientation)) { case 3: opts->rotate_degrees += 180; break; case 6: opts->rotate_degrees += 90; break; case 8: opts->rotate_degrees += 270; break; } // just clear all exif data MagickProfileImage(input, "exif", NULL, 0); } return opts->rotate_degrees ? MagickRotateImage(input, default_background, opts->rotate_degrees) : MagickPass; }
caddr_t bif_im_DeepZoom4to1 (caddr_t * qst, caddr_t * err, state_slot_t ** args) { im_env_t env; caddr_t res; int fmt_is_set = 0; int image_ctr; im_init (&env, qst, args, "IM DeepZoom4to1"); im_set_background (&env, "#000000"); env.ime_target_magick_wand = NewMagickWand (); if (MagickFalse == MagickNewImage (env.ime_target_magick_wand, 256, 256, env.ime_background)) im_leave_with_error (&env, "22023", "IM001", "Can not make new image"); if (MagickFalse == MagickSetImageType (env.ime_target_magick_wand, TrueColorType)) im_leave_with_error (&env, "22023", "IM001", "Can not set image type"); if (MagickFalse == MagickSetImageDepth (env.ime_target_magick_wand, 16)) im_leave_with_error (&env, "22023", "IM001", "Can not set image depth"); if (MagickFalse == MagickSetImageExtent (env.ime_target_magick_wand, 256, 256)) im_leave_with_error (&env, "22023", "IM001", "Can not set image extent"); if (MagickFalse == MagickSetImageBackgroundColor (env.ime_target_magick_wand, env.ime_background)) im_leave_with_error (&env, "22023", "IM001", "Can not set image background"); image_ctr = BOX_ELEMENTS (args) / 2; if (image_ctr > 4) image_ctr = 4; while (0 < image_ctr--) { if (DV_DB_NULL == DV_TYPE_OF (bif_arg (qst, args, image_ctr*2, "IM DeepZoom4to1"))) continue; im_env_set_input_blob (&env, image_ctr * 2); /*im_env_set_blob_ext (&env, 2);*/ im_read (&env); MagickResetIterator (env.ime_magick_wand); while (MagickNextImage (env.ime_magick_wand) != MagickFalse) { unsigned long v_size, h_size; if (!fmt_is_set) { if (MagickFalse == MagickSetImageFormat (env.ime_target_magick_wand, MagickGetImageFormat (env.ime_magick_wand))) im_leave_with_error (&env, "22023", "IM001", "Can not set image format"); fmt_is_set = 1; } h_size = MagickGetImageWidth (env.ime_magick_wand); v_size = MagickGetImageHeight (env.ime_magick_wand); if ((256 < h_size) || (256 < v_size)) continue; MagickResizeImage (env.ime_magick_wand, h_size/2, v_size/2, BoxFilter, 1.0); if (MagickFalse == MagickCompositeImage (env.ime_target_magick_wand, env.ime_magick_wand, OverCompositeOp, (image_ctr & 1) * 128, (image_ctr & 2) * 64)) im_leave_with_error (&env, "22023", "IM001", "Can not composite image"); } im_reset_read (&env); } MagickProfileImage (env.ime_target_magick_wand, "*", NULL, 0); DestroyMagickWand (env.ime_magick_wand); env.ime_magick_wand = env.ime_target_magick_wand; env.ime_target_magick_wand = NULL; res = im_write (&env); im_leave (&env); return res; }
caddr_t bif_im_ThumbnailImageFile (caddr_t * qst, caddr_t * err, state_slot_t ** args) { im_env_t env; long v_size = bif_long_arg (qst, args, 1, "IM ThumbnailImageFile"); long h_size = bif_long_arg (qst, args, 2, "IM ThumbnailImageFile"); long filter = bif_long_arg (qst, args, 3, "IM ThumbnailImageFile"); im_init (&env, qst, args, "IM ThumbnailImageFile"); im_env_set_filenames (&env, 0, 4); im_read (&env); MagickResetIterator (env.ime_magick_wand); while (MagickNextImage (env.ime_magick_wand) != MagickFalse) { MagickResizeImage (env.ime_magick_wand,v_size, h_size,filter,1.0); MagickProfileImage (env.ime_magick_wand, "*", NULL, 0); } im_write (&env); im_leave (&env); return(0); }
caddr_t bif_im_ThumbnailImageBlob (caddr_t * qst, caddr_t * err, state_slot_t ** args) { im_env_t env; caddr_t res; long v_size = bif_long_arg (qst, args, 2, "IM ThumbnailImageBlob"); long h_size = bif_long_arg (qst, args, 3, "IM ThumbnailImageBlob"); long filter = bif_long_arg (qst, args, 4, "IM ThumbnailImageBlob"); if (filter < 0 || filter > 15) filter = PointFilter; im_init (&env, qst, args, "IM ThumbnailImageBlob"); im_env_set_input_blob (&env, 0); im_env_set_blob_ext (&env, 5, -1); im_read (&env); MagickResetIterator (env.ime_magick_wand); while (MagickNextImage (env.ime_magick_wand) != MagickFalse) { MagickResizeImage (env.ime_magick_wand,v_size, h_size,filter,1.0); MagickProfileImage (env.ime_magick_wand, "*", NULL, 0); } res = im_write (&env); im_leave (&env); return res; }
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; }
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; }