예제 #1
0
파일: magick.c 프로젝트: kulve/pwgallery
/* save image to file */
static gboolean _save(struct data *data, 
                      MagickWand *wand, 
                      const gchar *uri)
{
    gchar *desc;
    guchar *img_data;
    gsize img_len;
    ExceptionType severity;

    g_debug("in _save");

    g_assert(data != NULL);
    g_assert(wand != NULL);
    g_assert(uri != NULL);
 
    if (data->gal->remove_exif && !MagickStripImage(wand))
    {
        desc = MagickGetException(wand, &severity);
        g_warning("_save: error stripping image: %s\n", desc);
        desc = (char *) MagickRelinquishMemory(desc);
    }

    img_data = MagickGetImagesBlob(wand, &img_len);

    vfs_write_file(data, uri, img_data, img_len);

    MagickRelinquishMemory(img_data);

    return TRUE;
}
예제 #2
0
apr_status_t
dims_strip_operation (dims_request_rec *d, char *args, char **err) {

    /* If args is passed from the user and 
     *   a) it equals true, strip the image.
     *   b) it equals false, don't strip the image.
     *   c) it is neither true/false, strip based on config value.
     * If args is NULL, strip based on config value.
     */
    if(args != NULL) {
        if(strcmp(args, "true") == 0 || ( strcmp(args, "false") != 0 && d->config->strip_metadata )) {
            MAGICK_CHECK(MagickStripImage(d->wand), d);
        }
    }
    else if(d->config->strip_metadata) {
        MAGICK_CHECK(MagickStripImage(d->wand), d);
    }

    return DIMS_SUCCESS;
}
예제 #3
0
    unsigned char* process(EIM_FORMAT fmt, size_t *new_length)
    {
        //long unsigned int number_properties;
        //char **properties = MagickGetImageProperties(magick_wand, "*", &number_properties);
        ////void *MagickRelinquishMemory(void *resource)
        //std::cout << "Profiles: " << std::endl;
        //if (properties != (char **) NULL)
        //{
        //    for (ssize_t i=0; i < (ssize_t)number_properties; i++)
        //    {
        //        char *property = MagickGetImageProperty(magick_wand,properties[i]);
        //        std::cout << properties[i] << std::endl;
        //        std::cout << property << std::endl;
        //        properties[i]=(char *) MagickRelinquishMemory(properties[i]);
        //    }
        //    properties=(char **) MagickRelinquishMemory(properties);
        //}
        
        //orientation is stored in the data we're about to strip, so correct the image first
        reorientate();
        MagickStripImage(magick_wand);
        
        status = MagickSetImageFormat(magick_wand, "jpg");
        // MagickWand * old_img = magick_wand;
        magick_wand = MagickMergeImageLayers(magick_wand, FlattenLayer);
        // MagickDestroyImage(old_img);
/*        switch(fmt)
        {
            case EIM_FORMAT_JPG:
                status=MagickSetImageFormat(magick_wand, "jpg");
                break;
            case EIM_FORMAT_GIF:
                status=MagickSetImageFormat(magick_wand, "gif");
                break;
            case EIM_FORMAT_PNG:
            default:
                status=MagickSetImageFormat(magick_wand, "png");
                break;
        }*/
        if (status == MagickFalse) {
            throw("An error occured");
        }
        unsigned char *new_blob;
        new_blob = MagickGetImageBlob(magick_wand,new_length);

        magick_wand=DestroyMagickWand(magick_wand);
        MagickWandTerminus();
        return new_blob;
    }
예제 #4
0
파일: zimg.c 프로젝트: Codefor/zimg
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;
}
예제 #5
0
파일: zdb.c 프로젝트: haython/zimg
/**
 * @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;
}
예제 #6
0
파일: zimg.c 프로젝트: Alexniver/zimg
/**
 * @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;
}
예제 #7
0
파일: imgmin.c 프로젝트: dpq/imgmin
/*
 * given a source image, a destination filepath and a set of image metadata thresholds,
 * search for the lowest-quality version of the source image whose properties fall within our
 * thresholds.
 * this will produce an image file that looks the same to the casual observer, but which
 * contains much less information and results in a smaller file.
 * typical savings on unoptimized images vary widely from 10-80%, with 25-50% being most common.
 */
MagickWand * search_quality(MagickWand *mw, const char *dst,
                                   const struct imgmin_options *opt)
{
    MagickWand *tmp = NULL;
    char tmpfile[MAX_PATH] = "/tmp/imgminXXXXXX";
    if (0 == strcmp("-", dst))
    {
        if (-1 == mkstemp(tmpfile))
        {
            perror("mkstemp");
            return CloneMagickWand(mw);
        }
    } else {
        strcpy(tmpfile, dst);
    }

    /*
     * The overwhelming majority of JPEGs are TrueColorType; it is those types, with a low
     * unique color count, that we must avoid.
     */
    if (!enough_colors(mw, opt))
    {
        fprintf(stdout, " Color count is too low, skipping...\n");
        return CloneMagickWand(mw);
    }

    if (quality(mw) < opt->quality_in_min)
    {
        fprintf(stdout, " Quality < %u, won't second-guess...\n", opt->quality_in_min);
        return CloneMagickWand(mw);
    }

    size_t width = MagickGetImageWidth(mw);
    size_t height = MagickGetImageHeight(mw);

    dssim_info *dssim = dssim_init(1);

    void *convert_data = convert_row_start(mw);
    dssim_set_original_float_callback(dssim, width, height, convert_row_callback, convert_data);
    convert_row_finish(convert_data);

    {
        ExceptionInfo *exception = AcquireExceptionInfo();

        const double original_density = color_density(mw);
        unsigned qmax = min(quality(mw), opt->quality_out_max);
        unsigned qmin = opt->quality_out_min;
        unsigned steps = 0;

        /*
         * binary search of quality space for optimally lowest quality that
         * produces an acceptable level of distortion
         */
        while (qmax > qmin + 1 && steps < opt->max_steps)
        {
            double density_ratio;
            unsigned q;

            steps++;
            q = (qmax + qmin) / 2;

            /* change quality */
            tmp = CloneMagickWand(mw);
            MagickSetImageCompressionQuality(tmp, q);

            /* apply quality change */
            MagickWriteImages(tmp, tmpfile, MagickTrue);
            DestroyMagickWand(tmp);
            tmp = NewMagickWand();
            MagickReadImage(tmp, tmpfile);

            void *convert_data = convert_row_start(tmp);
            dssim_set_modified_float_callback(dssim, width, height, convert_row_callback, convert_data);
            convert_row_finish(convert_data);

            double error = 20.0 * dssim_compare(dssim, NULL); // scaled to threshold of previous implementation

            density_ratio = fabs(color_density(tmp) - original_density) / original_density;

            /* color density ratio threshold is an alternative quality measure.
               If it's exceeded, pretend MSE was higher to increase quality */
            if (density_ratio > opt->color_density_ratio) {
                error *= 1.25 + density_ratio; // fudge factor
            }

            /* eliminate half search space based on whether distortion within thresholds */
            if (error > opt->error_threshold)
            {
                qmin = q;
            } else {
                qmax = q;
            }
            if (opt->show_progress)
            {
                fprintf(stdout, "%.2f/%.2f@%u ", error, density_ratio, q);
            }

            /* Stop searching if close enough to the target */
            if (fabs(error - opt->error_threshold) < opt->error_threshold * ERROR_THRESHOLD_INACCURACY) {
                qmax = q;
                break;
            }
        }
        if (opt->show_progress)
        {
            putc('\n', stdout);
        }

        MagickSetImageCompressionQuality(mw, qmax);

        /* "Chroma sub-sampling works because human vision is relatively insensitive to
         * small areas of colour. It gives a significant reduction in file sizes, with
         * little loss of perceived quality." [3]
         */
#if MagickLibVersion >= 0x630 /* FIXME: available in 0x660, not available in 0x628, not sure which version it was introduced in */
        (void) MagickSetImageProperty(mw, "jpeg:sampling-factor", "2x2");
#endif

        /* strip an image of all profiles and comments */
        (void) MagickStripImage(mw);

        MagickWriteImages(mw, tmpfile, MagickTrue);
        (void) DestroyMagickWand(tmp);
        tmp = NewMagickWand();
        MagickReadImage(tmp, tmpfile);

        exception = DestroyExceptionInfo(exception);
    }

    return tmp;
}
예제 #8
0
파일: zimg.c 프로젝트: Codefor/zimg
/**
 * @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;
}
예제 #9
0
unsigned char *covert_image(MagickWand *magick_wand,
		img_transition_info *image_transition_info, size_t *thumbnail_size) {
	unsigned char *image_data = NULL;
	MagickBooleanType status;
//	MagickWand *tmp_magick_wand = NULL;
	PixelWand *background = NULL;
	size_t height = MagickGetImageHeight(magick_wand);
	size_t old_height = height;
	size_t width = MagickGetImageWidth(magick_wand);
	size_t old_width = width;
	int is_crop = 0;
	int is_Crop = 0;
	int is_thumbnail = 0;
	ssize_t i = 0, j = 0;
	char is_gif_flag = 0;
	char is_jpeg_flag = 0;
	int do_quality = 0;
	char *fileformat = NULL;
	size_t cw = 0; //crop weight
	size_t ch = 0; //crop height

	size_t x_offset = 0;
	size_t y_offset = 0;

	fileformat = MagickGetImageFormat(magick_wand);
	if (fileformat == NULL) {
		return NULL;
	}

	if (0 == strcasecmp(fileformat, image_format[GIFEXT])) {
		is_gif_flag = 1;
	} else if (0 == strcasecmp(fileformat, image_format[JPEGEXT])) {
		is_jpeg_flag = 1;
	} else if (0 == strcasecmp(fileformat, image_format[JPGEXT])) {
		is_jpeg_flag = 1;
	}
	fileformat = (char *) MagickRelinquishMemory(fileformat); //free();

	if ('c' == image_transition_info->transition_str[0]) {
		is_crop = 1;
	} else if ('C' == image_transition_info->transition_str[0]) {
		is_Crop = 1;
	} else {
		is_thumbnail = 1;
	}
	if (is_crop) {
		ParseMetaGeometry(image_transition_info->transition_str + 1, &i, &j,
				&width, &height);
	} else if (is_thumbnail) {
		ParseMetaGeometry(image_transition_info->transition_str, &i, &j, &width,
				&height);
		if (old_width == width && height == old_height) //���ߴ���ͬ����������
			is_thumbnail = 0;
	} else if (is_Crop) {
		if (0
				>= get_Crop_width_height(
						image_transition_info->transition_str + 1, &cw, &ch,
						&x_offset, &y_offset)) {
			logError("%s%s:Crop  %s error\n", __FILE__, __func__,
					image_transition_info->transition_str + 1);

			return NULL;
		}
#if 0
		if(cw > width || ch > height) {
			image_data = MagickGetImagesBlob(magick_wand, thumbnail_size);
			magick_wand = DestroyMagickWand(magick_wand);
			return image_data;
		}
#endif
		//�õ�height��width,�����Ӧ��x_offset,yoffset;
		get_Crop_offset_and_wh(cw, ch, &width, &height, &x_offset, &y_offset);
	}

	if (old_width == width && height == old_height && (is_Crop == 0)
			&& (image_transition_info->is_rotate == 0)
			&& (image_transition_info->is_quality == 0)) {
		image_data = MagickGetImagesBlob(magick_wand, thumbnail_size);
	} else if (width <= 0 || height <= 0) {
		logError("%s%s:Geometry  %s error\n", __FILE__, __func__,
				image_transition_info->transition_str);
	} else {
		/*
		 * if type of the image is GIF, maybe have more than one frame, so do this different
		 *  from others
		 */
//		if (is_gif_flag) {
//			tmp_magick_wand = magick_wand;
//			magick_wand = MagickCoalesceImages(tmp_magick_wand);
//			tmp_magick_wand = magick_wand;
//			magick_wand = MagickOptimizeImageLayers(tmp_magick_wand);
//			tmp_magick_wand = DestroyMagickWand(tmp_magick_wand);
//		}
		/*
		 * if size of the image less than 800 * 600 and that's type is JPEG, then do
		 * quality 100 OP
		 */
		if ((old_width < 800) && (old_height < 600) && is_jpeg_flag
				&& is_crop != 1 && (image_transition_info->is_quality == 0)) {
			do_quality = 1;
		}
		background = NewPixelWand();
		status = PixelSetColor(background, "#000000");

		/* for gif
		 MagickResetIterator(magick_wand);
		 */
		MagickWand *tmp_magick_wand = MagickGetImage(magick_wand);

//		while (MagickNextImage(tmp_magick_wand) != MagickFalse) {
		if (do_quality) {
			MagickSetImageCompressionQuality(tmp_magick_wand, 100);
			MagickStripImage(tmp_magick_wand);
		}
		if (is_thumbnail == 1) {
			MagickThumbnailImage(tmp_magick_wand, width, height);
		} else if (is_crop == 1) {
			MagickCropImage(tmp_magick_wand, width, height, i, j);
		} else if (is_Crop == 1) {
			MagickThumbnailImage(tmp_magick_wand, width, height);
			MagickCropImage(tmp_magick_wand, cw, ch, x_offset, y_offset);
			if (is_gif_flag) { // gif should thumbnail again
				MagickThumbnailImage(tmp_magick_wand, cw, ch);
			}
		}
		if (image_transition_info->is_rotate == 1) {
			MagickRotateImage(tmp_magick_wand, background,
					(double) (image_transition_info->degree));
		}
		if (image_transition_info->is_quality) {
			MagickSetImageCompressionQuality(tmp_magick_wand,
					image_transition_info->quality);
		}
		MagickStripImage(tmp_magick_wand);
//		}

		background = DestroyPixelWand(background);
		image_data = MagickGetImagesBlob(tmp_magick_wand, thumbnail_size);
		tmp_magick_wand = DestroyMagickWand(tmp_magick_wand);
//
//		if (is_gif_flag) {
//			magick_wand = DestroyMagickWand(magick_wand);
//		}
	}
	return image_data;
}
예제 #10
0
unsigned char *get_thumbnail(char *full_filename, char *thumbnail_str,
		size_t *thumbnail_size, int is_rotate, int rotate_degree) {

	unsigned char *image_data = NULL;

	if (full_filename == NULL || thumbnail_str == NULL)
	return NULL;
	MagickBooleanType status;
	MagickWand *tmp_magick_wand = NULL;
	MagickWand *magick_wand = NULL;
	magick_wand = NewMagickWand();
	status = MagickReadImage(magick_wand, full_filename);
	if (status == MagickFalse) {
		ThrowWandException(magick_wand);
		return NULL;
	}
	PixelWand *background = NULL;

	size_t height = MagickGetImageHeight(magick_wand);
	size_t old_height = height;
	size_t width = MagickGetImageWidth(magick_wand);
	size_t old_width = width;

	ssize_t i = 0, j = 0;
	int is_crop = 0;
	char is_gif_flag = 0;
	char is_jpeg_flag = 0;
	int do_quality = 0;
	char *fileformat = NULL;

	fileformat = MagickGetImageFormat(magick_wand);
	if (fileformat == NULL) {
		return NULL;
	}

	if (0 == strcasecmp(fileformat, image_format[GIFEXT])) {
		is_gif_flag = 1;
	} else if (0 == strcasecmp(fileformat, image_format[JPEGEXT])) {
		is_jpeg_flag = 1;
	} else if (0 == strcasecmp(fileformat, image_format[JPGEXT])) {
		is_jpeg_flag = 1;
	}
	fileformat = (char *)MagickRelinquishMemory(fileformat); //free();
	if( 'C' == *thumbnail_str ||'c' == *thumbnail_str ) {
		is_crop = 1;
	}
	if(is_crop) {
		ParseMetaGeometry(thumbnail_str + 1, &i, &j, &width, &height);
	} else {
		ParseMetaGeometry(thumbnail_str, &i, &j, &width, &height);
	}

	if (old_width == width && height == old_height) {
		image_data = MagickGetImagesBlob(magick_wand, thumbnail_size);
	} else if (width <= 0 || height <= 0) {
		logError("%s%s:Geometry  %s error\n", __FILE__, __func__, thumbnail_str);
	} else {
		/*
		 * if type of the image is GIF, maybe have more than one frame, so do this different
		 *  from others
		 */
		if (is_gif_flag) {
			tmp_magick_wand = magick_wand;
			magick_wand = MagickCoalesceImages(tmp_magick_wand);
			tmp_magick_wand = DestroyMagickWand(tmp_magick_wand);
		}
		/*
		 * if size of the image less than 800 * 600 and that's type is JPEG, then do
		 * quality 100 OP
		 */
		if ((old_width < 800) && (old_height < 600) && is_jpeg_flag && is_crop != 1) {
			do_quality = 1;
		}

		MagickResetIterator(magick_wand);
		while (MagickNextImage(magick_wand) != MagickFalse) {
			if(do_quality) {
				MagickSetImageCompressionQuality(magick_wand, 100);
				MagickStripImage(magick_wand);
			}
			if(is_crop == 0)
			MagickThumbnailImage(magick_wand, width, height);
			else {
				logInfo("crop Image %ld, %ld", i, j);
				MagickCropImage(magick_wand, width, height, i, j);
			}
			if(is_rotate == 1) {
				background=NewPixelWand();
				status=PixelSetColor(background,"#000000");
				MagickRotateImage(magick_wand, background,(double)rotate_degree);
				background=DestroyPixelWand(background);
			}
		}
		image_data = MagickGetImagesBlob(magick_wand, thumbnail_size);
	}
	magick_wand = DestroyMagickWand(magick_wand);
	return image_data;
}
예제 #11
0
파일: imgmin.c 프로젝트: banzalik/imgmin
/*
 * given a source image, a destination filepath and a set of image metadata thresholds,
 * search for the lowest-quality version of the source image whose properties fall within our
 * thresholds.
 * this will produce an image file that looks the same to the casual observer, but which
 * contains much less information and results in a smaller file.
 * typical savings on unoptimized images vary widely from 10-80%, with 25-50% being most common.
 */
MagickWand * search_quality(MagickWand *mw, const char *dst,
                                   const struct imgmin_options *opt)
{
    MagickWand *tmp = NULL;
    char tmpfile[MAX_PATH] = "/tmp/imgminXXXXXX";
    if (0 == strcmp("-", dst))
    {
        if (-1 == mkstemp(tmpfile))
        {
            perror("mkstemp");
            return CloneMagickWand(mw);
        }
    } else {
        strcpy(tmpfile, dst);
    }

    /*
     * The overwhelming majority of JPEGs are TrueColorType; it is those types, with a low
     * unique color count, that we must avoid.
     */
    if (unique_colors(mw) < opt->min_unique_colors && MagickGetType(mw) != GrayscaleType)
    {
        fprintf(stderr, " Color count is too low, skipping...\n");
        return CloneMagickWand(mw);
    }

    if (quality(mw) < opt->quality_in_min)
    {
        fprintf(stderr, " Quality < %u, won't second-guess...\n", opt->quality_in_min);
        return CloneMagickWand(mw);
    }

    {
        ExceptionInfo *exception = AcquireExceptionInfo();

        const double original_density = color_density(mw);
        unsigned qmax = min(quality(mw), opt->quality_out_max);
        unsigned qmin = opt->quality_out_min;
        unsigned steps = 0;

        /*
         * binary search of quality space for optimally lowest quality that
         * produces an acceptable level of distortion
         */
        while (qmax > qmin + 1 && steps < opt->max_steps)
        {
            double distortion[CompositeChannels+1];
            double error;
            double density_ratio;
            unsigned q;

            steps++;
            q = (qmax + qmin) / 2;

            /* change quality */
            tmp = CloneMagickWand(mw);
            MagickSetImageCompressionQuality(tmp, q);

            /* apply quality change */
            MagickWriteImages(tmp, tmpfile, MagickTrue);
            DestroyMagickWand(tmp);
            tmp = NewMagickWand();
            MagickReadImage(tmp, tmpfile);

            /* quantify distortion produced by quality change
             * NOTE: writes to distortion[], which we don't care about
             * and to image(tmp)->error, which we do care about
             */
            (void) GetImageDistortion(GetImageFromMagickWand(tmp),
                                      GetImageFromMagickWand(mw),
                                      MeanErrorPerPixelMetric,
                                      distortion,
                                      exception);
            /* FIXME: in perlmagick i was getting back a number [0,255.0],
             * here something else is happening... the hardcoded divisor
             * is an imperfect attempt to scale the number back to the
             * perlmagick results. I really need to look into this.
             */
            error = GetImageFromMagickWand(tmp)->error.mean_error_per_pixel / 380.;
            density_ratio = fabs(color_density(tmp) - original_density) / original_density;
        
            /* eliminate half search space based on whether distortion within thresholds */
            if (error > opt->error_threshold || density_ratio > opt->color_density_ratio)
            {
                qmin = q;
            } else {
                qmax = q;
            }
            if (opt->show_progress)
            {
                fprintf(stderr, "%.2f/%.2f@%u ", error, density_ratio, q);
            }
        }
        if (opt->show_progress)
        {
            putc('\n', stderr);
        }

        MagickSetImageCompressionQuality(mw, qmax);

        /* "Chroma sub-sampling works because human vision is relatively insensitive to
         * small areas of colour. It gives a significant reduction in file sizes, with
         * little loss of perceived quality." [3]
         */
        (void) MagickSetImageProperty(mw, "jpeg:sampling-factor", "2x2");

        /* strip an image of all profiles and comments */
        (void) MagickStripImage(mw);

        MagickWriteImages(mw, tmpfile, MagickTrue);
        (void) DestroyMagickWand(tmp);
        tmp = NewMagickWand();
        MagickReadImage(tmp, tmpfile);

        exception = DestroyExceptionInfo(exception);
    }

    return tmp;
}