How to flatten several data surfaces with transparency

Steve Moreau <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <CAD9K4eA03WbJpLF7rG4=NJOSRG+3Og0juYiHrDByxMN36V7+Bg@mail.gmail.com>
Hi all,

I was playing with cairo to flatten several layers with transparency.
Some of my surfaces are data surface filled by an external lib.
Pixels on these surfaces have distributed alpha values (not only fully
transparent or opaque).

When I dump any surface independently, the transparency seems to be fine.

But as soon as I want to compose them, the transparent values of the top
layer behaves oddly.
I did a lot of tests but the best I could do to explain is the dummy cpp
file attached.

Basically I draw a gradient manually (let's say it is what the external lib
do). So alpha layer is in [0,1]. I want a red square to be behind this
gradient. So I expect the result square not to change on parts where
transparency is near 0.

When line 52 : buf[y*rowLen+x*4+1] = 50;
I see the square but is already altered because it is not its actual color.

When line 52 : buf[y*rowLen+x*4+1] = 255;
I see everything in green and I just can't explain why for now.

I keep on reading the doc to get it, but if someone could explain what
happens and how I could merge/flatten/composite several layers, it would be
nice, because it is a little unclear to me for now.
Thanks,

Steve

PS:

A copy/paste way to compile and run the example :
$ g++ -g -I/usr/include/cairo -o test Dummy.cpp -lpng -lcairo && ./test

A way to see the result :
$ eog test.png

-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
Dummy.cpp (text/x-c++src, 4.9 KB)
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <math.h>
#include <complex>
#include <stdexcept>
#include "string.h"

#define PNG_DEBUG 3
#include <png.h>

#include <cairo.h>



void setColor(unsigned char* pixel, unsigned int color, unsigned char opacity = 0xFF)
{
  pixel[0] = (color >> 16) & 0xFF;
  pixel[1] = (color >> 8) & 0xFF;
  pixel[2] = (color) & 0xFF;
  pixel[3] = opacity;
}

unsigned char* process()
{
  cairo_surface_t *surface;
  cairo_t *cr;
  int width = 1024, height = 300;
  int rowLen = width * 4;
  unsigned char* imageBuffer = (unsigned char*)malloc(4*width*height);
  int x, y;

  surface = cairo_image_surface_create_for_data (imageBuffer,
      CAIRO_FORMAT_ARGB32, width, height,
      rowLen);

  cr = cairo_create (surface);

 
  unsigned char* buf = (unsigned char*)malloc(4*width*height);
  cairo_surface_t* dataSurface = cairo_image_surface_create_for_data (buf, CAIRO_FORMAT_ARGB32, width, height, rowLen);
  for (y=0; y<height; y++)
  {
    for (x=0; x<width; x++)
    {
      //setColor(&buf[y*rowLen+x*4], 0x00FF00, y*255.0/3/height);
      buf[y*rowLen+x*4+0] = 0;
      buf[y*rowLen+x*4+1] = 50;
      buf[y*rowLen+x*4+2] = 0;
      buf[y*rowLen+x*4+3] = (y < 50 ? 0 : (y-50)*255.0/height);
    }
  }

  x=50;
  cairo_t *first_cr, *second_cr;
  cairo_surface_t *first, *second;

  first = cairo_surface_create_similar(cairo_get_target(cr),
      CAIRO_CONTENT_COLOR_ALPHA, width, height);

  second = cairo_surface_create_similar(cairo_get_target(cr),
      CAIRO_CONTENT_COLOR_ALPHA, width, height);

  first_cr = cairo_create(first);
  cairo_save(first_cr);
  cairo_set_source_rgba(first_cr, 0, 0, 0.4, 1);
  cairo_rectangle(first_cr, x, 0, 250, 250);
  cairo_fill(first_cr);
  cairo_restore(first_cr);

  //second_cr = cairo_create(second);
  //cairo_set_source_rgba(second_cr, 0.5, 0.5, 0, 0.5);
  //cairo_rectangle(second_cr, x+10, 40, 50, 50);
  //cairo_set_source_surface(second_cr, dataSurface, 0, 0);
  //cairo_paint(second_cr);

  second_cr = cairo_create(second);
  //cairo_set_source_rgb(second_cr, 0.5, 0.5, 0);
  //cairo_set_source_rgba (second_cr, 0.0f, 0.0f, 1.0f, 0);
  //cairo_set_operator(second_cr, CAIRO_OPERATOR_ADD);
  cairo_set_source_surface(second_cr, dataSurface, 0, 0);
  cairo_paint(second_cr);

  //cairo_set_operator(first_cr, CAIRO_OPERATOR_ATOP);
  cairo_set_operator(first_cr, CAIRO_OPERATOR_OVER);
  cairo_set_source_surface(first_cr, second, 0, 0);
  cairo_paint(first_cr);

  //cairo_set_source_rgba (cr, 1.0f, 1.0f, 1.0f, 0);
  cairo_set_source_surface(cr, first, 0, 0);
  cairo_paint(cr);

  cairo_surface_destroy(first);
  cairo_surface_destroy(second);

  cairo_destroy(first_cr);


  return imageBuffer;
}

void write_png_file(char* file_name)
{
  int width = 1024, height = 300;
  png_byte color_type = PNG_COLOR_TYPE_RGB_ALPHA;
  png_byte bit_depth = 8;

  png_structp png_ptr;
  png_infop info_ptr;
  int number_of_passes;
  png_bytep * row_pointers;
  int y;

  /* create file */
  FILE *fp = fopen(file_name, "wb");
  if (!fp)
    printf("[write_png_file] File %s could not be opened for writing", file_name);


  /* initialize stuff */
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr)
    printf("[write_png_file] png_create_write_struct failed");

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    printf("[write_png_file] png_create_info_struct failed");

  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[write_png_file] Error during init_io");

  png_init_io(png_ptr, fp);


  /* write header */
  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[write_png_file] Error during writing header");

  png_set_IHDR(png_ptr, info_ptr, width, height,
               bit_depth, color_type, PNG_INTERLACE_NONE,
               PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  png_write_info(png_ptr, info_ptr);


  /* write bytes */
  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[write_png_file] Error during writing bytes");

  unsigned char* imageBuffer = process();

  row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
  for (y=0; y<height; y++)
  {
    unsigned int rowLen = png_get_rowbytes(png_ptr, info_ptr);
    row_pointers[y] = (png_byte*) &imageBuffer[y*rowLen];
  }

  /*
  row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
  for (y=0; y<height; y++)
  {
    unsigned int rowLen = png_get_rowbytes(png_ptr,info_ptr);
    row_pointers[y] = (png_byte*) malloc(rowLen);
    memset(row_pointers[y], 0, rowLen);
  }
  */


  png_write_image(png_ptr, row_pointers);


  /* end write */
  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[write_png_file] Error during end of write");

  png_write_end(png_ptr, NULL);

  /* cleanup heap allocation */
  //for (y=0; y<height; y++)
  //  free(row_pointers[y]);
  free(row_pointers);

  fclose(fp);
}

int main(int argc, char* argv[])
{
  write_png_file((char*)"test.png");
  return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.