nr-filter-gaussian.cpp revision e875ebf833b09b5c9f373ebd07a41ea72bd61270
#define __NR_FILTER_GAUSSIAN_CPP__
/*
* Gaussian blur renderer
*
* Authors:
* Niko Kiirala <niko@kiirala.com>
* bulia byak
* Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
*
* Copyright (C) 2006 authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <cmath>
#include <glib.h>
#include "display/nr-filter-primitive.h"
#include "display/nr-filter-gaussian.h"
#include "display/nr-filter-types.h"
#include "libnr/nr-pixblock.h"
#include "libnr/nr-matrix.h"
#include "prefs-utils.h"
template<typename T> static inline T sqr(T const v) { return v*v; }
namespace NR {
{
}
{
return new FilterGaussian();
}
{
// Nothing to do here
}
{
}
{
// Compute kernel and sum of coefficients
// Note that actually only half the kernel is computed, as it is symmetric
double sum = 0;
for ( int i = 0; i <= scr_len ; i++ ) {
}
sum = 2*sum - kernel[0]; // the sum of the complete kernel is twice as large (minus the center element to avoid counting it twice)
// Normalize kernel
for ( int i = 0; i <= scr_len ; i++ ) {
}
}
{
return ret;
}
{
switch (quality) {
case BLUR_QUALITY_WORST:
if (scr_len_x < 8) {
return 1;
} else if (scr_len_x < 32) {
return 4;
} else if (scr_len_x < 64) {
return 8;
} else if (scr_len_x < 128) {
return 32;
} else if (scr_len_x < 256) {
return 128;
} else if (scr_len_x < 512) {
return 512;
} else if (scr_len_x < 1024) {
return 4096;
} else {
return 65536;
}
break;
case BLUR_QUALITY_WORSE:
if (scr_len_x < 16) {
return 1;
} else if (scr_len_x < 64) {
return 4;
} else if (scr_len_x < 120) {
return 8;
} else if (scr_len_x < 200) {
return 32;
} else if (scr_len_x < 400) {
return 64;
} else if (scr_len_x < 800) {
return 256;
} else if (scr_len_x < 1200) {
return 1024;
} else {
return 65536;
}
break;
case BLUR_QUALITY_BETTER:
if (scr_len_x < 32) {
return 1;
} else if (scr_len_x < 160) {
return 4;
} else if (scr_len_x < 320) {
return 8;
} else if (scr_len_x < 640) {
return 32;
} else if (scr_len_x < 1280) {
return 64;
} else if (scr_len_x < 2560) {
return 256;
} else {
return 1024;
}
break;
case BLUR_QUALITY_BEST:
return 1; // no subsampling at all
break;
case BLUR_QUALITY_NORMAL:
default:
if (scr_len_x < 16) {
return 1;
} else if (scr_len_x < 80) {
return 4;
} else if (scr_len_x < 160) {
return 8;
} else if (scr_len_x < 320) {
return 32;
} else if (scr_len_x < 640) {
return 64;
} else if (scr_len_x < 1280) {
return 256;
} else if (scr_len_x < 2560) {
return 1024;
} else {
return 65536;
}
break;
}
}
{
switch (quality) {
case BLUR_QUALITY_WORST:
if (scr_len_x < 8) {
return 0;
} else if (scr_len_x < 32) {
return 2;
} else if (scr_len_x < 64) {
return 3;
} else if (scr_len_x < 128) {
return 5;
} else if (scr_len_x < 256) {
return 7;
} else if (scr_len_x < 512) {
return 9;
} else if (scr_len_x < 1024) {
return 12;
} else {
return 16;
}
break;
case BLUR_QUALITY_WORSE:
if (scr_len_x < 16) {
return 0;
} else if (scr_len_x < 64) {
return 2;
} else if (scr_len_x < 120) {
return 3;
} else if (scr_len_x < 200) {
return 5;
} else if (scr_len_x < 400) {
return 6;
} else if (scr_len_x < 800) {
return 8;
} else if (scr_len_x < 1200) {
return 10;
} else {
return 16;
}
break;
case BLUR_QUALITY_BETTER:
if (scr_len_x < 32) {
return 0;
} else if (scr_len_x < 160) {
return 2;
} else if (scr_len_x < 320) {
return 3;
} else if (scr_len_x < 640) {
return 5;
} else if (scr_len_x < 1280) {
return 6;
} else if (scr_len_x < 2560) {
return 8;
} else {
return 10;
}
break;
case BLUR_QUALITY_BEST:
return 0; // no subsampling at all
break;
case BLUR_QUALITY_NORMAL:
default:
if (scr_len_x < 16) {
return 0;
} else if (scr_len_x < 80) {
return 2;
} else if (scr_len_x < 160) {
return 3;
} else if (scr_len_x < 320) {
return 5;
} else if (scr_len_x < 640) {
return 6;
} else if (scr_len_x < 1280) {
return 8;
} else if (scr_len_x < 2560) {
return 10;
} else {
return 16;
}
break;
}
}
/**
* Sanity check function for indexing pixblocks.
* Catches reading and writing outside the pixblock area.
* When enabled, decreases filter rendering speed massively.
*/
{
if (false) {
}
}
{
/* in holds the input pixblock */
/* If to either direction, the standard deviation is zero or
* input image is not defined,
* a transparent black image should be returned. */
// A bit guessing here, but source graphic is likely to be of
// right size
}
}
return 0;
}
/* Blur radius in screen units (pixels) */
// subsampling step; it depends on the radius, but somewhat nonlinearly, to make high zooms
// workable; is adjustable by quality in -2..2; 0 is the default; 2 is the best quality with no
// subsampling
// Take subsampling into account
expansion_x /= stepx;
expansion_y /= stepy;
/* buffer for x-axis blur */
/* buffer for y-axis blur */
// boundaries of the subsampled (smaller, unless step==1) buffers
// set up subsampled buffers
if ((bufx->size != NR_PIXBLOCK_SIZE_TINY && bufx->data.px == NULL) || (bufy->size != NR_PIXBLOCK_SIZE_TINY && bufy->data.px == NULL)) { // no memory
return 0;
}
/* Array for filter kernel, big enough to fit kernels for both X and Y
* direction kernel, one at time */
/* 1. Blur in direction of X-axis, from in to bufx (they have different resolution)*/
// corresponding line in the source buffer
int in_line;
} else {
if (in_line < 0)
in_line = 0;
}
// current line in bufx
// for all bytes of the pixel
double sum = 0;
int last_in = -1;
int different_count = 0;
// go over our point's neighborhood on x axis in the in buffer, with stepx increment
// the pixel we're looking at
} else {
if (x_in < 0)
x_in = 0;
}
// value at the pixel
// is it the same as last one we saw?
// sum pixels weighted by the kernel
}
// store the result in bufx
// optimization: if there was no variation within this point's neighborhood,
// skip ahead while we keep seeing the same last_in byte:
// blurring flat color would not change it anyway
if (different_count <= 1) {
int pos = x + 1;
NR_PIXBLOCK_PX(in)[in_line + NR_PIXBLOCK_BPP(in) * (((pos + scr_len_x) << stepx_l2) - in->area.x0) + byte] == last_in)
{
_check_index(in, in_line + NR_PIXBLOCK_BPP(in) * (((pos + scr_len_x) << stepx_l2) - in->area.x0) + byte, __LINE__);
pos++;
}
}
}
}
}
/* 2. Blur in direction of Y-axis, from bufx to bufy (they have the same resolution) */
double sum = 0;
int last_in = -1;
int different_count = 0;
unsigned char in_byte = NR_PIXBLOCK_PX(bufx)[y_in * bufx->rs + NR_PIXBLOCK_BPP(bufx) * (x - xd0) + byte];
}
if (different_count <= 1) {
int pos = y + 1;
{
pos++;
}
}
}
}
}
// we don't need bufx anymore
delete bufx;
// interpolation will need to divide by stepx * stepy
// new buffer for the final output, same resolution as the in buffer
// alas, we've accomplished a lot, but ran out of memory - so abort
return 0;
}
// get 4 values at the corners of the pixel from bufy
unsigned char a00 = NR_PIXBLOCK_PX(bufy)[((y - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x - xd0) + byte];
continue;
}
_check_index(bufy, ((y - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x + 1 - xd0) + byte, __LINE__);
unsigned char a10 = NR_PIXBLOCK_PX(bufy)[((y - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x + 1 - xd0) + byte];
_check_index(bufy, ((y + 1 - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x - xd0) + byte, __LINE__);
unsigned char a01 = NR_PIXBLOCK_PX(bufy)[((y + 1 - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x - xd0) + byte];
_check_index(bufy, ((y + 1 - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x + 1 - xd0) + byte, __LINE__);
unsigned char a11 = NR_PIXBLOCK_PX(bufy)[((y + 1 - yd0) * bufy->rs) + NR_PIXBLOCK_BPP(bufy) * (x + 1 - xd0) + byte];
// iterate over the rectangle to be interpolated
continue;
continue;
// simple linear interpolation
NR_PIXBLOCK_PX(out)[out_line + NR_PIXBLOCK_BPP(out) * (x_out - out->area.x0) + byte] = (unsigned char) a;
}
}
}
}
}
delete bufy;
return 0;
}
{
}
{
}
}
void FilterGaussian::set_deviation(double x, double y)
{
_deviation_x = x;
_deviation_y = y;
}
}
} /* namespace NR */
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :