bool THRawBitmap::_checkScaled(THRenderTarget* pCanvas, SDL_Rect& rcDest) { float fFactor; if(!pCanvas->shouldScaleBitmaps(&fFactor)) return false; int iScaledWidth = (int)((float)m_pBitmap->w * fFactor); if(!m_pCachedScaledBitmap || m_pCachedScaledBitmap->w != iScaledWidth) { SDL_FreeSurface(m_pCachedScaledBitmap); Uint32 iRMask, iGMask, iBMask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN iRMask = 0xff000000; iGMask = 0x00ff0000; iBMask = 0x0000ff00; #else iRMask = 0x000000ff; iGMask = 0x0000ff00; iBMask = 0x00ff0000; #endif m_pCachedScaledBitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, iScaledWidth, (int)((float)m_pBitmap->h * fFactor), 24, iRMask, iGMask, iBMask, 0); SDL_LockSurface(m_pCachedScaledBitmap); SDL_LockSurface(m_pBitmap); typedef agg::pixfmt_rgb24_pre pixfmt_pre_t; typedef agg::renderer_base<pixfmt_pre_t> renbase_pre_t; typedef image_accessor_clip_rgb24_pal8<pixfmt_pre_t> imgsrc_t; typedef agg::span_interpolator_linear<> interpolator_t; typedef agg::span_image_filter_rgb_2x2<imgsrc_t, interpolator_t> span_gen_type; agg::scanline_p8 sl; agg::span_allocator<pixfmt_pre_t::color_type> sa; agg::image_filter<agg::image_filter_bilinear> filter; agg::trans_affine_scaling img_mtx(1.0 / fFactor); agg::rendering_buffer rbuf_src(m_pData, m_pBitmap->w, m_pBitmap->h, m_pBitmap->pitch); imgsrc_t img_src(rbuf_src, *m_pPalette, agg::rgba(0.0, 0.0, 0.0)); interpolator_t interpolator(img_mtx); span_gen_type sg(img_src, interpolator, filter); agg::rendering_buffer rbuf(reinterpret_cast<unsigned char*>(m_pCachedScaledBitmap->pixels), m_pCachedScaledBitmap->w, m_pCachedScaledBitmap->h, m_pCachedScaledBitmap->pitch); pixfmt_pre_t pixf_pre(rbuf); renbase_pre_t rbase_pre(pixf_pre); rasterizer_scanline_rect ras(0, 0, rbuf.width(), rbuf.height()); rbase_pre.clear(agg::rgba(1.0,0,0,0)); agg::render_scanlines_aa(ras, sl, rbase_pre, sa, sg); SDL_UnlockSurface(m_pBitmap); SDL_UnlockSurface(m_pCachedScaledBitmap); } rcDest.x = (Sint16)((float)rcDest.x * fFactor); rcDest.y = (Sint16)((float)rcDest.y * fFactor); return true; }
void scale_image_agg(T & target, T const& source, scaling_method_e scaling_method, double image_ratio_x, double image_ratio_y, double x_off_f, double y_off_f, double filter_factor) { // "the image filters should work namely in the premultiplied color space" // http://old.nabble.com/Re:--AGG--Basic-image-transformations-p1110665.html // "Yes, you need to use premultiplied images only. Only in this case the simple weighted averaging works correctly in the image fitering." // http://permalink.gmane.org/gmane.comp.graphics.agg/3443 using image_type = T; using pixel_type = typename image_type::pixel_type; using pixfmt_pre = typename detail::agg_scaling_traits<image_type>::pixfmt_pre; using color_type = typename detail::agg_scaling_traits<image_type>::color_type; using img_src_type = typename detail::agg_scaling_traits<image_type>::img_src_type; using interpolator_type = typename detail::agg_scaling_traits<image_type>::interpolator_type; using renderer_base_pre = agg::renderer_base<pixfmt_pre>; constexpr std::size_t pixel_size = sizeof(pixel_type); // define some stuff we'll use soon agg::rasterizer_scanline_aa<> ras; agg::scanline_u8 sl; agg::span_allocator<color_type> sa; // initialize source AGG buffer agg::rendering_buffer rbuf_src(const_cast<unsigned char*>(source.bytes()), source.width(), source.height(), source.width() * pixel_size); pixfmt_pre pixf_src(rbuf_src); img_src_type img_src(pixf_src); // initialize destination AGG buffer (with transparency) agg::rendering_buffer rbuf_dst(target.bytes(), target.width(), target.height(), target.width() * pixel_size); pixfmt_pre pixf_dst(rbuf_dst); renderer_base_pre rb_dst_pre(pixf_dst); // create a scaling matrix agg::trans_affine img_mtx; img_mtx /= agg::trans_affine_scaling(image_ratio_x, image_ratio_y); // create a linear interpolator for our scaling matrix interpolator_type interpolator(img_mtx); // draw an anticlockwise polygon to render our image into double scaled_width = target.width(); double scaled_height = target.height(); ras.reset(); ras.move_to_d(x_off_f, y_off_f); ras.line_to_d(x_off_f + scaled_width, y_off_f); ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height); ras.line_to_d(x_off_f, y_off_f + scaled_height); if (scaling_method == SCALING_NEAR) { using span_gen_type = typename detail::agg_scaling_traits<image_type>::span_image_filter; span_gen_type sg(img_src, interpolator); agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); } else { using span_gen_type = typename detail::agg_scaling_traits<image_type>::span_image_resample_affine; agg::image_filter_lut filter; detail::set_scaling_method(filter, scaling_method, filter_factor); span_gen_type sg(img_src, interpolator, filter); agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); } }
void scale_image_agg(Image & target, Image const& source, scaling_method_e scaling_method, double image_ratio, double x_off_f, double y_off_f, double filter_radius, double ratio) { // "the image filters should work namely in the premultiplied color space" // http://old.nabble.com/Re:--AGG--Basic-image-transformations-p1110665.html // "Yes, you need to use premultiplied images only. Only in this case the simple weighted averaging works correctly in the image fitering." // http://permalink.gmane.org/gmane.comp.graphics.agg/3443 typedef agg::pixfmt_rgba32_pre pixfmt_pre; typedef agg::renderer_base<pixfmt_pre> renderer_base_pre; // define some stuff we'll use soon agg::rasterizer_scanline_aa<> ras; agg::scanline_u8 sl; agg::span_allocator<agg::rgba8> sa; agg::image_filter_lut filter; // initialize source AGG buffer agg::rendering_buffer rbuf_src((unsigned char*)source.getBytes(), source.width(), source.height(), source.width() * 4); pixfmt_pre pixf_src(rbuf_src); typedef agg::image_accessor_clone<pixfmt_pre> img_src_type; img_src_type img_src(pixf_src); // initialize destination AGG buffer (with transparency) agg::rendering_buffer rbuf_dst((unsigned char*)target.getBytes(), target.width(), target.height(), target.width() * 4); pixfmt_pre pixf_dst(rbuf_dst); renderer_base_pre rb_dst_pre(pixf_dst); rb_dst_pre.clear(agg::rgba(0, 0, 0, 0)); // create a scaling matrix agg::trans_affine img_mtx; img_mtx /= agg::trans_affine_scaling(image_ratio * ratio, image_ratio * ratio); // create a linear interpolator for our scaling matrix typedef agg::span_interpolator_linear<> interpolator_type; interpolator_type interpolator(img_mtx); // draw an anticlockwise polygon to render our image into double scaled_width = target.width(); double scaled_height = target.height(); ras.reset(); ras.move_to_d(x_off_f, y_off_f); ras.line_to_d(x_off_f + scaled_width, y_off_f); ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height); ras.line_to_d(x_off_f, y_off_f + scaled_height); switch(scaling_method) { case SCALING_NEAR: { typedef agg::span_image_filter_rgba_nn<img_src_type, interpolator_type> span_gen_type; span_gen_type sg(img_src, interpolator); agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); return; } case SCALING_BILINEAR: case SCALING_BILINEAR8: filter.calculate(agg::image_filter_bilinear(), true); break; case SCALING_BICUBIC: filter.calculate(agg::image_filter_bicubic(), true); break; case SCALING_SPLINE16: filter.calculate(agg::image_filter_spline16(), true); break; case SCALING_SPLINE36: filter.calculate(agg::image_filter_spline36(), true); break; case SCALING_HANNING: filter.calculate(agg::image_filter_hanning(), true); break; case SCALING_HAMMING: filter.calculate(agg::image_filter_hamming(), true); break; case SCALING_HERMITE: filter.calculate(agg::image_filter_hermite(), true); break; case SCALING_KAISER: filter.calculate(agg::image_filter_kaiser(), true); break; case SCALING_QUADRIC: filter.calculate(agg::image_filter_quadric(), true); break; case SCALING_CATROM: filter.calculate(agg::image_filter_catrom(), true); break; case SCALING_GAUSSIAN: filter.calculate(agg::image_filter_gaussian(), true); break; case SCALING_BESSEL: filter.calculate(agg::image_filter_bessel(), true); break; case SCALING_MITCHELL: filter.calculate(agg::image_filter_mitchell(), true); break; case SCALING_SINC: filter.calculate(agg::image_filter_sinc(filter_radius), true); break; case SCALING_LANCZOS: filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; case SCALING_BLACKMAN: filter.calculate(agg::image_filter_blackman(filter_radius), true); break; } // details on various resampling considerations // http://old.nabble.com/Re%3A-Newbie---texture-p5057255.html // high quality resampler //typedef agg::span_image_resample_rgba_affine<img_src_type> span_gen_type; // faster, lower quality //typedef agg::span_image_filter_rgba<img_src_type,interpolator_type> span_gen_type; // local, modified agg::span_image_resample_rgba_affine // not convinced we need this // https://github.com/mapnik/mapnik/issues/1489 typedef mapnik::span_image_resample_rgba_affine<img_src_type> span_gen_type; span_gen_type sg(img_src, interpolator, filter); agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); }