Re: Unable to create a blur image
Uli Schlachter <[email protected]> Fri, 11 Oct 2019 09:20:21 +0200
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <[email protected]> |
This is a multi-part message in MIME format.
--------------970D76B87374CCC5309623CC
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Hi,
On 10.10.19 13:15, Murali Krishna wrote:
> I have been trying to create a blur image in C++ using cairo library
You are not actually using cairo to blur the image. You are bluring it
yourself. Butokay, whatever.
> the code I used doesn't actually work.
"Doesn't actually work" is not the best error description I ever heard.
I took your code and removed the osg references. The attached program
loads "img.png" and writes "out.png". For me, this results in a blur, so
I guess your blurring code works.
However, your createBlur() function for some reason fills the whole
surface with blue and blurring a solid color is not really interesting.
(It is blue, because you use cairo_set_source_rgba(cr, b, g, a), so your
variable names do not match the order of function arguments.)
(It is the whole surface, because you use cairo_paint(). This fills the
whole surface. To just fill the current path, you would use
cairo_fill(). Which you also call...?)
Cheers,
Uli
--
“Some people are worth melting for.” - Olaf
--------------970D76B87374CCC5309623CC
Content-Type: text/x-c++src;
name="BlurExample.cpp"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="BlurExample.cpp"
#include<chrono>
#include <cairo/cairo.h>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
using namespace std::chrono;
/* Performs a simple 2D Gaussian blur of radius @radius on surface @surface. */
void
blur_image_surface(cairo_surface_t *surface, int radius)
{
cairo_surface_t *tmp;
int width, height;
int src_stride, dst_stride;
int x, y, z, w;
uint8_t *src, *dst;
uint32_t *s, *d, a, p;
int i, j, k;
int size = radius * 2 + 1;
std::vector<uint8_t> kernel;
kernel.resize(size);
const int half = size / 2;
if (cairo_surface_status(surface))
return;
std::cout << "foo1" << std::endl;
width = cairo_image_surface_get_width(surface);
height = cairo_image_surface_get_height(surface);
switch (cairo_image_surface_get_format(surface)) {
case CAIRO_FORMAT_A1:
default:
/* Don't even think about it! */
return;
case CAIRO_FORMAT_A8:
/* Handle a8 surfaces by effectively unrolling the loops by a
* factor of 4 - this is safe since we know that stride has to be a
* multiple of uint32_t. */
width /= 4;
break;
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_ARGB32:
break;
}
std::cout << "foo2" << std::endl;
tmp = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
std::cout << "foo3" << std::endl;
if (cairo_surface_status(tmp))
return;
src = cairo_image_surface_get_data(surface);
src_stride = cairo_image_surface_get_stride(surface);
dst = cairo_image_surface_get_data(tmp);
dst_stride = cairo_image_surface_get_stride(tmp);
a = 0;
for (i = 0; i < size; i++) {
double f = i - half;
a += kernel[i] = exp(-f * f / 30.0) * 80;
}
/* Horizontally blur from surface -> tmp */
std::cout << "foo4 " << height << " " << width << " " << size << std::endl;
for (i = 0; i < height; i++) {
std::cout << "4a " << i << " out of " << height << "\r" << std::flush;
s = (uint32_t *)(src + i * src_stride);
d = (uint32_t *)(dst + i * dst_stride);
for (j = 0; j < width; j++) {
if (radius < j && j < width - radius) {
d[j] = s[j];
continue;
}
x = y = z = w = 0;
for (k = 0; k < size; k++) {
if (j - half + k < 0 || j - half + k >= width)
continue;
p = s[j - half + k];
x += ((p >> 24) & 0xff) * kernel[k];
y += ((p >> 16) & 0xff) * kernel[k];
z += ((p >> 8) & 0xff) * kernel[k];
w += ((p >> 0) & 0xff) * kernel[k];
}
d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
}
}
std::cout << "foo5 " << height << " " << width << " " << size << std::endl;
/* Then vertically blur from tmp -> surface */
for (i = 0; i < height; i++) {
std::cout << "5a " << i << " out of " << height << "\r" << std::flush;
s = (uint32_t *)(dst + i * dst_stride);
d = (uint32_t *)(src + i * src_stride);
for (j = 0; j < width; j++) {
if (radius <= i && i < height - radius) {
d[j] = s[j];
continue;
}
x = y = z = w = 0;
for (k = 0; k < size; k++) {
if (i - half + k < 0 || i - half + k >= height)
continue;
s = (uint32_t *)(dst + (i - half + k) * dst_stride);
p = s[j];
x += ((p >> 24) & 0xff) * kernel[k];
y += ((p >> 16) & 0xff) * kernel[k];
z += ((p >> 8) & 0xff) * kernel[k];
w += ((p >> 0) & 0xff) * kernel[k];
}
d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
}
}
std::cout << "\ndone" << std::endl;
cairo_surface_destroy(tmp);
cairo_surface_mark_dirty(surface);
}
void createBlur(cairo_surface_t *cairoRawSurface)
{
if (cairoRawSurface)
{
cairo_t* cr = cairo_create(cairoRawSurface);
unsigned int _width = cairo_image_surface_get_width(cairoRawSurface);
unsigned int _height = cairo_image_surface_get_height(cairoRawSurface);
if (cr)
{
#if 0
I am not sure what all of this is supposed so I removed it (after making it work without osg)
cairo_line_to(cr, 10, 20);
cairo_line_to(cr, 30, 10);
cairo_line_to(cr, 30, 10);
cairo_line_to(cr, 30, 30);
cairo_line_to(cr, 10, 30);
cairo_close_path(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
double r = 255;
double g = 0;
double b = 0;
double a = 0.5;
cairo_set_source_rgba(cr, b / a, g / a, r / a, a); // Uhm, the arguments should be in range [0,1]. b/a is 510.
cairo_paint(cr); // This fills the whole surface with your blue color?
cairo_set_source_rgba(cr, b / a, g / a, r / a, a);
cairo_fill_preserve(cr);
cairo_set_source_rgba(cr, b / a, g / a, r / a, a);
#endif
const double blurPixels = (20 / 100.0) * static_cast<double>(_width);
cairo_set_line_width(cr, blurPixels / 2.0);
cairo_stroke(cr);
// apply blur
blur_image_surface(cairoRawSurface, blurPixels);
cairo_destroy(cr);
}
}
}
int main()
{
cairo_surface_t *areaImage = cairo_image_surface_create_from_png("img.png");
createBlur(areaImage);
cairo_surface_write_to_png(areaImage, "out.png");
}
--------------970D76B87374CCC5309623CC
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: inline
LS0gCmNhaXJvIG1haWxpbmcgbGlzdApjYWlyb0BjYWlyb2dyYXBoaWNzLm9yZwpodHRwczovL2xp
c3RzLmNhaXJvZ3JhcGhpY3Mub3JnL21haWxtYW4vbGlzdGluZm8vY2Fpcm8=
--------------970D76B87374CCC5309623CC--