[cairo] Problem with cairo pdf output

Tobias Hoffmann lcairo-list at thax.hardliners.org
Thu Nov 3 18:55:47 UTC 2022


Minimal reproducible example:

#include <cairo/cairo.h>
#include <cairo/cairo-pdf.h>

int main()
{
   cairo_surface_t *sfc = cairo_pdf_surface_create("out.pdf", 100, 100);
   cairo_t *cr = cairo_create(sfc);

   // prepare some background
   cairo_set_source_rgb(cr, 0.7, 1.0, 1.0);
   cairo_paint(cr);

   cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
   cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
   cairo_move_to(cr, 2.0, 2.0);
   cairo_line_to(cr, 98.0, 98.0);
   cairo_stroke(cr);

   cairo_push_group(cr);
   cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
   cairo_rectangle(cr, 10.0, 10.0, 80.0, 30.0);
   cairo_fill(cr);

   cairo_pattern_t *p1 = cairo_pop_group(cr);

#if 1
   // Problem only manifests, when clipping is enabled
cairo_rectangle(cr, 0.0, 0.0, 100.0, 99.0);
   cairo_clip(cr);
#endif

   cairo_set_operator(cr, CAIRO_OPERATOR_MULTIPLY);
   cairo_set_source(cr, p1);
   cairo_paint(cr);

cairo_translate(cr, 0.0, 50.0);
   cairo_set_source(cr, p1); // source has cached the ctm -> needs update
   cairo_paint(cr);

   cairo_pattern_destroy(p1);

cairo_surface_write_to_png(sfc, "out.png");

   cairo_destroy(cr);
   cairo_surface_destroy(sfc);

   return 0;
}

out.png is correct, out.pdf is not.

Comparison of pdf content streams:
-- w/o clipping: --
1 0 0 -1 0 100 cm
q
0.7 1 1 rg /a0 gs
0 0 100 100 re f
0 0 0 RG 2 w
0 J
0 j
[] 0.0 d
10 M 2 2 m 98 98 l S
/b14 gs
q
/a0 gs /x6 Do
Q
q
1 0 0 1 0 50 cm
/a0 gs /x6 Do
Q
Q

-- vs. w/ clipping: --
1 0 0 -1 0 100 cm
q
0.7 1 1 rg /a0 gs
0 0 100 100 re f
0 0 0 RG 2 w
0 J
0 j
[] 0.0 d
10 M 2 2 m 98 98 l S
Q q
0 0 100 99 re W n
/b14 gs
q
/a0 gs /x6 Do
Q
Q q
0 50 100 49 re W n
q
1 0 0 1 0 50 cm
/a0 gs /x6 Do
Q
Q

The change of clipping (translate...) adds another level of q/Q grouping 
to limit its effect, but the group also contains and limits the /b14 gs 
command – and the /b14 is not emitted again in the second group, 
although MULTIPLY should still be used.

   Tobias



On 03/11/2022 16:30, Tobias Hoffmann wrote:
> I did some more research and ltrace'd pdftocairo --pdf and --png.
> There is no obvious difference in the cairo call that generate the 
> highlight.
>
> Next, I compared the cairo commands producing the first highlight 
> ("small") with those of the second highlight ("Virtual Mechanics"). 
> Apart from some differing address, the only major difference is an 
> additional cairo_pattern_destroy:
>
> [...cairo_clip, etc....]
> // CairoOutputDev::beginTransparencyGroup
> // 
> https://github.com/freedesktop/poppler/blob/bc4a0d9a2abfcd75d9b0ee4be3f7600905fe6001/poppler/CairoOutputDev.cc#L906
> cairo_get_matrix(0x56e2e080, 0x56eabc08, 2, 0xf7095466)                
> = 0x56eabc08
> cairo_push_group(0x56e2e080, 0x56eabc08, 2, 
> 0xf7095466)                 = 0
> cairo_set_operator(0x56e2e080, 2, 2, 
> 0xf7095466)                        = 0
> cairo_save(0x56e2e080, 0, 0xf79509a9, 
> 0xf7b55184)                       = 0
> cairo_pattern_reference(0x56e2e830, 0, 0xf79509a9, 
> 0xf7b55184)          = 0x56e2e830
> cairo_pattern_reference(0x56e2e830, 0, 0xf79509a9, 
> 0xf7b55184)          = 0x56e2e830
> cairo_pattern_get_type(0x56e2e830, 0x56eac04c, 0xffd4a260, 
> 0xf791e9f8)  = 0
> cairo_pattern_destroy(0x56e2e830, 0x56eac04c, 0xffd4a260, 
> 0xf791e9f8)   = 10
>
> cairo_pattern_create_rgba(0, 0x3ff00000, 0, 
> 0x3ff00000)                 = 0x56eab410
> cairo_new_path(0x56e2e080, 0, 0, 
> 7)                                     = 0
> cairo_move_to(0x56e2e080, 0x28f5c290, 0x405b5f5c, 
> 0x51eb851f)           = 0
> cairo_curve_to(0x56e2e080, 0xcccccccd, 0x405acccc, 
> 0xc28f5c29)          = 0
> cairo_line_to(0x56e2e080, 0xeb851eb8, 0x40614851, 
> 0x8f5c28f6)           = 0
> cairo_curve_to(0x56e2e080, 0x9999999a, 0x40619199, 
> 0x1eb851eb)          = 0
> cairo_set_fill_rule(0x56e2e080, 0, 0x56eabfd0, 
> 0x56eabbb0)              = 0
> cairo_set_source(0x56e2e080, 0x56eab410, 0x56eabfd0, 
> 0x56eabbb0)        = 0
> cairo_fill(0x56e2e080, 0x56eab410, 0x56eabfd0, 
> 0x56eabbb0)              = 0
> cairo_restore(0x56e2e080, 744, 0xf78ea873, 
> 0x56594bdc)                  = 0
> cairo_pattern_destroy(0x56eab410, 744, 0xf78ea873, 
> 0x56594bdc)          = 0
> cairo_pattern_destroy(0x56e2e830, 744, 0xf78ea873, 
> 0x56594bdc)          = 9
>
> cairo_set_operator(0x56e2e080, 2, 2, 
> 0x565abb00)                        = 0
> // Next line is only present for the second highlight  -> 
> CairoOutputDev::endTransparencyGroup
>   cairo_pattern_destroy(0x56e30cd0, 0xf78ffab0, 0xf78f46b9, 
> 0xf7b55184)   = 0
> cairo_pop_group(0x56e2e080, 0xf78ffab0, 0xf78f46b9, 
> 0xf7b55184)         = 0x56e30cd0  // (retval same for both!)
> cairo_restore(0x56e2e080, 0xf78ffab0, 0xf78f25e9, 
> 0x56594bdc)           = 0
> cairo_pattern_destroy(0x56e2e830, 0xf78ffab0, 0xf78f25e9, 
> 0x56594bdc)   = 8
> cairo_pattern_destroy(0x56e2e830, 0xf78ffab0, 0xf78f25e9, 
> 0x56594bdc)   = 7
>
> // CairoOutputDev::paintTransparencyGroup
> cairo_set_operator(0x56e2e080, 14, 0xf7b55184, 
> 0x565abb00)              = 0
> cairo_save(0x56e2e080, 0xffd4a6e4, 0xf78f4889, 
> 0x56597a6c)              = 0
> cairo_set_matrix(0x56e2e080, 0x56eabc08, 0xf78f4889, 
> 0x56597a6c)        = 0
> cairo_set_source(0x56e2e080, 0x56e30cd0, 0xf78f4889, 
> 0x56597a6c)        = 0
> cairo_paint_with_alpha(0x56e2e080, 0, 0x3ff00000, 
> 0x56597a6c)           = 0
> cairo_status(0x56e2e080, 0, 0x3ff00000, 
> 0x56597a6c)                     = 0
> _ZdlPvj(0x56eabc00, 60, 0x3ff00000, 
> 0x56597a6c)                         = 0
> cairo_restore(0x56e2e080, 60, 0x3ff00000, 
> 0x56597a6c)                   = 0
>
> cairo_restore(0x56e2e080, 32, 0xf78f25e9, 
> 0x56594bdc)                   = 0
> cairo_pattern_destroy(0x56e2e830, 32, 0xf78f25e9, 
> 0x56594bdc)           = 6
> cairo_pattern_destroy(0x56e2e830, 32, 0xf78f25e9, 
> 0x56594bdc)           = 5
>
> cairo_set_operator(0x56e2e080, 2, 0xf7b55184, 
> 0x565abb00)               = 0
> cairo_restore(0x56e2e080, 744, 0xffd4add4, 
> 0x56594bdc)                  = 0
> cairo_pattern_destroy(0x56e2e830, 744, 0xffd4add4, 
> 0x56594bdc)          = 4
> cairo_pattern_destroy(0x56e2e830, 744, 0xffd4add4, 
> 0x56594bdc)          = 3
>
> I believe cairo_set_operator(,14,) in paintTransparencyGroup should 
> output a gs change in BOTH cases, but it's only for the first case 
> when using a PDF surface; OTOH, when the context is backed by a Image 
> surface, CAIRO_OPERATOR_MULTIPLY is honored also for the second 
> highlight...
>
>   Tobias
>
>
> On 03/11/2022 14:53, Tobias Hoffmann wrote:
>> cairo 1.16.0 also exhibits the problem.
>>
>> AFAICT the difference between "small" and "Virtual Mechanics" in the 
>> content stream (obj 4) is that only for the "small" an additional 
>> "/b14 gs" command is present:
>>
>> [...]
>> q
>> 106.926 93.812 33.621 13.883 re W n
>> /b14 gs
>> q
>> 1 0 0 1 106 93 cm
>> /a0 gs /x7 Do
>> Q
>> Q q
>> 148.605 117.57 83.879 14.02 re W n
>> q
>> 1 0 0 1 148 117 cm
>> /a0 gs /x8 Do
>> Q
>> Q
>> [...]
>>
>> The ExtGState definitions says:
>> /a0 <<
>>   /CA 1
>>   /ca 1
>> >>
>> /b14 <<
>>   /BM /Multiply
>> >>
>>
>> Adding /b14 gs to drawing of the second XObject (i.e. /x8) fixes the 
>> output.
>>
>> Maybe someone with more knowledge about cairo's pdf surface and/or 
>> pdftocairo can help here?
>>
>>   Tobias
>>
>>
>> On 03/11/2022 13:47, Beckmann Urs (ID) wrote:
>>>
>>> Dear Cairo developers
>>>
>>> The attached pdf small-sample-with-comments.pdf gives incorrect 
>>> output from pdftocairo -pdf.
>>>
>>> The yellow stripe covers the text “Virtual Mechanics”, instead of 
>>> being transparent. Text “small” instead remains correctly not 
>>> covered after pdftocairo -pdf.
>>>
>>> pdftocairo -png and pdftocairo -ps give correct results. It looks 
>>> like the problem comes from cairo pdf output engine.
>>>
>>> Tested with cairo-version 1.17.4
>>>
>>> Kind regards
>>>
>>> Urs
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.cairographics.org/archives/cairo/attachments/20221103/09eb8c53/attachment-0001.htm>


More information about the cairo mailing list