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;
}
Exemple #2
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);
  }
Exemple #3
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);
}
Exemple #4
0
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;
}
Exemple #5
0
/**
 * @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);
}
Exemple #7
0
/**
 * @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;
}
Exemple #8
0
/**
 * @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;
}
Exemple #10
0
/**
 * @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;
}
Exemple #12
0
MagickWand* MerlinImage::ReadImage(MerlinImage *img) {
    MagickWand* wand = NewMagickWand();
    MagickReadImageBlob(wand, reinterpret_cast<unsigned char*>(BufferData(img->buffer)), BufferLength(img->buffer));
    return wand;
}
Exemple #13
0
// 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;
}
Exemple #15
0
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();
}