Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test/gradients #303

Merged
merged 2 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/xml/modules/classes/vectorgradient.xml
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@
<access read="G" write="S">Get/Set</access>
<type>DOUBLE</type>
<description>
<p>The <code>(X1, Y1)</code> field values define the starting coordinate for mapping linear gradients. Other gradient types ignore these values. The gradient will be drawn from <code>(X1, Y1)</code> to <code>(X2, Y2)</code>.</p>
<p>Coordinate values can be expressed as percentages that are scaled to the target space.</p>
<p>For linear gradients, the <code>(X1, Y1)</code> field values define the starting coordinate for mapping linear gradients. The gradient will be drawn from <code>(X1, Y1)</code> to <code>(X2, Y2)</code>. Coordinate values can be expressed as units that are scaled to the target space.</p>
<p>For contour gradients, <code>X1</code> is used as the floor for the gradient colour values and <code>X2</code> acts as a multiplier. <code>X1</code> has a range of <code>0 &lt; X1 &lt; X2</code> and <code>X2</code> has a range of <code>.01 &lt; X2 &lt; 4</code>.</p>
</description>
</field>

Expand All @@ -245,8 +245,8 @@
<access read="G" write="S">Get/Set</access>
<type>DOUBLE</type>
<description>
<p>The <code>(X2, Y2)</code> field values define the end coordinate for mapping linear gradients. Other gradient types ignore these values. The gradient will be drawn from <code>(X1, Y1)</code> to <code>(X2, Y2)</code>.</p>
<p>Coordinate values can be expressed as percentages that are scaled to the target space.</p>
<p>For linear gradients, the <code>(X1, Y1)</code> field values define the starting coordinate for mapping linear gradients. The gradient will be drawn from <code>(X1, Y1)</code> to <code>(X2, Y2)</code>. Coordinate values can be expressed as units that are scaled to the target space.</p>
<p>For contour gradients, <code>X1</code> is used as the floor for the gradient colour values and <code>X2</code> acts as a multiplier. <code>X1</code> has a range of <code>0 &lt; X1 &lt; X2</code> and <code>X2</code> has a range of <code>.01 &lt; X2 &lt; 4</code>.</p>
</description>
</field>

Expand All @@ -257,7 +257,7 @@
<type>DOUBLE</type>
<description>
<p>The <code>(X1, Y1)</code> field values define the starting coordinate for mapping linear gradients. Other gradient types ignore these values. The gradient will be drawn from <code>(X1, Y1)</code> to <code>(X2, Y2)</code>.</p>
<p>Coordinate values can be expressed as percentages that are scaled to the target space.</p>
<p>Coordinate values can also be expressed as units that are scaled to the target space.</p>
</description>
</field>

Expand All @@ -268,7 +268,7 @@
<type>DOUBLE</type>
<description>
<p>The <code>(X2, Y2)</code> field values define the end coordinate for mapping linear gradients. Other gradient types ignore these values. The gradient will be drawn from <code>(X1, Y1)</code> to <code>(X2, Y2)</code>.</p>
<p>Coordinate values can be expressed as percentages that are scaled to the target space.</p>
<p>Coordinate values can also be expressed as units that are scaled to the target space.</p>
</description>
</field>

Expand Down
31 changes: 17 additions & 14 deletions examples/gradients.fluid
Original file line number Diff line number Diff line change
Expand Up @@ -37,43 +37,45 @@ function selectGradient(Text)
elseif Text == 'Contour' then
gradient.type = 'contour'
gradient.x1 = 0
gradient.x2 = 512
gradient.x2 = 2.0
uiEvent = function(ev)
local x = math.abs(ev.x - (gradientVP.width * 0.5))
local y = math.abs(ev.y - (gradientVP.height * 0.5))
local x = math.abs(ev.x - (gradientVP.width * 0.5)) / gradientVP.width * 2
local y = math.abs(ev.y - (gradientVP.height * 0.5)) / gradientVP.height * 2

if x > y then
gradient.x1 = x
gradient.x1 = x * gradient.x2
else
gradient.x1 = y
gradient.x1 = y * gradient.x2
end
end
elseif Text == 'Contour Low-Res' then
gradient.type = 'contour'
gradient.x1 = 0
gradient.x2 = LORES_COUNT
gradient.x2 = LORES_COUNT/256
uiEvent = function(ev)
local xscale = math.abs(ev.x - (gradientVP.width * 0.5)) / gradientVP.width * 2
local yscale = math.abs(ev.y - (gradientVP.height * 0.5)) / gradientVP.height * 2
if xscale > yscale then
gradient.x1 = xscale * LORES_COUNT
gradient.x1 = xscale * LORES_COUNT/256
else
gradient.x1 = yscale * LORES_COUNT
gradient.x1 = yscale * LORES_COUNT/256
end
gradient.x2 = LORES_COUNT
gradient.x2 = LORES_COUNT/256
end
elseif Text == 'Contour Shape' then
contourShape.visibility = 'visible'
gradient.type = 'contour'
rect.visibility = 'hidden'
gradient.x1 = 211
gradient.x2 = 256
gradient.x1 = 0.9
gradient.x2 = 1.0
uiEvent = function(ev)
local xscale = math.abs(ev.x - (gradientVP.width * 0.5)) / gradientVP.width * 2
local yscale = math.abs(ev.y - (gradientVP.height * 0.5)) / gradientVP.height * 2

if xscale > yscale then
gradient.x1 = xscale*256
gradient.x1 = xscale
else
gradient.x1 = yscale*256
gradient.x1 = yscale
end
end
elseif Text == 'Linear' then
Expand All @@ -83,7 +85,8 @@ function selectGradient(Text)
gradient.cY = (ev.y / gradientVP.height * 100) .. '%'
gradient.x2 = (ev.x / gradientVP.width * 100) .. '%'
gradient.y2 = (ev.y / gradientVP.height * 100) .. '%'
end gradient.x1 = '50%'
end
gradient.x1 = '50%'
gradient.y1 = '50%'
gradient.x2 = '100%'
gradient.y2 = '100%'
Expand Down
8 changes: 7 additions & 1 deletion src/picture/picture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,13 @@ static ERR PICTURE_SaveImage(extPicture *Self, struct acSaveImage *Args)
}
else {
png_set_IHDR(write_ptr, info_ptr, bmp->Width, bmp->Height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_PLTE(write_ptr, info_ptr, (png_colorp)bmp->Palette->Col, bmp->AmtColours);

std::vector<png_color> p(bmp->Palette->AmtColours);
for (LONG i=0; i < bmp->Palette->AmtColours; i++) {
p[i] = { bmp->Palette->Col[i].Red, bmp->Palette->Col[i].Green, bmp->Palette->Col[i].Blue };
}

png_set_PLTE(write_ptr, info_ptr, p.data(), bmp->AmtColours);
}

// On Intel CPU's the pixel format is BGR
Expand Down
2 changes: 1 addition & 1 deletion src/svg/gradients.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ void svgState::parse_contourgradient(const XMLTag &Tag, objVectorGradient *Gradi
auto &val = Tag.Attribs[a].Value;
if (val.empty()) continue;

log.trace("Processing contour gradient attribute %s = %s", Tag.Attribs[a].Name, val);
log.trace("Processing contour gradient attribute %s = %s", Tag.Attribs[a].Name, val);

auto attrib = strihash(Tag.Attribs[a].Name);
switch(attrib) {
Expand Down
18 changes: 13 additions & 5 deletions src/svg/tests/gradients/contour-gradient.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/svg/tests/test-svg.fluid
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ function testW3TransformAttr05() hashTestSVG('transforms/w3-coords-transformattr

function testCSS() hashTestSVG('misc/css.svg', 0x586302af) end
function testBrushStrokes() hashTestSVG('misc/brush-strokes.svg', 0x21e65d43) end
function testContourGradient() hashTestSVG('gradients/contour-gradient.svg', 0x5726053f) end
function testContourGradient() hashTestSVG('gradients/contour-gradient.svg', 0xab4dcff7) end

function testBottleTree() hashTestSVG('images/bottletree.svg', 0xd7fb84ff) end
function testButton() hashTestSVG('images/button.svg', 0x0e8f5a31) end
Expand Down
82 changes: 33 additions & 49 deletions src/vector/agg/include/agg_span_gradient_contour.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@
#include "agg_rasterizer_outline.h"
#include "agg_span_gradient.h"

#define infinity 1E20
constexpr double infinity = 1E20;

namespace agg
{
class gradient_contour {
private:
std::vector<int8u> m_buffer;
int m_width;
int m_height;
int m_frame;
double m_d1;
double m_d2;
int m_width, m_height;
double m_d1; // Ranges from 0 to 254
double m_d2; // Ranges from 0.001 to 1.0

public:
gradient_contour() : m_buffer(NULL), m_width(0), m_height(0), m_frame(10), m_d1(0), m_d2(100) { }
gradient_contour(double d1, double d2) : m_buffer(NULL), m_width(0), m_height(0), m_frame(10), m_d1(d1), m_d2(d2) { }
gradient_contour() : m_width(0), m_height(0), m_d1(0), m_d2(1.0) { }
gradient_contour(double d1, double d2) : m_width(0), m_height(0), m_d2(d2) {
m_d1 = (d1 > 254) ? 254 : d1;
}

int8u* contour_create(path_storage &ps);

Expand All @@ -51,73 +51,64 @@
void d1(double d) { m_d1 = d; }
void d2(double d) { m_d2 = d; }

void frame(int f) { m_frame = f; }
int frame() { return m_frame; }

int calculate(int x, int y, int d) const {
if (!m_buffer.empty()) {
int px = x >> agg::gradient_subpixel_shift;
int py = y >> agg::gradient_subpixel_shift;
int px = (x >> agg::gradient_subpixel_shift) % m_width;
int py = (y >> agg::gradient_subpixel_shift) % m_height;

px %= m_width;
if (px < 0) px += m_width;
py %= m_height;
if (py < 0) py += m_height;
return iround(m_buffer[py * m_width + px ] * (m_d2 / 256) + m_d1) << gradient_subpixel_shift;
return iround((m_buffer[(py * m_width) + px] * m_d2) + m_d1) << gradient_subpixel_shift;
}
else return 0;
}
};

static constexpr int square(int x) { return x * x; }

// DT algorithm by: Pedro Felzenszwalb
// Distance transform algorithm by: Pedro Felzenszwalb
void dt(std::vector<double> &spanf, std::vector<double> &spang, std::vector<double> &spanr, std::vector<int> &spann, int length)
{
int k = 0;
double s;

spann[0] = 0;
spang[0] = double(-infinity);
spang[1] = double(+infinity);
spang[0] = -infinity;
spang[1] = +infinity;

int k = 0;
for (int q = 1; q <= length - 1; q++) {
s = ((spanf[q ] + square(q)) - (spanf[spann[k]] + square(spann[k]))) / (2 * q - 2 * spann[k]);
double s = ((spanf[q ] + square(q)) - (spanf[spann[k]] + square(spann[k]))) / (2 * q - 2 * spann[k]);

while (s <= spang[k ]) {
k--;
s = ((spanf[q] + square(q)) - (spanf[spann[k]] + square(spann[k]))) / (2 * q - 2 * spann[k]);
}

k++;
spann[k ] = q;
spang[k ] = s;
spang[k + 1 ] = double(+infinity);
spann[k] = q;
spang[k] = s;
spang[k + 1] = +infinity;
}

k = 0;
int j = 0;
for (int q = 0; q <= length - 1; q++) {
while (spang[k + 1] < q) k++;
spanr[q] = square(q - spann[k]) + spanf[spann[k]];
while (spang[j + 1] < q) j++;
spanr[q] = square(q - spann[j]) + spanf[spann[j]];
}
}

// DT algorithm by: Pedro Felzenszwalb
// Distance transform algorithm by: Pedro Felzenszwalb
int8u* gradient_contour::contour_create(path_storage &ps) {
// I. Render Black And White NonAA Stroke of the Path
// Path Bounding Box + Some Frame Space Around [configurable]
agg::conv_curve<agg::path_storage> conv(ps);

double x1, y1, x2, y2;

if (agg::bounding_rect_single(conv, 0, &x1, &y1, &x2, &y2)) {
// Create BW Rendering Surface
int width = int(ceil(x2 - x1)) + m_frame * 2 + 1;
int height = int(ceil(y2 - y1)) + m_frame * 2 + 1;
auto size = width * height;
auto width = int(ceil(x2 - x1)) + 1;
auto height = int(ceil(y2 - y1)) + 1;

m_buffer.resize(size);
memset(m_buffer.data(), 255, size);
m_buffer.resize(width * height);

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type High

Multiplication result may overflow 'int' before it is converted to 'size_type'.

Copilot Autofix AI 22 days ago

To fix the problem, we need to ensure that the multiplication is performed using a larger integer type to prevent overflow. This can be achieved by casting one of the operands to size_t before performing the multiplication. This way, the multiplication will be done in the larger type, and the result will be correctly interpreted as a size_t.

  • Cast one of the operands (width or height) to size_t before the multiplication.
  • Update the line where the multiplication occurs to ensure the correct type is used.
Suggested changeset 1
src/vector/agg/include/agg_span_gradient_contour.h

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/vector/agg/include/agg_span_gradient_contour.h b/src/vector/agg/include/agg_span_gradient_contour.h
--- a/src/vector/agg/include/agg_span_gradient_contour.h
+++ b/src/vector/agg/include/agg_span_gradient_contour.h
@@ -109,3 +109,3 @@
 
-			m_buffer.resize(width * height);
+			m_buffer.resize(static_cast<size_t>(width) * height);
          std::fill(m_buffer.begin(), m_buffer.end(), 255);
EOF
@@ -109,3 +109,3 @@

m_buffer.resize(width * height);
m_buffer.resize(static_cast<size_t>(width) * height);
std::fill(m_buffer.begin(), m_buffer.end(), 255);
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
std::fill(m_buffer.begin(), m_buffer.end(), 255);

// Setup VG Engine & Render
agg::rendering_buffer rb;
Expand All @@ -129,7 +120,7 @@
agg::rasterizer_outline<renderer_primitives<agg::renderer_base<agg::pixfmt_gray8>>> ras(prim);

agg::trans_affine mtx;
mtx *= agg::trans_affine_translation(-x1 + m_frame, -y1 + m_frame);
mtx.translate(-x1, -y1);

agg::conv_transform<agg::conv_curve<agg::path_storage>> trans(conv, mtx);

Expand All @@ -143,7 +134,7 @@
for (int y=0, l=0; y < height; y++) {
for (int x=0; x < width; x++, l++) {
if (m_buffer[l] == 0) image[l] = 0.0;
else image[l] = double(infinity);
else image[l] = infinity;
}
}

Expand All @@ -160,16 +151,12 @@

// Transform along columns
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
spanf[y] = image[y * width + x];
}
for (int y = 0; y < height; y++) spanf[y] = image[y * width + x];

// DT of 1d
dt(spanf, spang, spanr, spann, height);

for (int y=0; y < height; y++) {
image[y * width + x] = spanr[y];
}
for (int y=0; y < height; y++) image[y * width + x] = spanr[y];
}

// Transform along rows
Expand All @@ -195,14 +182,11 @@
}

// III. Convert To Grayscale
if (min == max) {
auto size = width * height;
memset(m_buffer.data(), 0, size);
}
if (min == max) m_buffer.clear();
else {
double scale = 255.0 / (max - min);
for (int y=0, l=0; y < height; y++) {
for (int x=0; x < width; x++ ,l++) m_buffer[l] = int8u(int((image[l] - min) * scale));
for (int x=0; x < width; x++, l++) m_buffer[l] = int8u(int((image[l] - min) * scale));
}
}

Expand Down
Loading
Loading