drawing-image.cpp revision ad90ddf22d75b5ce8a62de1b2a2d826d39a9440c
1ec681f88b68c6186b267afcce12c7fd667cc9f8tgdwyer * Bitmap image belonging to an SVG drawing.
1ec681f88b68c6186b267afcce12c7fd667cc9f8tgdwyer * Krzysztof KosiĆski <tweenk.pl@gmail.com>
1ec681f88b68c6186b267afcce12c7fd667cc9f8tgdwyer * Copyright (C) 2011 Authors
1ec681f88b68c6186b267afcce12c7fd667cc9f8tgdwyer * Released under GNU GPL, read the file 'COPYING' for more information
namespace Inkscape {
if (_style)
if (_pixbuf) {
_origin = o;
return ret;
if (_pixbuf) {
return STATE_ALL;
unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*area*/, unsigned /*flags*/, DrawingItem * /*stop_at*/)
if (!outline) {
// _style->image_rendering.computed
// See: http://www.w3.org/TR/SVG/painting.html#ImageRenderingProperty
// http://www.w3.org/TR/css4-images/#the-image-rendering
// The total transform (which is RIGHT-multiplied with the item points to get display points) equals:
if (_scale[Geom::X]*expansion[Geom::X]*orgwidth*255.0<1.0 || _scale[Geom::Y]*expansion[Geom::Y]*orgheight*255.0<1.0) {
return RENDER_OK;
// Split scale*expansion in a part that is <= 1.0 and a part that is >= 1.0. We only take care of the part <= 1.0.
Geom::Scale scaleExpansionSmall(std::min<Geom::Coord>(fabs(_scale[Geom::X]*expansion[Geom::X]),1),std::min<Geom::Coord>(fabs(_scale[Geom::Y]*expansion[Geom::Y]),1));
Geom::Scale scaleExpansionLarge(_scale[Geom::X]*expansion[Geom::X]/scaleExpansionSmall[Geom::X],_scale[Geom::Y]*expansion[Geom::Y]/scaleExpansionSmall[Geom::Y]);
// This essentially considers an image to be composed of rectangular pixels (box kernel) and computes the least-squares approximation of the original.
// When the scale factor is really large or small this essentially results in using a box filter, while for scale factors approaching 1 it is more like a "tent" kernel.
// Although the quality of the result is not great, it is typically better than an ordinary box filter, and it is guaranteed to preserve the overall brightness of the image.
// The best improvement would probably be to do the same kind of thing based on a tent kernel, but that's quite a bit more complicated, and probably not worth the trouble for a hack like this.
for(int x=0; x<orgwidth; x++) {
double coordBegin = x*static_cast<double>(scaleExpansionSmall[Geom::X]); // x-coord in target coordinates where the current source pixel begins
double coordEnd = (x+1)*static_cast<double>(scaleExpansionSmall[Geom::X]); // x-coord in target coordinates where the current source pixel ends
int begin = static_cast<int>(floor(coordBegin)); // First pixel (x-coord) affected by the current source pixel
int end = static_cast<int>(ceil(coordEnd)); // First pixel (x-coord) NOT affected by the current source pixel (a zero contribution is counted as not affecting the pixel)
// This computes the fraction of the current target pixel (at nx) that is covered by the source pixel (at x).
xCoefs[nx].push_back(static_cast<float>(std::min<double>(nx+1,coordEnd) - std::max<double>(nx,coordBegin)));
for(int y=0; y<orgheight; y++) {
double coordBegin = y*static_cast<double>(scaleExpansionSmall[Geom::Y]); // y-coord in target coordinates where the current source pixel begins
double coordEnd = (y+1)*static_cast<double>(scaleExpansionSmall[Geom::Y]); // y-coord in target coordinates where the current source pixel ends
int begin = static_cast<int>(floor(coordBegin)); // First pixel (y-coord) affected by the current source pixel
int end = static_cast<int>(ceil(coordEnd)); // First pixel (y-coord) NOT affected by the current source pixel (a zero contribution is counted as not affecting the pixel)
// This computes the fraction of the current target pixel (at ny) that is covered by the source pixel (at y).
yCoefs[ny].push_back(static_cast<float>(std::min<double>(ny+1,coordEnd) - std::max<double>(ny,coordBegin)));
for(int y=0; y<newheight; y++) {
for(int x=0; x<newwidth; x++) {
//ct.translate(_origin);
//ct.scale(_scale);
//ct.setSource(_surface, 0, 0);
return RENDER_OK;
double a_2 = a * a;
if (outline) {
return NULL;
return NULL;
return NULL;