Bug 35407

Summary: boundary of image gets wrong color
Product: cairo Reporter: clock9
Component: generalAssignee: Carl Worth <cworth>
Status: RESOLVED FIXED QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: major    
Priority: medium    
Version: 1.10.2   
Hardware: ARM   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:
Attachments: result of test.
Commit which seems to fix the problem for me

Description clock9 2011-03-18 01:54:26 UTC
Created attachment 44569 [details]
result of test.

I got a problem in cairo 1.10.2.

The boundary of an image I try to draw has wrong color.

It's 1 pixel outer box.

you can see it with the attached file.


'_cairo_image_surface_paint' function (It's not in 1.8.8 so '_cairo_surface_fallback_paint' function is used),
and the decimal scaling, and the alpha property of the image surface,
seem to make this issue.

please take this issue and please let me know how to make it right.


================================================
my test code and conditions are below.
================================================
A. The conditions

1. set operator as CAIRO_OPERATOR_SOURCE
2. scale factor is decimal not integer. like cairo_scale(cr,4.1) in the test code
3. the image surface has no alpha format.

B. The Test Code

{
    char outfile[100];
    
    uint32_t* dst_buffer = create_buffer32(480*800, 0xff00ff00);

    cairo_surface_t* cairo_surface = cairo_image_surface_create_for_data (
                                                          (unsigned char*)dst_buffer,
                                                           CAIRO_FORMAT_RGB24,
                                                          480, 800,
                                                          cairo_format_stride_for_width(CAIRO_FORMAT_RGB24,
                                                          480));
    cairo_t* cr = cairo_create(cairo_surface); 

    cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);

    cairo_scale(cr,4.1, 4.1);

    cairo_surface_t* src_surface = cairo_image_surface_create_from_png("/white.png"); // just white image file 25x16.
    
    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
    
    cairo_pattern_t* pattern = cairo_pattern_create_for_surface(src_surface);

    cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
  
    cairo_matrix_t matrix = { 1.0, 0, 0, 1.0, 0, 0 };

    cairo_pattern_set_matrix(pattern, &matrix);

    cairo_translate(cr, 8, 8);
    
    cairo_set_source(cr, pattern);

    cairo_pattern_destroy(pattern);

    cairo_rectangle(cr, 0, 0, 25, 16);

    cairo_clip(cr);

    cairo_paint_with_alpha(cr, 1.0);

    sprintf(outfile,"test.png");

    cairo_surface_write_to_png(cairo_surface,outfile);

    cairo_surface_destroy(src_surface);

    cairo_surface_destroy(cairo_surface);

    cairo_destroy(cr);
    
    destroy_buffer32(dst_buffer);    
}
Comment 1 Bill Spitzak 2011-03-18 11:06:30 UTC
That's double premultiplication of the image border.

The immediate solution is to use CAIRO_EXTEND_REPEAT (or any setting 
other than none) and always use a rectangle to crop the result to the 
area you expect.

I also still recommend that cairo be altered so that CAIRO_EXTEND_NONE 
does this automatically, as the current behavior is useless and not at 
all what a beginning user expects. Using "min" for the intersection with 
the current region+mask will avoid double premultiplication, which would 
be much better than what the cairo client can do (unless more complex 
methods of intersecting paths are added).

bugzilla-daemon@freedesktop.org wrote:
> https://bugs.freedesktop.org/show_bug.cgi?id=35407
> 
>            Summary: boundary of image gets wrong color
>            Product: cairo
>            Version: 1.10.2
>           Platform: ARM
>         OS/Version: Linux (All)
>             Status: NEW
>           Severity: major
>           Priority: medium
>          Component: general
>         AssignedTo: cworth@cworth.org
>         ReportedBy: clock9@naver.com
>          QAContact: cairo-bugs@cairographics.org
> 
> 
> Created an attachment (id=44569)
>  --> (https://bugs.freedesktop.org/attachment.cgi?id=44569)
> result of test.
> 
> I got a problem in cairo 1.10.2.
> 
> The boundary of an image I try to draw has wrong color.
> 
> It's 1 pixel outer box.
> 
> you can see it with the attached file.
> 
> 
> '_cairo_image_surface_paint' function (It's not in 1.8.8 so
> '_cairo_surface_fallback_paint' function is used),
> and the decimal scaling, and the alpha property of the image surface,
> seem to make this issue.
> 
> please take this issue and please let me know how to make it right.
> 
> 
> ================================================
> my test code and conditions are below.
> ================================================
> A. The conditions
> 
> 1. set operator as CAIRO_OPERATOR_SOURCE
> 2. scale factor is decimal not integer. like cairo_scale(cr,4.1) in the test
> code
> 3. the image surface has no alpha format.
> 
> B. The Test Code
> 
> {
>     char outfile[100];
> 
>     uint32_t* dst_buffer = create_buffer32(480*800, 0xff00ff00);
> 
>     cairo_surface_t* cairo_surface = cairo_image_surface_create_for_data (
>                                                           (unsigned
> char*)dst_buffer,
>                                                            CAIRO_FORMAT_RGB24,
>                                                           480, 800,
>                                                          
> cairo_format_stride_for_width(CAIRO_FORMAT_RGB24,
>                                                           480));
>     cairo_t* cr = cairo_create(cairo_surface); 
> 
>     cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
> 
>     cairo_scale(cr,4.1, 4.1);
> 
>     cairo_surface_t* src_surface =
> cairo_image_surface_create_from_png("/white.png"); // just white image file
> 25x16.
> 
>     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
> 
>     cairo_pattern_t* pattern = cairo_pattern_create_for_surface(src_surface);
> 
>     cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
> 
>     cairo_matrix_t matrix = { 1.0, 0, 0, 1.0, 0, 0 };
> 
>     cairo_pattern_set_matrix(pattern, &matrix);
> 
>     cairo_translate(cr, 8, 8);
> 
>     cairo_set_source(cr, pattern);
> 
>     cairo_pattern_destroy(pattern);
> 
>     cairo_rectangle(cr, 0, 0, 25, 16);
> 
>     cairo_clip(cr);
> 
>     cairo_paint_with_alpha(cr, 1.0);
> 
>     sprintf(outfile,"test.png");
> 
>     cairo_surface_write_to_png(cairo_surface,outfile);
> 
>     cairo_surface_destroy(src_surface);
> 
>     cairo_surface_destroy(cairo_surface);
> 
>     cairo_destroy(cr);
> 
>     destroy_buffer32(dst_buffer);    
> }
>
Comment 2 clock9 2011-03-23 18:18:29 UTC
Using CAIRO_EXTEND_REPEAT for the pattern, is not working. the problem is still in there.

How do I get the right rectangle without double premultiplication?
Comment 3 Benjamin Otte 2011-03-23 18:27:02 UTC
(In reply to comment #1)
> That's double premultiplication of the image border.
> 
> The immediate solution is to use CAIRO_EXTEND_REPEAT (or any setting 
> other than none) and always use a rectangle to crop the result to the 
> area you expect.
> 
The example code is using CAIRO_EXTEND_PAD though?
Comment 4 clock9 2011-03-23 21:55:05 UTC
(In reply to comment #3)
> (In reply to comment #1)
> > That's double premultiplication of the image border.
> > 
> > The immediate solution is to use CAIRO_EXTEND_REPEAT (or any setting 
> > other than none) and always use a rectangle to crop the result to the 
> > area you expect.
> > 
> The example code is using CAIRO_EXTEND_PAD though?

Yes it was. 

and I'd changed 'CAIRO_EXTEND_PAD' to 'CAIRO_EXTEND_REPEAT'. but it didn't work.

anything else I need to do?
Comment 5 clock9 2011-03-29 04:49:56 UTC
please let me know what the difference of using pixman between fallback-paint function and image-paint function.

1.
_cairo_surface_fallback_paint function, in this case,
   '_clip_and_composite_source' -> '_cairo_surface_composite' -> '_cairo_image_surface_composite' are called 

   finally, 'pixman_image_composite32' is called twice with 'CAIRO_OPERATOR_DEST_OUT' and 'CAIRO_OPERATOR_ADD'. and it can get good result.


2.
_cairo_image_surface_paint function, in this case,
_clip_and_composite_boxes -> _composite_boxes -> _composite_unaligned_boxes are called.

   finally, 'pixman_image_composite32' is called once with 'CAIRO_OPERATOR_SOURCE'. and it gets bad result.


actually, in this case, 'mask' in '_composite_unaligned_boxes' seems to be wrong. If I set it NULL, no problem.

and If I use 'pixman_image_composite32' twice like fallback-paint function, no problem.

Can you let me know what's wrong with it for me?
Comment 6 Uli Schlachter 2011-03-29 11:56:26 UTC
Created attachment 45011 [details] [review]
Commit which seems to fix the problem for me

Hi,

this seems to be the same problem that was already mentioned on the mailing list here:

http://lists.cairographics.org/archives/cairo/2011-March/021827.html

Attached is my patch for that. Could you test if that also fixes the issue for you?

I tried running your test case, but since I don't have white.png and I don't know which size it should have, I'm not sure this actually fixes the problem. It certainly does fix it for me.
Comment 7 clock9 2011-04-26 17:53:17 UTC
Fixed by Uli Schlachter's patch.

I hope this will be on next version.

appreciated.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.