summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 850f435)
raw | patch | inline | side by side (parent: 850f435)
author | kiirala <kiirala@users.sourceforge.net> | |
Tue, 18 Jul 2006 10:35:54 +0000 (10:35 +0000) | ||
committer | kiirala <kiirala@users.sourceforge.net> | |
Tue, 18 Jul 2006 10:35:54 +0000 (10:35 +0000) |
index 556812db59b8bd45f9afdf4430c65a1bf9097375..9ea721d3beb44ad3313abba7b3fc5adea2c1d12a 100644 (file)
_input = NR_FILTER_SLOT_NOT_SET;
_output = NR_FILTER_SLOT_NOT_SET;
+ // These defaults are according to SVG standard.
+ // NB: SVGLength.set takes prescaled percent values: 1 means 100%
_region_x.set(SVGLength::PERCENT, 0, 0);
_region_y.set(SVGLength::PERCENT, 0, 0);
_region_width.set(SVGLength::PERCENT, 1, 0);
// Nothing to do here
}
+/** Wrapper function for rendering with C-style matrices. */
int FilterPrimitive::render(FilterSlot &slot, NRMatrix const *trans) {
if(trans) {
return this->render(slot, *trans);
index 74cf7e003a1cf869576eec371d108ae26cbd6697..13ce1afe20fff919619db5fc2b9d8ac4d2f97826 100644 (file)
class FilterSlot {
public:
+ /** Creates a new FilterSlot object, with two slots. */
FilterSlot();
+ /** Creates a new FilterSlot object, with specified amount of slots */
FilterSlot(int slots);
+ /** Destroys the FilterSlot object and all its contents */
~FilterSlot();
+ /** Returns the pixblock in specified slot.
+ * Parameter 'slot' may be either an positive integer or one of
+ * pre-defined filter slot types: NR_FILTER_SLOT_NOT_SET,
+ * NR_FILTER_SOURCEGRAPHIC, NR_FILTER_SOURCEALPHA,
+ * NR_FILTER_BACKGROUNDIMAGE, NR_FILTER_BACKGROUNDALPHA,
+ * NR_FILTER_FILLPAINT, NR_FILTER_SOURCEPAINT.
+ * If the defined filter slot is not set before, this function
+ * returns NULL. Also, that filter slot is created in process.
+ */
NRPixBlock *get(int slot);
+
+ /** Sets or re-sets the pixblock associated with given slot.
+ * If there was a pixblock already assigned with this slot,
+ * that pixblock is destroyed.
+ * Pixblocks passed to this function should be considered
+ * managed by this FilterSlot object.
+ * Pixblocks passed to this function should be reserved with
+ * c++ -style new-operator.
+ */
void set(int slot, NRPixBlock *pb);
+ /** Returns the number of slots in use. */
int get_slot_count();
private:
int _last_out;
+ /** Returns the table index of given slot. If that slot dows not exist,
+ * it is created. Table index can be used to read the correct
+ * pixblock from _slot */
int _get_index(int slot);
};
index 6c57f3200a5a6a03518b0c44c609afdeee78b8b8..db1e9d8db596df27c093c8ce74d83e165534365f 100644 (file)
void Filter::_common_init() {
_slot_count = 1;
+ // Having "not set" here as value means the output of last filter
+ // primitive will be used as output of this filter
_output_slot = NR_FILTER_SLOT_NOT_SET;
+ // These are the default values for filter region,
+ // as specified in SVG standard
+ // NB: SVGLength.set takes prescaled percent values: -.10 means -10%
_region_x.set(SVGLength::PERCENT, -.10, 0);
_region_y.set(SVGLength::PERCENT, -.10, 0);
_region_width.set(SVGLength::PERCENT, 1.20, 0);
_region_height.set(SVGLength::PERCENT, 1.20, 0);
+ // Filter resolution, negative value here stands for "automatic"
_x_pixels = -1.0;
_y_pixels = -1.0;
Matrix trans = *item->ctm;
FilterSlot slot(_slot_count);
NRPixBlock *in = new NRPixBlock;
+
+ // First, if filter resolution is not set to automatic, we should
+ // scale the input image to correct resolution
if (_x_pixels >= 0) {
/* If filter resolution is zero, the object should not be rendered */
if (_x_pixels == 0 || _y_pixels == 0) {
memset(NR_PIXBLOCK_PX(pb), 0, size);
return 0;
}
+ // Resolution is specified as pixel length of our internal buffer.
+ // Though, we might not be rendering the whole object at time,
+ // so we need to calculate the correct pixel size
int x_len = (int)round(((pb->area.x1 - pb->area.x0) * _x_pixels) / (item->bbox.x1 - item->bbox.x0));
if (x_len < 1) x_len = 1;
+ // If y-resolution is also set, count y-area in the same way as x-area
+ // Otherwise, make y-area so, that aspect ratio of input pixblock and
+ // internal pixblock are the same.
int y_len;
if (_y_pixels > 0) {
y_len = (int)round(((pb->area.y1 - pb->area.y0) * _y_pixels) / (item->bbox.y1 - item->bbox.y0));
y_len / (double)(pb->area.y1 - pb->area.y0));
trans *= res_scaling;
} else {
+ // If filter resolution is automatic, just make copy of input image
nr_pixblock_setup_fast(in, pb->mode,
pb->area.x0, pb->area.y0,
pb->area.x1, pb->area.y1, true);
slot.set(NR_FILTER_SOURCEGRAPHIC, in);
in = NULL; // in is now handled by FilterSlot, we should not touch it
+ // TODO: loop through the primitives and render them one at a time
_primitive[0]->render(slot, trans);
NRPixBlock *out = slot.get(_output_slot);
+ // Clear the pixblock, where the output will be put
+ // -> the original image does not show through
int size = (pb->area.x1 - pb->area.x0)
* (pb->area.y1 - pb->area.y0)
* NR_PIXBLOCK_BPP(pb);
memset(NR_PIXBLOCK_PX(pb), 0, size);
-
+
+ // If the filter resolution is automatic, just copy our final image
+ // to output pixblock, otherwise use bicubic scaling
if (_x_pixels < 0) {
nr_blit_pixblock_pixblock(pb, out);
} else {
scale_bicubic(pb, out);
}
+ // Take note of the amount of used image slots
+ // -> next time this filter is rendered, we can reserve enough slots
+ // immediately
_slot_count = slot.get_slot_count();
return 0;
}
int Filter::get_enlarge(Matrix const &m)
{
+ // Just sum the enlargement factor of all filter elements.
+ // TODO: this both sucks and blows for filters like feOffset
+ // -> ditch this method and design a better one...
int enlarge = 0;
for ( int i = 0 ; i < _primitive_count ; i++ ) {
if(_primitive[i]) enlarge += _primitive[i]->get_enlarge(m);
}
}
+/* Constructor table holds pointers to static methods returning filter
+ * primitives. This table is indexed with FilterPrimitiveType, so that
+ * for example method in _constructor[NR_FILTER_GAUSSIANBLUR]
+ * returns a filter object of type NR::FilterGaussian.
+ */
typedef FilterPrimitive*(*FilterConstructor)();
static FilterConstructor _constructor[NR_FILTER_ENDPRIMITIVETYPE];
void Filter::_create_constructor_table()
{
+ // Constructor table won't change in run-time, so no need to recreate
static bool created = false;
if(created) return;
_constructor[NR_FILTER_SPECULARLIGHTING] = NULL;
_constructor[NR_FILTER_TILE] = NULL;
_constructor[NR_FILTER_TURBULENCE] = NULL;
+ created = true;
}
+/** Helper method for enlarging table of filter primitives. When new
+ * primitives are added, but we have no space for them, this function
+ * makes some more space.
+ */
void Filter::_enlarge_primitive_table() {
FilterPrimitive **new_tbl = new FilterPrimitive*[_primitive_table_size * 2];
for (int i = 0 ; i < _primitive_count ; i++) {
index 3b8461383d4eacf1ff4957e3ca2e59b44028175a..3be52c3f30878ab6f2bb5485129712e206acaa20 100644 (file)
#define __NR_PIXBLOCK_SCALER_CPP__
+/*
+ * Functions for blitting pixblocks using scaling
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
#include <glib.h>
#include <cmath>
using std::floor;
int r, g, b, a;
};
-inline int sampley(unsigned const char a, unsigned const char b, unsigned const char c, unsigned const char d, const double len) {
+/** Calculates cubically interpolated value of the four given pixel values.
+ * The pixel values should be from four vertically adjacent pixels.
+ * If we are calculating a pixel, whose y-coordinate in source image is
+ * i, these pixel values a, b, c and d should come from lines
+ * floor(i) - 1, floor(i), floor(i) + 1, floor(i) + 2, respectively.
+ * Parameter len should be set to i.
+ * Returns the interpolated value in fixed point format with 8 bit
+ * decimal part. (24.8 assuming 32-bit int)
+ */
+__attribute__ ((const))
+inline int sampley(unsigned const char a, unsigned const char b,
+ unsigned const char c, unsigned const char d,
+ const double len)
+{
double lenf = len - floor(len);
int sum = 0;
sum += (int)((((-1.0 / 3.0) * lenf + 4.0 / 5.0) * lenf - 7.0 / 15.0)
return sum;
}
+/** Calculates cubically interpolated value of the four given pixel values.
+ * The pixel values should be interpolated values from sampley, from four
+ * horizontally adjacent vertical lines. The parameters a, b, c and d
+ * should be in fixed point format with 8-bit decimal part.
+ * If we are calculating a pixel, whose x-coordinate in source image is
+ * i, these vertical lines from where a, b, c and d are calculated, should be
+ * floor(i) - 1, floor(i), floor(i) + 1, floor(i) + 2, respectively.
+ * Parameter len should be set to i.
+ * Returns the interpolated value in 8-bit format, ready to be written
+ * to output buffer.
+ */
inline unsigned char samplex(const int a, const int b, const int c, const int d, const double len) {
double lenf = len - floor(len);
int sum = 0;
sum += (int)(c * ((((1 - lenf) - 9.0 / 5.0) * (1 - lenf) - 1.0 / 5.0) * (1 - lenf) + 1.0));
sum += (int)(d * (((-1.0 / 3.0) * (1 - lenf) + 4.0 / 5.0) * (1 - lenf) - 7.0 / 15.0) * (1 - lenf));
if (sum < 0) sum = 0;
- if (sum > 255*256) sum = 255 * 256;
+ if (sum >= 256*256) sum = 255 * 256;
return (unsigned char)(sum / 256);
}
@@ -54,16 +89,27 @@ inline void _check_index(NRPixBlock const * const pb, int const location, int co
void scale_bicubic(NRPixBlock *to, NRPixBlock *from)
{
+ if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) {
+ g_warning("A non-32-bpp image passed to scale_bicubic: scaling aborted.");
+ return;
+ }
+
+ // Precalculate sizes of source and destination pixblocks
int from_width = from->area.x1 - from->area.x0;
int from_height = from->area.y1 - from->area.y0;
int to_width = to->area.x1 - to->area.x0;
int to_height = to->area.y1 - to->area.y0;
+ // from_step: when advancing one pixel in destination image,
+ // how much we should advance in source image
double from_stepx = (double)from_width / (double)to_width;
double from_stepy = (double)from_height / (double)to_height;
+ // Loop through every pixel of destination image, a line at a time
for (int to_y = 0 ; to_y < to_height ; to_y++) {
double from_y = to_y * from_stepy + from_stepy / 2;
+ // Pre-calculate beginning of the four horizontal lines, from
+ // which we should read
int from_line[4];
for (int i = 0 ; i < 4 ; i++) {
if ((int)floor(from_y) + i - 1 >= 0) {
from_line[i] = 0;
}
}
+ // Loop through this horizontal line in destination image
+ // For every pixel, calculate the color of pixel with
+ // bicubic interpolation and set the pixel value in destination image
for (int to_x = 0 ; to_x < to_width ; to_x++) {
double from_x = to_x * from_stepx + from_stepx / 2;
RGBA line[4];
index 1e30d0a34a7fe9907c66801ed7b6e4e7328bb660..907429257bf2f1e8dc45f04c21e1f676305589ab 100644 (file)
#ifndef __NR_PIXBLOCK_SCALER_H__
#define __NR_PIXBLOCK_SCALER_H__
+/*
+ * Functions for blitting pixblocks using scaling
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
#include "libnr/nr-pixblock.h"
namespace NR {
+/** Blits the second pixblock to the first.
+ * Image in source pixblock is scaled to the size of destination pixblock
+ * using bicubic interpolation.
+ * Source pixblock is not modified in process.
+ * Only works for 32-bpp images.
+ */
void scale_bicubic(NRPixBlock *to, NRPixBlock *from);
} /* namespace NR */