[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