[cairo] BUG: CAIRO_FORMAT_ARGB32, image_surface transparency = CAIRO_IMAGE_IS_OPAQUE after write_png()

lamer314 at mail.ru lamer314 at mail.ru
Tue Jun 7 07:15:41 UTC 2016


Tuesday, June 7, 2016, 8:58:57 AM, you wrote:

lmr> Tuesday, June 7, 2016, 1:49:47 AM, you wrote:

AJ>> On 07/06/16 05:37, chnav wrote:
>>> Hi,
>>> 
>>> have discovered sporatic bug working with transparent images,
>>> which I finally managed to reproduce.
>>> 
>>> ------- code 1 begin --------------
>>> cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 256, 256);
>>> cairo_t *cr = cairo_create (surface);
>>> // Initialisation
>>> cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
>>> cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
>>> cairo_paint(cr);
>>> cairo_surface_write_to_png(surface, "cairo_test3a.png");
>>> // ...
>>> cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.5);
>>> cairo_paint(cr);
>>> cairo_surface_write_to_png(surface, "cairo_test3b.png");
>>> ------- code 1 end --------------
>>> 
>>> Both files supposed to be 32 bit PNG with alpha but above will produce
>>> 24 bit png without alpha. 
>>> 
>>> 
>>> ------- code 2 begin --------------
>>> cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 256, 256);
>>> cairo_t *cr = cairo_create (surface);
>>> // Initialisation
>>> cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
>>> cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.9);
>>> cairo_paint(cr);
>>> cairo_surface_write_to_png(surface, "cairo_test3a.png");
>>> // ...
>>> cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.5);
>>> cairo_paint(cr);
>>> cairo_surface_write_to_png(surface, "cairo_test3b.png");
>>> ------- code 2 end --------------
>>> 
>>> Now both files are 32 bit PNG alpha.
>>> 
>>> 
>>> Short explanation, tracing "code 1" in debugger:
>>> 
>>> 1. Before 1st call of write_png():
>>>    image->transparency = CAIRO_IMAGE_UNKNOWN;
>>> 2. cairo_surface_write_to_png() calls _cairo_image_analyze_transparency();
>>> 3. _cairo_image_analyze_transparency() see CAIRO_IMAGE_UNKNOWN and
>>>    scans every pixels' alpha. It founds all of them equal 255 and changes
>>>    image->transparency = CAIRO_IMAGE_IS_OPAQUE (!!!)

AJ>> If all alpha is 255 the image is opaque.


>>> 4. From now on any subsequent call of _cairo_image_analyze_transparency()
>>>    will return CAIRO_IMAGE_IS_OPAQUE;
>>> 5. cairo_surface_write_to_png() sets png_color_type = PNG_COLOR_TYPE_RGB;
>>> 
>>> 
>>> I assume if we create image surface CAIRO_FORMAT_ARGB32 then
>>> image->transparency must be CAIRO_IMAGE_HAS_ALPHA

AJ>> That assumption is incorrect. Cairo analyses image transparency to
AJ>> ensure it uses the most efficient format when writing out images to PNG,
AJ>> PDF, and PS.

lmr> Ok, but writing PNG shall not affect consequent writings. If we paint
lmr> later with transparent source it is not opaque anymore and then 
lmr> _cairo_image_analyze_transparency() shall run again.

lmr> Either we have optimised PNG which requires time cost analyzing,
lmr> or we have intentionally set CAIRO_FORMAT_ARGB32 and write
lmr> non-optimized 32-bit PNG.

lmr> I think it would be good idea to add some function like
lmr> cairo_surface_write_to_png_flat() which will dump image data
lmr> to PNG in the same format as surface. It also can be usefull for
lmr> debugging then user can open file in image viwer and see what data
lmr> in what format hi is actually working on.


lmr> I am making slippy web map and generating overlay images. Tiles can be
lmr> opaque or transparent depends on data and I cannot know which will go
lmr> first.

I have added my usecase

------- code 3 begin --------------
        cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 256, 256);
        cairo_t *cr = cairo_create(surface);
        while(havedata) {
                // clear canvas
                cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
                cairo_paint(cr);
                cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
                // do real data drawing
                _PaintSomeData(cr);
                cairo_surface_write_to_png_stream(surface, ..........);
        }
------- code 3 end --------------


lmr> Right now the tile surface cannot be re-used.

lmr> Thanks and Regards
lmr> chnav

lmr> Tuesday, June 7, 2016, 8:01:52 AM LOCAL
lmr> --


>>> 
>>> 
>>> Thanks and Regards
>>> chnav
>>> 
>>> 
>>> Monday, June 6, 2016, 9:52:54 PM LOCAL
>>> 






More information about the cairo mailing list