Skip to content

Commit

Permalink
Add alpha blending to draw_image() (celiagg#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwiggins authored Mar 26, 2021
1 parent 9e6a3a8 commit 517ecb2
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 5 deletions.
1 change: 1 addition & 0 deletions celiagg/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <agg_renderer_scanline.h>
#include <agg_rendering_buffer.h>
#include <agg_scanline_p.h>
#include <agg_span_converter.h>

#include "canvas_impl.h"
#include "font_cache.h"
Expand Down
2 changes: 0 additions & 2 deletions celiagg/canvas.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ void canvas<pixfmt_t>::draw_image(Image& img,
const agg::trans_affine& transform, const GraphicsState& gs)
{
_set_clipping(gs.clip_box());
// XXX: Apply master alpha here somehow!

if (gs.stencil() == NULL)
{
_draw_image_internal<renderer_t>(img, transform, gs, m_renderer);
Expand Down
57 changes: 54 additions & 3 deletions celiagg/canvas_image.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,32 @@
// Authors: Erik Hvatum <[email protected]>
// John Wiggins

// This is taken from the "image_alpha.cpp" AGG example
template <typename color_type>
class span_conv_alpha
{
public:
typedef agg::cover_type alpha_type;

span_conv_alpha(const alpha_type alpha) : m_alpha(alpha) {}
void prepare() {}

void generate(color_type* span, int x, int y, unsigned len) const
{
do
{
// It's a bit of a hack, but we can treat the 8-bit alpha value as a cover.
span->a = color_type::mult_cover(color_type::full_value(), m_alpha);
++span;
}
while(--len);
}

private:
const alpha_type m_alpha;
};


template<typename pixfmt_t>
template<typename base_renderer_t>
void canvas<pixfmt_t>::_draw_image_internal(Image& img,
Expand All @@ -32,6 +58,7 @@ void canvas<pixfmt_t>::_draw_image_internal(Image& img,
{
typedef typename image_filters<pixfmt_t>::source_t source_t;
typedef agg::conv_transform<agg::path_storage> trans_curve_t;
typedef span_conv_alpha<typename pixfmt_t::color_type> conv_t;

pixfmt_t src_pix(img.get_buffer());
typename pixfmt_t::color_type back_color(agg::rgba(0.5, 0.5, 0.5, 1.0));
Expand All @@ -53,15 +80,31 @@ void canvas<pixfmt_t>::_draw_image_internal(Image& img,
typedef typename image_filters<pixfmt_t>::nearest_t span_gen_t;

span_gen_t span_generator(source, interpolator);
_draw_image_final<base_renderer_t>(renderer, span_generator);
if (gs.master_alpha() < 1.0) {
typedef typename agg::span_converter<span_gen_t, conv_t> span_conv_t;

conv_t converter(agg::cover_type(gs.master_alpha() * 255));
span_conv_t span_converer(span_generator, converter);
_draw_image_final<base_renderer_t>(renderer, span_converer);
} else {
_draw_image_final<base_renderer_t>(renderer, span_generator);
}
break;
}
case GraphicsState::InterpolationBilinear:
{
typedef typename image_filters<pixfmt_t>::bilinear_t span_gen_t;

span_gen_t span_generator(source, interpolator);
_draw_image_final<base_renderer_t>(renderer, span_generator);
if (gs.master_alpha() < 1.0) {
typedef typename agg::span_converter<span_gen_t, conv_t> span_conv_t;

conv_t converter(agg::cover_type(gs.master_alpha() * 255));
span_conv_t span_converer(span_generator, converter);
_draw_image_final<base_renderer_t>(renderer, span_converer);
} else {
_draw_image_final<base_renderer_t>(renderer, span_generator);
}
break;
}
case GraphicsState::InterpolationBicubic:
Expand Down Expand Up @@ -100,7 +143,15 @@ void canvas<pixfmt_t>::_draw_image_internal(Image& img,
}

span_gen_t span_generator(source, interpolator, filter);
_draw_image_final<base_renderer_t>(renderer, span_generator);
if (gs.master_alpha() < 1.0) {
typedef typename agg::span_converter<span_gen_t, conv_t> span_conv_t;

conv_t converter(agg::cover_type(gs.master_alpha() * 255));
span_conv_t span_converer(span_generator, converter);
_draw_image_final<base_renderer_t>(renderer, span_converer);
} else {
_draw_image_final<base_renderer_t>(renderer, span_generator);
}
break;
}
}
Expand Down
68 changes: 68 additions & 0 deletions examples/image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# The MIT License (MIT)
#
# Copyright (c) 2016-2021 Celiagg Contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Authors: John Wiggins
import math

import numpy as np
from PIL import Image

import celiagg as agg

SIZE = 1000
HALF = SIZE / 2
QUARTER = HALF / 2
IMG_X = 50
IMG_Y = 50
image = np.random.randint(0, 256, size=(IMG_Y, IMG_X, 4), dtype=np.uint8)
image[:, :, 3] = 255

box = agg.Path()
box.rect(0, 0, HALF, HALF)

canvas = agg.CanvasRGB24(np.zeros((SIZE, SIZE, 3), dtype=np.uint8))
gs = agg.GraphicsState(drawing_mode=agg.DrawingMode.DrawFill)
transform = agg.Transform()
blue_paint = agg.SolidPaint(0.1, 0.1, 1.0)

canvas.clear(1, 1, 1)
canvas.draw_shape(box, transform, gs, fill=blue_paint)

gs.master_alpha = 0.5
positions = (
(HALF - IMG_X/2, QUARTER - IMG_Y/2,
math.pi / 3, agg.InterpolationMode.Bilinear),
(HALF - IMG_X/2, HALF - IMG_Y/2,
math.pi / 4, agg.InterpolationMode.Bicubic),
(QUARTER - IMG_X/2, HALF - IMG_Y/2,
math.pi / 6, agg.InterpolationMode.Sinc64),
)
for (x, y, rot, interp) in positions:
transform.reset()
transform.translate(-IMG_X, -IMG_Y)
transform.scale(4, 4)
transform.translate(x/4, y/4)
transform.rotate(rot)
gs.image_interpolation_mode = interp
canvas.draw_image(image, agg.PixelFormat.RGBA32, transform, gs)

Image.fromarray(canvas.array).save('image.png')

0 comments on commit 517ecb2

Please sign in to comment.