[cairo] Writing Surface to PNG based on Window Context: POSSIBLE?

darethehair darethehair at gmail.com
Sat Mar 21 06:20:20 PDT 2009


Gerdus van Zyl wrote:
> Well it works for me! Below is the code I use:
> tsurf = ctx.get_target()
> tsurf.write_to_png("screenshot.png")
>
> This is code that works on MS Windows. According to the API docs it
> should work for any pixel based surface. But as suggested if you
> structure your code to be able to render to any cairo context that
> would of course be better in the long term.
>
> ~Gerdus
>
> On Sat, Mar 21, 2009 at 3:22 AM, Neil Mayhew
> <neil_mayhew at users.sourceforge.net> wrote:
>   
>> On 20/03/09 04:31 PM darethehair wrote:
>>     
>>> How does one invoke the 'write_to_png' in that situation? The reason I
>>> ask this is that I would like to be able to draw on the 'screen', but
>>> also re-direct to a PNG (or whatever) file if I want to.
>>>       
>> You can't write a window to a PNG (not with cairo, anyway). However, you
>> can refactor your program into two parts: one that takes a cairo.Context
>> as a parameter and generates the desired graphics, and another one that
>> sets up the destination surface and context and calls the other
>> (drawing) part.
>>
>> I've done this for one program I have been writing. It uses gtkmm and
>> cairomm rather than PyCairo, but the principle is the same. Depending on
>> the command-line arguments it either opens up a window and hooks the
>> pure-cairo drawing function to the expose event, or it creates a
>> pure-cairo surface, calls the drawing function on that, and then writes
>> it out. However, you could instead have a File -> Export menu item that
>> does the same thing.
>>
>> In case it's helpful, I've included the code I am using. It's in C++,
>> but hopefully you can translate.
>>
>> --Neil
>>
>> void export(std::string filename, int size_x, int size_y)
>> {
>>    std::string suffix = filename.substr(filename.rfind('.') + 1);
>>
>>    Cairo::RefPtr<Cairo::Surface> surface;
>>
>>    if (suffix == "pdf")
>>        surface = Cairo::PdfSurface::create(filename, size_x, size_y);
>>    else if (suffix == "svg")
>>        surface = Cairo::SvgSurface::create(filename, size_x, size_y);
>>    else if (suffix == "ps")
>>        surface = Cairo::PsSurface::create(filename, size_x, size_y);
>>    else if (suffix == "png")
>>        surface = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, \
>>            size_x, size_y);
>>    else
>>        throw std::runtime_error("Unknown filename suffix");
>>
>>    Cairo::RefPtr<Cairo::Context> context = \
>>        Cairo::Context::create(surface);
>>
>>    if (suffix == "png")
>>    {
>>        context->set_source_rgb(1.0, 1.0, 1.0);
>>        context->paint();
>>    }
>>
>>    render(context, size_x, size_y);
>>
>>    if (suffix == "png")
>>        surface->write_to_png(filename);
>> }
>>
>> _______________________________________________
>> cairo mailing list
>> cairo at cairographics.org
>> http://lists.cairographics.org/mailman/listinfo/cairo
>>
>>     
> _______________________________________________
> cairo mailing list
> cairo at cairographics.org
> http://lists.cairographics.org/mailman/listinfo/cairo
>   
Thanks to you both!

I pondered what Neil had said, and agreed that pushing *two* contexts -- 
one window-based, and another PNG-based -- through the same 'drawing' 
code -- would accomplish what I had desired.  However, I couldn't help 
thinking that there must be some better/easier way of somehow 
transferring one to another, without the hassle of repeating the same 
drawing code all over again.  It looks like Gerdus has the solution I 
was looking for!

Again, I am a total newbie, but this sounds like a perfect 
question/answer in an FAQ somewhere, right?

Dare


More information about the cairo mailing list