pdf-cairo.cpp revision 281f415c86e8fdd9d9d6455d247fa5d00d9ccd3b
#define __SP_PDF_CAIRO_C__
/** \file
* PDF printing with Cairo.
*/
/*
* Authors:
* Miklós Erdélyi <erdelyim@gmail.com>
*
* Based on pdf.cpp
*
* Licensed under GNU GPL
*/
/* Plain Print */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_CAIRO_PDF
#ifndef PANGO_ENABLE_BACKEND
#define PANGO_ENABLE_BACKEND
#endif
#ifndef PANGO_ENABLE_ENGINE
#define PANGO_ENABLE_ENGINE
#endif
#include <signal.h>
#include <errno.h>
#include <libnr/n-art-bpath.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkradiobutton.h>
#include <gtk/gtkcombo.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkentry.h>
#include <gtk/gtktooltips.h>
#include "display/nr-arena-item.h"
#include "display/canvas-bpath.h"
#include "sp-item.h"
#include "style.h"
#include "sp-linear-gradient.h"
#include "sp-radial-gradient.h"
#include "libnrtype/font-instance.h"
#include "libnrtype/font-style-to-pos.h"
#include <unit-constants.h>
#include "pdf-cairo.h"
#include <cairo.h>
#include <cairo-pdf.h>
#include <pango/pangofc-fontmap.h>
#ifdef RENDER_WITH_PANGO_CAIRO
#include <pango/pangocairo.h>
#else
#include <cairo-ft.h>
#endif
namespace Inkscape {
namespace Extension {
namespace Internal {
static cairo_status_t _write_callback(void *closure, const unsigned char *data, unsigned int length);
static void _concat_transform(cairo_t *cr, double xx, double yx, double xy, double yy, double x0, double y0);
_dpi(72),
_bitmap(false)
{
}
PrintCairoPDF::~PrintCairoPDF(void)
{
/* restore default signal handling for SIGPIPE */
#endif
return;
}
unsigned int
{
static gchar const *const pdr[] = {"72", "75", "100", "144", "150", "200", "300", "360", "600", "1200", "2400", NULL};
#ifdef TED
#endif
/* Create dialog */
// SP_DT_WIDGET(SP_ACTIVE_DESKTOP)->window,
NULL,
NULL);
/* Print properties frame */
/* Print type */
_("Use PDF vector operators. The resulting image is usually smaller "
"in file size and can be arbitrarily scaled, but "
"patterns will be lost."), NULL);
rb = gtk_radio_button_new_with_label(gtk_radio_button_get_group((GtkRadioButton *) rb), _("Print as bitmap"));
_("Print everything as bitmap. The resulting image is usually larger "
"in file size and cannot be arbitrarily scaled without quality loss, "
"but all objects will be rendered exactly as displayed."), NULL);
/* Resolution */
_("Preferred resolution (dots per inch) of bitmap"), NULL);
/* Setup strings */
}
if (1) {
}
/* Print destination frame */
f = gtk_frame_new(_("Print destination"));
l = gtk_label_new(_("Printer name (as given by lpstat -p);\n"
"leave empty to use the system default printer.\n"
"Use '> filename' to print to file.\n"
"Use '| prog arg...' to pipe to a program."));
GtkWidget *e = gtk_entry_new();
if (1) {
? val
: "" ));
}
// pressing enter in the destination field is the same as clicking Print:
if (response == GTK_RESPONSE_OK) {
char const *sstr;
/* Arrgh, have to do something */
/* skip leading whitespace, bug #1068483 */
/* g_print("Printing to %s\n", fn); */
}
return ret;
}
unsigned int
{
gsize bytesWritten = 0;
/* TODO: Replace the below fprintf's with something that does the right thing whether in
* gui or batch mode (e.g. --print=blah). Consider throwing an exception: currently one of
* the callers (sp_print_document_to_file, "ret = mod->begin(doc)") wrongly ignores the
* return code.
*/
if (*fn == '|') {
fn += 1;
#ifndef WIN32
#else
#endif
if (!osp) {
return 0;
}
} else if (*fn == '>') {
fn += 1;
if (!osf) {
return 0;
}
} else {
/* put cwd stuff in here */
: g_strdup("lpr") );
#ifndef WIN32
#else
#endif
if (!osp) {
return 0;
}
}
}
if (_stream) {
/* fixme: this is kinda icky */
#endif
}
// test output stream?
// width and height in pt
NRRect d;
bool pageBoundingBox;
// printf("Page Bounding Box: %s\n", pageBoundingBox ? "TRUE" : "FALSE");
if (pageBoundingBox) {
} else {
// if not page, use our base, which is either root or the item we want to export
// convert from px to pt
}
// printf("\n _width:%f _height:%f scale:%f\n", _width, _height, PT_PER_PX);
pdf_surface = cairo_pdf_surface_create_for_stream(Inkscape::Extension::Internal::_write_callback, _stream, d.x1-d.x0, d.y1-d.y0);
// move to the origin
if (!_bitmap) {
// from now on we can output px, but they will be treated as pt
// note that the we do not have to flip the y axis
// because Cairo's coordinate system is identical to Inkscape's
}
return 1;
}
unsigned int
{
if (!_stream) return 0;
if (_bitmap) return 0;
pdf_surface = NULL;
/* Flush stream to be sure. */
/* fixme: should really use pclose for popen'd streams */
_stream = 0;
return 1;
}
unsigned int
{
if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
if (_bitmap) return 0;
if (opacity < 1.0) {
} else {
cairo_save(cr);
}
_concat_transform(cr, transform->c[0], transform->c[1], transform->c[2], transform->c[3], transform->c[4], transform->c[5]);
// printf("bind: (%f) %f %f %f %f %f %f\n", opacity, transform->c[0], transform->c[1], transform->c[2], transform->c[3], transform->c[4], transform->c[5]);
// remember these to be able to undo them when outputting text
return 1;
}
unsigned int
{
if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
if (_bitmap) return 0;
if (opacity < 1.0) {
} else {
}
// g_printf("release\n");
return 1;
}
unsigned int
{
if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
if (_bitmap) return 0;
return 1;
}
PrintCairoPDF::create_pattern_for_paint(SPPaintServer const *const paintserver, NRRect const *pbox, float alpha)
{
bool apply_bbox2user = false;
if (SP_IS_LINEARGRADIENT (paintserver)) {
// convert to userspace
}
// create linear gradient pattern
// add stops
float rgb[3];
cairo_pattern_add_color_stop_rgba(pattern, lg->vector.stops[i].offset, rgb[0], rgb[1], rgb[2], lg->vector.stops[i].opacity * alpha);
}
} else if (SP_IS_RADIALGRADIENT (paintserver)) {
if (df >= r) {
}
apply_bbox2user = true;
// create radial gradient pattern
// add stops
float rgb[3];
cairo_pattern_add_color_stop_rgba(pattern, rg->vector.stops[i].offset, rgb[0], rgb[1], rgb[2], rg->vector.stops[i].opacity * alpha);
}
}
if (pattern) {
// set extend type
switch (spread) {
break;
break;
case SP_GRADIENT_SPREAD_PAD:
default:
break;
}
if (g->gradientTransform_set) {
// apply gradient transformation
} else {
}
if (apply_bbox2user) {
// convert to userspace
}
}
return pattern;
}
void
{
float rgb[3];
} else {
if (pattern) {
}
}
}
unsigned int
PrintCairoPDF::fill(Inkscape::Extension::Print *mod, NRBPath const *bpath, NRMatrix const *ctm, SPStyle const *const style,
{
if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
if (_bitmap) return 0;
cairo_save(cr);
} else {
}
if (alpha != 1.0 &&
cairo_clip (cr);
} else {
cairo_fill(cr);
}
}
return 0;
}
void
{
float rgb[3];
if (pattern) {
}
}
{
} else {
}
// set line join type
case SP_STROKE_LINEJOIN_MITER:
break;
case SP_STROKE_LINEJOIN_ROUND:
break;
case SP_STROKE_LINEJOIN_BEVEL:
break;
}
// set line cap type
case SP_STROKE_LINECAP_BUTT:
break;
case SP_STROKE_LINECAP_ROUND:
break;
case SP_STROKE_LINECAP_SQUARE:
break;
}
}
unsigned int
PrintCairoPDF::stroke(Inkscape::Extension::Print *mod, NRBPath const *bpath, NRMatrix const *ctm, SPStyle const *style,
{
if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
if (_bitmap) return 0;
cairo_save(cr);
}
return 0;
}
unsigned int
PrintCairoPDF::image(Inkscape::Extension::Print *mod, guchar *px, unsigned int w, unsigned int h, unsigned int rs,
{
if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
if (_bitmap) return 0;
if (!px_rgba) return 0;
// make a copy of the original pixbuf with premultiplied alpha
// if we pass the original pixbuf it will get messed up
for (unsigned i = 0; i < h; i++) {
for (unsigned j = 0; j < w; j++) {
// calculate opacity-modified alpha
if (alpha != 1.0)
// premul alpha (needed because this will be undone by cairo-pdf)
}
}
cairo_surface_t *image_surface = cairo_image_surface_create_for_data(px_rgba, CAIRO_FORMAT_ARGB32, w, h, w * 4);
if (cairo_surface_status(image_surface)) {
return 0;
}
cairo_save(cr);
// scaling by width & height is not needed because it will be done by cairo-pdf
// we have to translate down by height also in order to eliminate the last translation done by sp_image_print
// set clip region so that the pattern will not be repeated (bug in Cairo prior 1.2.1)
cairo_rectangle(cr, 0, 0, w, h);
cairo_clip(cr);
return 0;
}
#define GLYPH_ARRAY_SIZE 64
#ifndef RENDER_WITH_PANGO_CAIRO
PrintCairoPDF::draw_glyphs(cairo_t *cr, NR::Point p, PangoFont *font, PangoGlyphString *glyph_string,
{
int num_invalid_glyphs = 0;
// skip glyphs which are PANGO_GLYPH_EMPTY (0x0FFFFFFF) or have
// the PANGO_GLYPH_UNKNOWN_FLAG (0x10000000) set
continue;
}
if (vertical) {
}
else
}
if (stroke)
else
}
#endif
unsigned int
{
bool dirty_pattern = false;
if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
if (_bitmap) return 0;
cairo_save(cr);
// this needs to be there to encounter Cairo's userspace locking semantics for set_source
// otherwise gradients won't be shown correctly
// printf("\n _last_tx:%f _last_ty:%f", _last_tx, _last_ty);
// create pango layout and context if needed
#ifdef RENDER_WITH_PANGO_CAIRO
//_context = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(pango_cairo_font_map_get_default()));
#else
#endif
}
// create font instance from style and use it
g_printf("Warning: trouble getting font_instance\n");
}
pango_font_description_set_absolute_size(adjusted, (gint)(style->font_size.computed * PANGO_SCALE));
#ifdef RENDER_WITH_PANGO_CAIRO
#else
#endif
return 0;
#ifndef RENDER_WITH_PANGO_CAIRO
// apply the selected font
double size;
{
dirty_pattern = true;
}
size = 12.0;
// adjust size and horizontal flip
#endif
{
// set fill style
#ifndef RENDER_WITH_PANGO_CAIRO
cursor += draw_glyphs(cr, cursor, run->item->analysis.font, run->glyphs, dirty_pattern, false) / PANGO_SCALE;
}
#else
// as pango has inverted origin we simulate the moveto and apply the vertical flip
//cairo_move_to(cr, _last_tx, _last_ty);
cairo_move_to(cr, 0, 0);
#endif
}
{
// set stroke style
// paint stroke
#ifndef RENDER_WITH_PANGO_CAIRO
cursor += draw_glyphs(cr, cursor, run->item->analysis.font, run->glyphs, dirty_pattern, true) / PANGO_SCALE;
}
#else
// as pango has inverted origin we simulate the moveto and apply the vertical flip
//cairo_move_to(cr, _last_tx, _last_ty);
cairo_move_to(cr, 0, 0);
#endif
}
#ifndef RENDER_WITH_PANGO_CAIRO
if (dirty_pattern) {
}
#endif
return 0;
}
/* Helper functions */
void
{
bool closed = false;
case NR_MOVETO:
if (closed) {
}
closed = true;
break;
case NR_MOVETO_OPEN:
if (closed) {
}
closed = false;
break;
case NR_LINETO:
break;
case NR_CURVETO:
break;
default:
break;
}
bp += 1;
}
if (closed) {
}
}
static void
{
}
static cairo_status_t
{
return CAIRO_STATUS_SUCCESS;
else
return CAIRO_STATUS_WRITE_ERROR;
}
bool
{
}
#include "clear-n_.h"
void
PrintCairoPDF::init(void)
{
/* PDF out */
"<inkscape-extension>\n"
"<param name=\"bitmap\" type=\"boolean\">FALSE</param>\n"
"<param name=\"resolution\" type=\"string\">72</param>\n"
"<param name=\"destination\" type=\"string\">| lp</param>\n"
"<param name=\"pageBoundingBox\" type=\"boolean\">TRUE</param>\n"
"<param name=\"textToPath\" type=\"boolean\">TRUE</param>\n"
"<param name=\"exportDrawing\" type=\"boolean\">FALSE</param>\n"
"<param name=\"exportId\" type=\"string\"></param>\n"
"<print/>\n"
"</inkscape-extension>", new PrintCairoPDF());
}
} /* namespace Internal */
} /* namespace Extension */
} /* namespace Inkscape */
/* End of GNU GPL code */
#endif /* HAVE_CAIRO_PDF */
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :