Skip to content

Commit

Permalink
Traktor: SVG rasterizer using proper alpha mode when generating icons.
Browse files Browse the repository at this point in the history
  • Loading branch information
apistol78 committed Apr 27, 2024
1 parent a407745 commit 9e66c30
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 663 deletions.
65 changes: 36 additions & 29 deletions code/Drawing/Raster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,26 @@
#include <agg_span_allocator.h>
#include "Core/Containers/AlignedVector.h"
#include "Core/Log/Log.h"
#include "Core/Math/Envelope.h"
#include "Core/Misc/Align.h"
#include "Drawing/Image.h"
#include "Drawing/Raster.h"

namespace traktor
{

Color4f operator * (float v, const Color4f& c)
{
return c * Scalar(v);
}

Color4f operator * (const Color4f& c, float v)
{
return c * Scalar(v);
}

}

namespace traktor::drawing
{

Expand Down Expand Up @@ -141,29 +157,25 @@ class SolidStyle< agg::rgba8 > : public IStyle< agg::rgba8 >
class LinearGradientStyle : public IStyle< agg::rgba8 >
{
public:
LinearGradientStyle(const Matrix33& gradientMatrix, const AlignedVector< std::pair< Color4f, float > >& colors)
explicit LinearGradientStyle(const Matrix33& gradientMatrix, const AlignedVector< std::pair< Color4f, float > >& colors)
: m_gradientMatrix(gradientMatrix)
, m_colors(colors)
{
// Premultiply to be in "byte range".
for (AlignedVector< std::pair< Color4f, float > >::iterator i = m_colors.begin(); i != m_colors.end(); ++i)
i->first *= Scalar(255.0f);
for (const auto& p : colors)
m_envelope.addKey(p.second, p.first * 255.0_simd);
}

virtual void generateSpan(agg::rgba8* span, int x, int y, unsigned len) const override final
{
float s = m_colors.front().second;
float e = m_colors.back().second;
float n = 1.0f / (e - s);
float s = 0.0f;
float n = 1.0f;

Vector2 pt = m_gradientMatrix * Vector2(float(x), float(y));
Vector2 dt = m_gradientMatrix * Vector2(float(x + 1.0f), float(y)) - pt;

for (unsigned i = 0; i < len; ++i)
{
float f = clamp((pt.x - s) * n, 0.0f, 1.0f);

Color4f c(lerp(m_colors.front().first, m_colors.back().first, Scalar(f)));
const float f = clamp((pt.x - s) * n, 0.0f, 1.0f);
const Color4f c = m_envelope(f);

span[i] = agg::rgba8(
agg::int8u(c.getRed()),
Expand All @@ -178,36 +190,32 @@ class LinearGradientStyle : public IStyle< agg::rgba8 >

private:
Matrix33 m_gradientMatrix;
AlignedVector< std::pair< Color4f, float > > m_colors;
Envelope< Color4f, LinearEvaluator< Color4f > > m_envelope;
};

/*! Radial gradient style for 32-bit colors. */
class RadialGradientStyle : public IStyle< agg::rgba8 >
{
public:
RadialGradientStyle(const Matrix33& gradientMatrix, const AlignedVector< std::pair< Color4f, float > >& colors)
explicit RadialGradientStyle(const Matrix33& gradientMatrix, const AlignedVector< std::pair< Color4f, float > >& colors)
: m_gradientMatrix(gradientMatrix)
, m_colors(colors)
{
// Premultiply to be in "byte range".
for (AlignedVector< std::pair< Color4f, float > >::iterator i = m_colors.begin(); i != m_colors.end(); ++i)
i->first *= Scalar(255.0f);
for (const auto& p : colors)
m_envelope.addKey(p.second, p.first * 255.0_simd);
}

virtual void generateSpan(agg::rgba8* span, int x, int y, unsigned len) const override final
{
float s = m_colors.front().second;
float e = m_colors.back().second;
float n = 1.0f / (e - s);
float s = 0.0f;
float n = 1.0f;

Vector2 pt = m_gradientMatrix * Vector2(float(x), float(y));
Vector2 dt = m_gradientMatrix * Vector2(float(x + 1.0f), float(y)) - pt;

for (unsigned i = 0; i < len; ++i)
{
float f = clamp(((pt * pt).length() - s) * n, 0.0f, 1.0f);

Color4f c(lerp(m_colors.front().first, m_colors.back().first, Scalar(f)));
const float f = clamp(((pt * pt).length() - s) * n, 0.0f, 1.0f);
const Color4f c = m_envelope(f);

span[i] = agg::rgba8(
agg::int8u(c.getRed()),
Expand All @@ -222,7 +230,7 @@ class RadialGradientStyle : public IStyle< agg::rgba8 >

private:
Matrix33 m_gradientMatrix;
AlignedVector< std::pair< Color4f, float > > m_colors;
Envelope< Color4f, LinearEvaluator< Color4f > > m_envelope;
};

/*! Image style for 32-bit colors. */
Expand Down Expand Up @@ -435,7 +443,6 @@ class RasterImpl : public RefCountImpl< IRasterImpl >
: m_rbuffer((agg::int8u*)image->getData(), image->getWidth(), image->getHeight(), image->getWidth() * image->getPixelFormat().getByteSize())
, m_pf(m_rbuffer)
, m_renderer(m_pf)
// , m_closed(false)
{
}

Expand Down Expand Up @@ -656,13 +663,13 @@ bool Raster::setImage(Image* image)
m_impl = nullptr;

if (image->getPixelFormat() == PixelFormat::getA8B8G8R8())
m_impl = new RasterImpl< agg::pixfmt_rgba32, agg::rgba8 >(image);
m_impl = new RasterImpl< agg::pixfmt_rgba32_plain, agg::rgba8 >(image);
else if (image->getPixelFormat() == PixelFormat::getB8G8R8A8())
m_impl = new RasterImpl< agg::pixfmt_argb32, agg::rgba8 >(image);
m_impl = new RasterImpl< agg::pixfmt_argb32_plain, agg::rgba8 >(image);
else if (image->getPixelFormat() == PixelFormat::getA8R8G8B8())
m_impl = new RasterImpl< agg::pixfmt_bgra32, agg::rgba8 >(image);
m_impl = new RasterImpl< agg::pixfmt_bgra32_plain, agg::rgba8 >(image);
else if (image->getPixelFormat() == PixelFormat::getR8G8B8A8())
m_impl = new RasterImpl< agg::pixfmt_abgr32, agg::rgba8 >(image);
m_impl = new RasterImpl< agg::pixfmt_abgr32_plain, agg::rgba8 >(image);
else if (image->getPixelFormat() == PixelFormat::getA8())
m_impl = new RasterImpl< agg::pixfmt_gray8, agg::gray8 >(image);

Expand Down
14 changes: 12 additions & 2 deletions code/Svg/ClassFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ class ShapeVisitorDelegate : public IShapeVisitor
Ref< IRuntimeDelegate > m_delegateLeave;
};

Ref< Shape > Parser_parse(Parser* self, xml::Document* doc)
{
return self->parse(doc);
}

RefArray< BoxedSubPath > Path_getSubPaths(Path* self)
{
RefArray< BoxedSubPath > bsp;
Expand Down Expand Up @@ -124,6 +129,11 @@ void Shape_visit(Shape* self, IRuntimeDelegate* enter, IRuntimeDelegate* leave)
self->visit(&visitor);
}

Ref< drawing::Image > Rasterizer_raster(Rasterizer* self, const Document* document)
{
return self->raster(document);
}

}

T_IMPLEMENT_RTTI_FACTORY_CLASS(L"traktor.svg.ClassFactory", 0, ClassFactory, IRuntimeClassFactory)
Expand All @@ -150,7 +160,7 @@ void ClassFactory::createClasses(IRuntimeClassRegistrar* registrar) const

auto classParser = new AutoRuntimeClass< Parser >();
classParser->addConstructor();
//classParser->addMethod("parse", &Parser::parse);
classParser->addMethod("parse", &Parser_parse);
registrar->registerClass(classParser);

auto classPath = new AutoRuntimeClass< Path >();
Expand Down Expand Up @@ -211,7 +221,7 @@ void ClassFactory::createClasses(IRuntimeClassRegistrar* registrar) const

auto classRasterizer = new AutoRuntimeClass< Rasterizer >();
classRasterizer->addConstructor();
// classRasterizer->addMethod("raster", &Rasterizer::raster);
classRasterizer->addMethod("raster", &Rasterizer_raster);
registrar->registerClass(classRasterizer);
}

Expand Down
2 changes: 1 addition & 1 deletion code/Svg/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ Ref< Shape > Parser::parseRect(const xml::Element* elm)
const float y = parseAttr(elm, L"y");
const float width = parseAttr(elm, L"width");
const float height = parseAttr(elm, L"height");
const float round = parseAttr(elm, L"ry");
const float round = parseAttr(elm, L"ry") * 2.0f;

Path path;

Expand Down
22 changes: 20 additions & 2 deletions code/Svg/Rasterizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <functional>
#include "Drawing/Image.h"
#include "Drawing/Raster.h"
#include "Drawing/Filters/ScaleFilter.h"
#include "Svg/Document.h"
#include "Svg/Gradient.h"
#include "Svg/IShapeVisitor.h"
Expand Down Expand Up @@ -171,12 +172,29 @@ Ref< drawing::Image > Rasterizer::raster(const Document* document, float scale,
if (width <= 0 || height <= 0)
return nullptr;

Ref< drawing::Image > image = new drawing::Image(drawing::PixelFormat::getR8G8B8A8(), width, height);
image->clear(Color4f(1.0f, 1.0f, 1.0f, 0.0f));
const int32_t ss = 1;

Ref< drawing::Image > image = new drawing::Image(
drawing::PixelFormat::getR8G8B8A8(),
width * ss,
height * ss
);
image->clear(Color4f(0.0f, 0.0f, 0.0f, 0.0f));

if (!raster(document, image, pageOffsetX, pageOffsetY))
return nullptr;

if (ss > 1)
{
const drawing::ScaleFilter scaleFilter(
width,
height,
drawing::ScaleFilter::MnAverage,
drawing::ScaleFilter::MgLinear
);
image->apply(&scaleFilter);
}

return image;
}

Expand Down
Loading

0 comments on commit 9e66c30

Please sign in to comment.