Ejemplo n.º 1
0
void save_image(ConvertContext *context) {
    int result = RESULT_OK;
    char *error_desc;
    ExceptionType error_type;
	
    // get pixel data
    if (context->hasAlphaChannel == MagickTrue) {
        if (MagickImportImagePixels(context->mw, 0, 0, context->imageWidth, context->imageHeight, "ARGB", CharPixel, context->pixels)  == MagickFalse) {
            error_desc = MagickGetException(context->mw, &error_type);
            asprintf(&context->results.message, "Error exporting pixel data (%s): %s\n",error_desc,context->src_path);
            error_desc = (char *)MagickRelinquishMemory(error_desc);
            result += RESULT_ERROR;
        }
    }
    
    // convert image to PNG
    if (result == RESULT_OK) {
        if (MagickSetImageFormat(context->mw,"PNG") == MagickFalse) {
            error_desc = MagickGetException(context->mw, &error_type);
			asprintf(&context->results.message,"Error converting image (%s): %s\n",error_desc,context->src_path);
            error_desc = (char *)MagickRelinquishMemory(error_desc);
            result += RESULT_ERROR;
        }
    }
	
	// activate/deactivate alpha channel
	MagickSetImageAlphaChannel(context->mw, (context->results.alpha_type == ALPHA_TYPE_NONE ? DeactivateAlphaChannel : ActivateAlphaChannel));

    // make sure image is saved as RGB and not crunched down to grayscale
	MagickSetType(context->mw, (context->results.alpha_type == ALPHA_TYPE_NONE ? TrueColorType : TrueColorMatteType));
	
	// save image to disk
    if (result == RESULT_OK) {
        if (MagickWriteImage(context->mw, context->dst_path) == MagickFalse) {
            error_desc = MagickGetException(context->mw, &error_type);
            asprintf(&context->results.message, "Error saving image (%s): %s\n",error_desc,context->dst_path);
            error_desc = (char *)MagickRelinquishMemory(error_desc);
            result += RESULT_ERROR;
        }
    }
	
	if (result == RESULT_OK && context->options.delete_original != 0) {
		if (unlink(context->src_path) == -1) {
			asprintf(&context->results.message, "Unable to delete original image (%s): %s\n", strerror(errno), context->src_path);
			result += RESULT_ERROR;
		}
    }
    
	// cleanup and report results
	context->results.result = result;
	dispatch_group_async_f(context->conv_group, dispatch_get_main_queue(), context, (void (*)(void *))finish_image);
}
Ejemplo n.º 2
0
static PyObject *
im_RemoveAlpaChannel(PyObject *self, PyObject *args) {

	void *magick_pointer;
	MagickWand *magick_wand;

	if (!PyArg_ParseTuple(args, "O", &magick_pointer)){
		Py_INCREF(Py_None);
		return Py_None;
	}

	magick_wand = (MagickWand *) PyCObject_AsVoidPtr(magick_pointer);
	MagickSetImageAlphaChannel(magick_wand, DeactivateAlphaChannel);

	Py_INCREF(Py_None);
	return Py_None;
}
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;
}