예제 #1
0
void composite(T1 & im, T2 & im2, composite_mode_e mode,
               float opacity,
               int dx,
               int dy,
               bool premultiply_src,
               bool premultiply_dst)
{
    typedef agg::rgba8 color;
    typedef agg::order_rgba order;
    typedef agg::pixel32_type pixel_type;
    typedef agg::comp_op_adaptor_rgba<color, order> blender_type;
    typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_type;
    typedef agg::renderer_base<pixfmt_type> renderer_type;

    agg::rendering_buffer source(im.getBytes(),im.width(),im.height(),im.width() * 4);
    agg::rendering_buffer mask(im2.getBytes(),im2.width(),im2.height(),im2.width() * 4);

    pixfmt_type pixf(source);
    pixf.comp_op(static_cast<agg::comp_op_e>(mode));

    agg::pixfmt_rgba32 pixf_mask(mask);
    if (premultiply_src)  pixf_mask.premultiply();
    if (premultiply_dst)  pixf.premultiply();
    renderer_type ren(pixf);
    // TODO - is this really opacity, or agg::cover?
    ren.blend_from(pixf_mask,0, dx,dy,unsigned(255*opacity));
}
예제 #2
0
inline int import_image_data(T2 const& image,
                             WebPPicture & pic,
                             bool alpha)
{
    // Reason for copy: https://github.com/mapnik/mapnik/issues/2024
    // TODO - figure out way to pass view pixels directly to webp importer
    image_data_32 im(image.width(),image.height());
    for (unsigned y = 0; y < image.height(); ++y)
    {
        typename T2::pixel_type const * row_from = image.getRow(y);
        image_data_32::pixel_type * row_to = im.getRow(y);
        for (unsigned x = 0; x < image.width(); ++x)
        {
            row_to[x] = row_from[x];
        }
    }
    int stride = sizeof(typename T2::pixel_type) * im.width();
    if (alpha)
    {
        return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
    }
    else
    {
#if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
        return WebPPictureImportRGBX(&pic, im.getBytes(), stride);
#else
        return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
#endif
    }
}
예제 #3
0
inline int import_image_data(T2 const& image,
                             WebPPicture & pic,
                             bool alpha)
{
    ImageData<typename T2::pixel_type> const& data = image.data();
    int stride = sizeof(typename T2::pixel_type) * image.width();
    if (data.width() == image.width() &&
        data.height() == image.height())
    {
        if (alpha)
        {
            return WebPPictureImportRGBA(&pic, data.getBytes(), stride);
        }
        else
        {
    #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
            return WebPPictureImportRGBX(&pic, data.getBytes(), stride);
    #else
            return WebPPictureImportRGBA(&pic, data.getBytes(), stride);
    #endif
        }
    }
    else
    {
        // need to copy: https://github.com/mapnik/mapnik/issues/2024
        image_data_32 im(image.width(),image.height());
        for (unsigned y = 0; y < image.height(); ++y)
        {
            typename T2::pixel_type const * row_from = image.getRow(y);
            image_data_32::pixel_type * row_to = im.getRow(y);
            std::memcpy(row_to,row_from,stride);
        }
        if (alpha)
        {
            return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
        }
        else
        {
    #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
            return WebPPictureImportRGBX(&pic, im.getBytes(), stride);
    #else
            return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
    #endif
        }
    }
}
예제 #4
0
void save_as_png8(T1 & file, T2 const& image, T3 const & tree,
                  std::vector<mapnik::rgb> const& palette, std::vector<unsigned> const& alphaTable,
                  int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY)
{
    unsigned width = image.width();
    unsigned height = image.height();

    if (palette.size() > 16 )
    {
        // >16 && <=256 colors -> write 8-bit color depth
        image_data_8 reduced_image(width, height);

        for (unsigned y = 0; y < height; ++y)
        {
            mapnik::image_data_32::pixel_type const * row = image.getRow(y);
            mapnik::image_data_8::pixel_type  * row_out = reduced_image.getRow(y);

            for (unsigned x = 0; x < width; ++x)
            {
                row_out[x] = tree.quantize(row[x]);
            }
        }
        save_as_png(file, palette, reduced_image, width, height, 8, compression, strategy, alphaTable);
    }
    else if (palette.size() == 1)
    {
        // 1 color image ->  write 1-bit color depth PNG
        unsigned image_width  = width > 7 ? (int(0.125*width) + 1)&~1 : 1;
        unsigned image_height = height;
        image_data_8 reduced_image(image_width, image_height);
        reduced_image.set(0);
        save_as_png(file, palette, reduced_image, width, height, 1, compression, strategy, alphaTable);
    }
    else
    {
        // <=16 colors -> write 4-bit color depth PNG
        unsigned image_width  = width > 3 ? (int(0.5*width) + 3)&~3 : 4;
        unsigned image_height = height;
        image_data_8 reduced_image(image_width, image_height);
        for (unsigned y = 0; y < height; ++y)
        {
            mapnik::image_data_32::pixel_type const * row = image.getRow(y);
            mapnik::image_data_8::pixel_type  * row_out = reduced_image.getRow(y);
            byte index = 0;

            for (unsigned x = 0; x < width; ++x)
            {

                index = tree.quantize(row[x]);
                if (x%2 == 0) index = index<<4;
                row_out[x>>1] |= index;
            }
        }
        save_as_png(file, palette, reduced_image, width, height, 4, compression, strategy, alphaTable);
    }
}
예제 #5
0
   void save_as_jpeg(T1 & file,int quality, T2 const& image)
   {  
      struct jpeg_compress_struct cinfo;
      struct jpeg_error_mgr jerr;

      int width=image.width();
      int height=image.height();
	
      cinfo.err = jpeg_std_error(&jerr);
      jpeg_create_compress(&cinfo);
    
      cinfo.dest = (struct jpeg_destination_mgr *)(*cinfo.mem->alloc_small)
         ((j_common_ptr) &cinfo, JPOOL_PERMANENT, sizeof(dest_mgr));
      dest_mgr * dest = (dest_mgr*) cinfo.dest;
      dest->pub.init_destination = init_destination;
      dest->pub.empty_output_buffer = empty_output_buffer;
      dest->pub.term_destination = term_destination;
      dest->out = &file;
      
      //jpeg_stdio_dest(&cinfo, fp);
      cinfo.image_width = width;
      cinfo.image_height = height;
      cinfo.input_components = 3;
      cinfo.in_color_space = JCS_RGB; 
      jpeg_set_defaults(&cinfo);
      jpeg_set_quality(&cinfo, quality,1);
      jpeg_start_compress(&cinfo, 1);
      JSAMPROW row_pointer[1];
      JSAMPLE* row=reinterpret_cast<JSAMPLE*>( ::operator new (sizeof(JSAMPLE) * width*3));
      while (cinfo.next_scanline < cinfo.image_height) 
      {
         const unsigned* imageRow=image.getRow(cinfo.next_scanline);
         int index=0;
         for (int i=0;i<width;++i)
         {
#ifdef MAPNIK_BIG_ENDIAN
            row[index++]=(imageRow[i]>>24)&0xff;
            row[index++]=(imageRow[i]>>16)&0xff;
            row[index++]=(imageRow[i]>>8)&0xff;
#else
            row[index++]=(imageRow[i])&0xff;
            row[index++]=(imageRow[i]>>8)&0xff;
            row[index++]=(imageRow[i]>>16)&0xff;
#endif
         }
         row_pointer[0] = &row[0];
         (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
      }
      ::operator delete(row);
      
      jpeg_finish_compress(&cinfo);
      jpeg_destroy_compress(&cinfo);
   }  
예제 #6
0
void composite(T1 & dst, T2 & src, composite_mode_e mode,
               float opacity,
               int dx,
               int dy,
               bool premultiply_src)
{
    using color = agg::rgba8;
    using order = agg::order_rgba;
    using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>;
    using pixfmt_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>;
    using renderer_type = agg::renderer_base<pixfmt_type>;

    agg::rendering_buffer dst_buffer(dst.getBytes(),dst.width(),dst.height(),dst.width() * 4);
    agg::rendering_buffer src_buffer(src.getBytes(),src.width(),src.height(),src.width() * 4);

    pixfmt_type pixf(dst_buffer);
    pixf.comp_op(static_cast<agg::comp_op_e>(mode));

    agg::pixfmt_rgba32 pixf_mask(src_buffer);
    if (premultiply_src)  pixf_mask.premultiply();
    renderer_type ren(pixf);
    ren.blend_from(pixf_mask,0,dx,dy,unsigned(255*opacity));
}
예제 #7
0
void save_as_png(T1 & file,
                T2 const& image,
                png_options const& opts)

{
    png_voidp error_ptr=0;
    png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                                error_ptr,0, 0);

    if (!png_ptr) return;

    // switch on optimization only if supported
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED)
    png_uint_32 mask, flags;
    flags = png_get_asm_flags(png_ptr);
    mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
    png_set_asm_flags(png_ptr, flags | mask);
#endif
    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&png_ptr,static_cast<png_infopp>(0));
        return;
    }
    jmp_buf* jmp_context = static_cast<jmp_buf*>(png_get_error_ptr(png_ptr));
    if (jmp_context)
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return;
    }
    png_set_write_fn (png_ptr, &file, &write_data<T1>, &flush_data<T1>);

    png_set_compression_level(png_ptr, opts.compression);
    png_set_compression_strategy(png_ptr, opts.strategy);
    png_set_compression_buffer_size(png_ptr, 32768);

    png_set_IHDR(png_ptr, info_ptr,image.width(),image.height(),8,
                 (opts.trans_mode == 0) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
    const std::unique_ptr<png_bytep[]> row_pointers(new png_bytep[image.height()]);
    for (unsigned int i = 0; i < image.height(); i++)
    {
        row_pointers[i] = const_cast<png_bytep>(reinterpret_cast<const unsigned char *>(image.get_row(i)));
    }
    png_set_rows(png_ptr, info_ptr, row_pointers.get());
    png_write_png(png_ptr, info_ptr, (opts.trans_mode == 0) ? PNG_TRANSFORM_STRIP_FILLER_AFTER : PNG_TRANSFORM_IDENTITY, nullptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);
}
예제 #8
0
파일: webp_io.hpp 프로젝트: cquest/mapnik
inline int import_image(T2 const& im_in,
                             WebPPicture & pic,
                             bool alpha)
{
    image<typename T2::pixel> const& data = im_in.data();
    std::size_t width = im_in.width();
    std::size_t height = im_in.height();
    std::size_t stride = sizeof(typename T2::pixel_type) * width;
    if (data.width() == width &&
        data.height() == height)
    {
        if (alpha)
        {
            return WebPPictureImportRGBA(&pic, data.bytes(), static_cast<int>(stride));
        }
        else
        {
    #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
            return WebPPictureImportRGBX(&pic, data.bytes(), static_cast<int>(stride));
    #else
            return WebPPictureImportRGBA(&pic, data.bytes(), static_cast<int>(stride));
    #endif
        }
    }
    else
    {
        // need to copy: https://github.com/mapnik/mapnik/issues/2024
        image_rgba8 im(width,height);
        for (unsigned y = 0; y < height; ++y)
        {
            typename T2::pixel_type const * row_from = im_in.get_row(y);
            image_rgba8::pixel_type * row_to = im.get_row(y);
            std::copy(row_from, row_from + width, row_to);
        }
        if (alpha)
        {
            return WebPPictureImportRGBA(&pic, im.bytes(), static_cast<int>(stride));
        }
        else
        {
    #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
            return WebPPictureImportRGBX(&pic, im.bytes(), static_cast<int>(stride));
    #else
            return WebPPictureImportRGBA(&pic, im.bytes(), static_cast<int>(stride));
    #endif
        }
    }
}
예제 #9
0
void save_as_png(T1 & file , T2 const& image, int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY)
{
    png_voidp error_ptr=0;
    png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                                error_ptr,0, 0);

    if (!png_ptr) return;

    // switch on optimization only if supported
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED)
    png_uint_32 mask, flags;
    flags = png_get_asm_flags(png_ptr);
    mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
    png_set_asm_flags(png_ptr, flags | mask);
#endif
    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&png_ptr,(png_infopp)0);
        return;
    }
    jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr);
    if (jmp_context)
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return;
    }
    png_set_write_fn (png_ptr, &file, &write_data<T1>, &flush_data<T1>);

    png_set_compression_level(png_ptr, compression);
    png_set_compression_strategy(png_ptr, strategy);
    png_set_compression_buffer_size(png_ptr, 32768);

    png_set_IHDR(png_ptr, info_ptr,image.width(),image.height(),8,
                 PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
    png_write_info(png_ptr, info_ptr);
    for (unsigned i=0;i<image.height();i++)
    {
        png_write_row(png_ptr,(png_bytep)image.getRow(i));
    }

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);
}
예제 #10
0
void save_as_webp(T1& file,
                  T2 const& image,
                  WebPConfig const& config,
                  bool alpha)
{
    bool valid = WebPValidateConfig(&config);
    if (!valid)
    {
        throw std::runtime_error("Invalid configuration");
    }

    WebPPicture pic;
    if (!WebPPictureInit(&pic))
    {
        throw std::runtime_error("version mismatch");
    }
    pic.width = image.width();
    pic.height = image.height();
    int ok = 0;
#if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
    pic.use_argb = !!config.lossless;
    // lossless fast track
    if (pic.use_argb)
    {
        pic.colorspace = static_cast<WebPEncCSP>(pic.colorspace | WEBP_CSP_ALPHA_BIT);
        if (WebPPictureAlloc(&pic)) {
            ok = 1;
            const int width = pic.width;
            const int height = pic.height;
            for (int y = 0; y < height; ++y) {
                typename T2::pixel_type const * row = image.getRow(y);
                for (int x = 0; x < width; ++x) {
                    const unsigned rgba = row[x];
                    unsigned a = (rgba >> 24) & 0xff;
                    unsigned r = rgba & 0xff;
                    unsigned g = (rgba >> 8 ) & 0xff;
                    unsigned b = (rgba >> 16) & 0xff;
                    const uint32_t argb = (a << 24) | (r << 16) | (g << 8) | (b);
                    pic.argb[x + y * pic.argb_stride] = argb;
                }
            }
        }
예제 #11
0
void save_as_png8_hex(T1 & file, T2 const& image, int colors = 256,
                      int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY,
                      int trans_mode = -1, double gamma = 2.0)
{
    unsigned width = image.width();
    unsigned height = image.height();

    // structure for color quantization
    hextree<mapnik::rgba> tree(colors);
    if (trans_mode >= 0)
        tree.setTransMode(trans_mode);
    if (gamma > 0)
        tree.setGamma(gamma);

    for (unsigned y = 0; y < height; ++y)
    {
        typename T2::pixel_type const * row = image.getRow(y);
        for (unsigned x = 0; x < width; ++x)
        {
            unsigned val = row[x];
            tree.insert(mapnik::rgba(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val)));
        }
    }

    //transparency values per palette index
    std::vector<mapnik::rgba> pal;
    tree.create_palette(pal);
    assert(int(pal.size()) <= colors);

    std::vector<mapnik::rgb> palette;
    std::vector<unsigned> alphaTable;
    for(unsigned i=0; i<pal.size(); i++)
    {
        palette.push_back(rgb(pal[i].r, pal[i].g, pal[i].b));
        alphaTable.push_back(pal[i].a);
    }

    save_as_png8<T1, T2, hextree<mapnik::rgba> >(file, image, tree, palette, alphaTable, compression, strategy);
}
예제 #12
0
void save_as_png8_oct(T1 & file,
                      T2 const& image,
                      png_options const& opts)
{
    // number of alpha ranges in png8 format; 2 results in smallest image with binary transparency
    // 3 is minimum for semitransparency, 4 is recommended, anything else is worse
    const unsigned TRANSPARENCY_LEVELS = (opts.trans_mode==2||opts.trans_mode<0)?MAX_OCTREE_LEVELS:2;
    unsigned width = image.width();
    unsigned height = image.height();
    unsigned alphaHist[256];//transparency histogram
    unsigned semiCount = 0;//sum of semitransparent pixels
    unsigned meanAlpha = 0;

    if (opts.trans_mode == 0)
    {
        meanAlpha = 255;
    }
    else
    {
        for(int i=0; i<256; i++)
        {
            alphaHist[i] = 0;
        }
        for (unsigned y = 0; y < height; ++y)
        {
            for (unsigned x = 0; x < width; ++x)
            {
                unsigned val = U2ALPHA(static_cast<unsigned>(image.get_row(y)[x]));
                alphaHist[val]++;
                meanAlpha += val;
                if (val>0 && val<255)
                {
                    semiCount++;
                }
            }
        }
        meanAlpha /= width*height;
    }

    // transparency ranges division points
    unsigned limits[MAX_OCTREE_LEVELS+1];
    limits[0] = 0;
    limits[1] = (opts.trans_mode!=0 && alphaHist[0]>0)?1:0;
    limits[TRANSPARENCY_LEVELS] = 256;
    for(unsigned j=2; j<TRANSPARENCY_LEVELS; j++)
    {
        limits[j] = limits[1];
    }
    if (opts.trans_mode != 0)
    {
        unsigned alphaHistSum = 0;
        for(unsigned i=1; i<256; i++)
        {
            alphaHistSum += alphaHist[i];
            for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
            {
                if (alphaHistSum<semiCount*(j)/4)
                {
                    limits[j] = i;
                }
            }
        }
    }
    // avoid too wide full transparent range
    if (limits[1]>256/(TRANSPARENCY_LEVELS-1))
    {
        limits[1]=256/(TRANSPARENCY_LEVELS-1);
    }
    // avoid too wide full opaque range
    if (limits[TRANSPARENCY_LEVELS-1]<212)
    {
        limits[TRANSPARENCY_LEVELS-1]=212;
    }
    if (TRANSPARENCY_LEVELS==2)
    {
        limits[1]=127;
    }
    // estimated number of colors from palette assigned to chosen ranges
    unsigned cols[MAX_OCTREE_LEVELS];
    // count colors
    if (opts.trans_mode == 0)
    {
        for (unsigned j=0; j<TRANSPARENCY_LEVELS; j++)
        {
            cols[j] = 0;
        }
        cols[TRANSPARENCY_LEVELS-1] = width * height;
    }
    else
    {
        for (unsigned j=0; j<TRANSPARENCY_LEVELS; j++)
        {
            cols[j] = 0;
            for (unsigned i=limits[j]; i<limits[j+1]; i++)
            {
                cols[j] += alphaHist[i];
            }
        }
    }

    unsigned divCoef = width*height-cols[0];
    if (divCoef==0)
    {
        divCoef = 1;
    }
    cols[0] = cols[0]>0?1:0; // fully transparent color (one or not at all)

    if (opts.colors>=64)
    {
        // give chance less populated but not empty cols to have at least few colors(12)
        unsigned minCols = (12+1)*divCoef/(opts.colors-cols[0]);
        for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
        {
            if (cols[j]>12 && cols[j]<minCols)
            {
                divCoef += minCols-cols[j];
                cols[j] = minCols;
            }
        }
    }
    unsigned usedColors = cols[0];
    for(unsigned j=1; j<TRANSPARENCY_LEVELS-1; j++)
    {
        cols[j] = cols[j]*(opts.colors-cols[0])/divCoef;
        usedColors += cols[j];
    }
    // use rest for most opaque group of pixels
    cols[TRANSPARENCY_LEVELS-1] = opts.colors-usedColors;

    //no transparency
    if (opts.trans_mode == 0)
    {
        limits[1] = 0;
        cols[0] = 0;
        cols[1] = opts.colors;
    }

    // octree table for separate alpha range with 1-based index (0 is fully transparent: no color)
    octree<rgb> trees[MAX_OCTREE_LEVELS];
    for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
    {
        trees[j].setMaxColors(cols[j]);
    }
    for (unsigned y = 0; y < height; ++y)
    {
        typename T2::pixel_type const * row = image.get_row(y);
        for (unsigned x = 0; x < width; ++x)
        {
            unsigned val = row[x];
            // insert to proper tree based on alpha range
            for(unsigned j=TRANSPARENCY_LEVELS-1; j>0; j--)
            {
                if (cols[j]>0 && U2ALPHA(val)>=limits[j])
                {
                    trees[j].insert(mapnik::rgb(U2RED(val), U2GREEN(val), U2BLUE(val)));
                    break;
                }
            }
        }
    }
    unsigned leftovers = 0;
    std::vector<rgb> palette;
    palette.reserve(opts.colors);
    if (cols[0])
    {
        palette.push_back(rgb(0,0,0));
    }

    for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
    {
        if (cols[j]>0)
        {
            if (leftovers>0)
            {
                cols[j] += leftovers;
                trees[j].setMaxColors(cols[j]);
                leftovers = 0;
            }
            std::vector<rgb> pal;
            trees[j].setOffset( static_cast<unsigned>(palette.size()));
            trees[j].create_palette(pal);
            leftovers = cols[j] - static_cast<unsigned>(pal.size());
            cols[j] = static_cast<unsigned>(pal.size());
            palette.insert(palette.end(), pal.begin(), pal.end());
        }
    }

    //transparency values per palette index
    std::vector<unsigned> alphaTable;
    //alphaTable.resize(palette.size());//allow semitransparency also in almost opaque range
    if (opts.trans_mode != 0)
    {
        alphaTable.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]);
    }

    if (palette.size() > 16 )
    {
        // >16 && <=256 colors -> write 8-bit color depth
        image_gray8 reduced_image(width,height);
        reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
        save_as_png(file,palette,reduced_image,width,height,8,alphaTable,opts);
    }
    else if (palette.size() == 1)
    {
        // 1 color image ->  write 1-bit color depth PNG
        unsigned image_width  = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary
        unsigned image_height = height;
        image_gray8 reduced_image(image_width,image_height);
        reduce_1(image,reduced_image,trees, limits, alphaTable);
        if (meanAlpha<255 && cols[0]==0)
        {
            alphaTable.resize(1);
            alphaTable[0] = meanAlpha;
        }
        save_as_png(file,palette,reduced_image,width,height,1,alphaTable,opts);
    }
예제 #13
0
파일: png_io.hpp 프로젝트: zeke/node-blend
void save_as_png(T1 & file,
                 T2 const& image,
                 int compression = Z_DEFAULT_COMPRESSION,
                 int strategy = Z_DEFAULT_STRATEGY,
                 int alpha = false,
                 bool use_miniz = false)
{
    if (use_miniz) {
        MiniZ::PNGWriter writer(compression);
        if (alpha) {
            writer.writeIHDR(image.width(), image.height(), 32);
            writer.writeIDAT(image);
        } else {
            writer.writeIHDR(image.width(), image.height(), 24);
            writer.writeIDATStripAlpha(image);
        }
        writer.writeIEND();
        writer.toStream(file);
        return;
    }

    png_voidp error_ptr=0;
    png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
                        error_ptr,0, 0);

    if (!png_ptr) return;

    // switch on optimization only if supported
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED)
    png_uint_32 mask, flags;
    flags = png_get_asm_flags(png_ptr);
    mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
    png_set_asm_flags(png_ptr, flags | mask);
#endif
    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&png_ptr,(png_infopp)0);
        return;
    }
    jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr);
    if (jmp_context)
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return;
    }
    png_set_write_fn (png_ptr, &file, &write_data<T1>, &flush_data<T1>);

    png_set_compression_level(png_ptr, compression);
    png_set_compression_strategy(png_ptr, strategy);
    png_set_compression_buffer_size(png_ptr, 32768);

    png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(), 8,
                 alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);

    png_bytep row_pointers[image.height()];
    for (unsigned int i = 0; i < image.height(); i++) {
        row_pointers[i] = (png_bytep)image.getRow(i);
    }
    png_set_rows(png_ptr, info_ptr, (png_bytepp)&row_pointers);
    png_write_png(png_ptr, info_ptr, alpha ? PNG_TRANSFORM_IDENTITY : PNG_TRANSFORM_STRIP_FILLER_AFTER, NULL);
    png_destroy_write_struct(&png_ptr, &info_ptr);
}
예제 #14
0
void save_as_webp(T1& file,
                  float quality,
                  int method,
                  int lossless,
                  int image_hint,
                  bool alpha,
                  T2 const& image)
{
    WebPConfig config;
    if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality))
    {
        throw std::runtime_error("version mismatch");
    }

    // Add additional tuning
    if (method >= 0) config.method = method;
#if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
    config.lossless = !!lossless;
    config.image_hint = static_cast<WebPImageHint>(image_hint);
#else
    #ifdef _MSC_VER
    #pragma NOTE(compiling against webp that does not support lossless flag)
    #else
    #warning "compiling against webp that does not support lossless flag"
    #endif
#endif

    bool valid = WebPValidateConfig(&config);
    if (!valid)
    {
        throw std::runtime_error("Invalid configuration");
    }

    WebPPicture pic;
    if (!WebPPictureInit(&pic))
    {
        throw std::runtime_error("version mismatch");
    }
    pic.width = image.width();
    pic.height = image.height();
    int ok = 0;
#if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
    pic.use_argb = !!lossless;
    // lossless fast track
    if (pic.use_argb)
    {
        pic.colorspace = static_cast<WebPEncCSP>(pic.colorspace | WEBP_CSP_ALPHA_BIT);
        if (WebPPictureAlloc(&pic)) {
            ok = 1;
            const int width = pic.width;
            const int height = pic.height;
            for (int y = 0; y < height; ++y) {
                typename T2::pixel_type const * row = image.getRow(y);
                for (int x = 0; x < width; ++x) {
                    const unsigned rgba = row[x];
                    unsigned a = (rgba >> 24) & 0xff;
                    unsigned r = rgba & 0xff;
                    unsigned g = (rgba >> 8 ) & 0xff;
                    unsigned b = (rgba >> 16) & 0xff;
                    const uint32_t argb = (a << 24) | (r << 16) | (g << 8) | (b);
                    pic.argb[x + y * pic.argb_stride] = argb;
                }
            }
        }
예제 #15
0
void composite(T1 & im, T2 & im2, composite_mode_e mode)
{
    typedef agg::rgba8 color;
    typedef agg::order_bgra order;
    typedef agg::pixel32_type pixel_type;
    typedef agg::comp_op_adaptor_rgba<color, order> blender_type;
    typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_type;
    typedef agg::renderer_base<pixfmt_type> renderer_type;
    typedef agg::comp_op_adaptor_rgba<color, order> blender_type;
    typedef agg::renderer_base<pixfmt_type> renderer_type;
    
    agg::rendering_buffer source(im.getBytes(),im.width(),im.height(),im.width() * 4);
    agg::rendering_buffer mask(im2.getBytes(),im2.width(),im2.height(),im2.width() * 4);
    
    agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixf(source);
    agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixf_mask(mask);
    
    switch(mode)
    {
    case clear :
        pixf.comp_op(agg::comp_op_clear);
        break;
    case src:
        pixf.comp_op(agg::comp_op_src);
        break;
    case dst:
        pixf.comp_op(agg::comp_op_dst);
        break;
    case src_over:
        pixf.comp_op(agg::comp_op_src_over);
        break;
    case dst_over:
        pixf.comp_op(agg::comp_op_dst_over);
        break;
    case src_in:
        pixf.comp_op(agg::comp_op_src_in);
        break;
    case dst_in:
        pixf.comp_op(agg::comp_op_dst_in);
        break;
    case src_out:
        pixf.comp_op(agg::comp_op_src_out);
        break;
    case dst_out:
        pixf.comp_op(agg::comp_op_dst_out);
        break;
    case src_atop:
        pixf.comp_op(agg::comp_op_src_atop);
        break;
    case dst_atop:
        pixf.comp_op(agg::comp_op_dst_atop);
        break;
    case _xor:
        pixf.comp_op(agg::comp_op_xor);
        break;
    case plus:
        pixf.comp_op(agg::comp_op_plus);
        break;
    case minus:
        pixf.comp_op(agg::comp_op_minus);
        break;
    case multiply:
        pixf.comp_op(agg::comp_op_multiply);
        break;     
    case screen:
        pixf.comp_op(agg::comp_op_screen);
        break;
    case overlay:
        pixf.comp_op(agg::comp_op_overlay);
        break;
    case darken:
        pixf.comp_op(agg::comp_op_darken);
        break;    
    case lighten:
        pixf.comp_op(agg::comp_op_lighten);
        break;
    case color_dodge:
        pixf.comp_op(agg::comp_op_color_dodge);
        break;
    case color_burn:
        pixf.comp_op(agg::comp_op_color_burn);
        break;
    case hard_light:
        pixf.comp_op(agg::comp_op_hard_light);
        break;
    case soft_light:
        pixf.comp_op(agg::comp_op_soft_light);
        break;
    case difference:
        pixf.comp_op(agg::comp_op_difference);
        break;
    case exclusion:
        pixf.comp_op(agg::comp_op_exclusion);
        break;
    case contrast:
        pixf.comp_op(agg::comp_op_contrast);
        break;
    case invert:
        pixf.comp_op(agg::comp_op_invert);
        break;
    case invert_rgb:
        pixf.comp_op(agg::comp_op_invert_rgb);
        break;
    default:
        break;
    
    }
    renderer_type ren(pixf);
    agg::renderer_base<pixfmt_type> rb(pixf);
    rb.blend_from(pixf_mask,0,0,0,255);

}
예제 #16
0
void save_as_png256_hex(T1 & file, T2 const& image, int colors = 256, int trans_mode = -1, double gamma = 2.0)
{
    unsigned width = image.width();
    unsigned height = image.height();

    // structure for color quantization
    hextree<mapnik::rgba> tree(colors);
    if (trans_mode >= 0)
        tree.setTransMode(trans_mode);
    if (gamma > 0)
        tree.setGamma(gamma);

    for (unsigned y = 0; y < height; ++y)
    {
        typename T2::pixel_type const * row = image.getRow(y);
        for (unsigned x = 0; x < width; ++x)
        {
            unsigned val = row[x];
            tree.insert(mapnik::rgba(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val)));
        }
    }

    //transparency values per palette index
    std::vector<mapnik::rgba> pal;
    tree.create_palette(pal);
    assert(int(pal.size()) <= colors);

    std::vector<mapnik::rgb> palette;
    std::vector<unsigned> alphaTable;
    for(unsigned i=0; i<pal.size(); i++)
    {
        palette.push_back(rgb(pal[i].r, pal[i].g, pal[i].b));
        alphaTable.push_back(pal[i].a);
    }

    if (palette.size() > 16 )
    {
        // >16 && <=256 colors -> write 8-bit color depth
        image_data_8 reduced_image(width, height);

        for (unsigned y = 0; y < height; ++y)
        {
            mapnik::image_data_32::pixel_type const * row = image.getRow(y);
            mapnik::image_data_8::pixel_type  * row_out = reduced_image.getRow(y);

            for (unsigned x = 0; x < width; ++x)
            {
                unsigned val = row[x];
                mapnik::rgba c(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val));
                row_out[x] = tree.quantize(c);
            }
        }
        save_as_png(file, palette, reduced_image, width, height, 8, alphaTable);
    }
    else if (palette.size() == 1)
    {
        // 1 color image ->  write 1-bit color depth PNG
        unsigned image_width  = (int(0.125*width) + 7)&~7;
        unsigned image_height = height;
        image_data_8 reduced_image(image_width, image_height);
        reduced_image.set(0);
        save_as_png(file, palette, reduced_image, width, height, 1, alphaTable);
    }
    else
    {
        // <=16 colors -> write 4-bit color depth PNG
        unsigned image_width  = (int(0.5*width) + 3)&~3;
        unsigned image_height = height;
        image_data_8 reduced_image(image_width, image_height);
        for (unsigned y = 0; y < height; ++y)
        {
            mapnik::image_data_32::pixel_type const * row = image.getRow(y);
            mapnik::image_data_8::pixel_type  * row_out = reduced_image.getRow(y);
            byte index = 0;

            for (unsigned x = 0; x < width; ++x)
            {
                unsigned val = row[x];
                mapnik::rgba c(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val));
                index = tree.quantize(c);
                if (x%2 == 0) index = index<<4;
                row_out[x>>1] |= index;
            }
        }
        save_as_png(file, palette, reduced_image, width, height, 4, alphaTable);
    }
}