From 1c51deb0c68f8358e7db1501b6c0135364758c55 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 20 Feb 2010 22:01:12 +0100 Subject: add option to exclude/omit text from the PDF when saving to pdf (bzr r9101.1.1) --- src/extension/internal/cairo-renderer-pdf-out.cpp | 14 ++++++++++++-- src/extension/internal/cairo-renderer.cpp | 6 ++++++ src/extension/internal/cairo-renderer.h | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index 0598c388a..a62d2cb14 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -48,7 +48,7 @@ CairoRendererPdfOutput::check (Inkscape::Extension::Extension * module) static bool pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level, - bool texttopath, bool filtertobitmap, int resolution, + bool texttopath, bool texttolatex, bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas) { sp_document_ensure_up_to_date(doc); @@ -83,6 +83,7 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int CairoRenderContext *ctx = renderer->createContext(); ctx->setPDFLevel(level); ctx->setTextToPath(texttopath); + renderer->_omitText = texttolatex; ctx->setFilterToBitmap(filtertobitmap); ctx->setBitmapResolution(resolution); @@ -146,6 +147,14 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, g_warning("Parameter might not exist"); } + bool new_textToLaTeX = FALSE; + try { + new_textToLaTeX = mod->get_param_bool("textToLaTeX"); + } + catch(...) { + g_warning("Parameter might not exist"); + } + bool new_blurToBitmap = FALSE; try { new_blurToBitmap = mod->get_param_bool("blurToBitmap"); @@ -189,7 +198,7 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar * final_name; final_name = g_strdup_printf("> %s", filename); ret = pdf_render_document_to_file(doc, final_name, level, - new_textToPath, new_blurToBitmap, new_bitmapResolution, + new_textToPath, new_textToLaTeX, new_blurToBitmap, new_bitmapResolution, new_exportId, new_exportDrawing, new_exportCanvas); g_free(final_name); @@ -217,6 +226,7 @@ CairoRendererPdfOutput::init (void) "<_item value='PDF14'>" N_("PDF 1.4") "\n" "\n" "false\n" + "false\n" "true\n" "90\n" "false\n" diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 0e68ae130..6d75c1e5d 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -103,6 +103,7 @@ namespace Extension { namespace Internal { CairoRenderer::CairoRenderer(void) + : _omitText(false) {} CairoRenderer::~CairoRenderer(void) @@ -568,6 +569,11 @@ CairoRenderer::setStateForItem(CairoRenderContext *ctx, SPItem const *item) void CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item) { + if ( _omitText && (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) ) { + // skip text if _omitText is true + return; + } + ctx->pushState(); setStateForItem(ctx, item); diff --git a/src/extension/internal/cairo-renderer.h b/src/extension/internal/cairo-renderer.h index ab5d4cf58..d69a60753 100644 --- a/src/extension/internal/cairo-renderer.h +++ b/src/extension/internal/cairo-renderer.h @@ -56,6 +56,10 @@ public: /** Traverses the object tree and invokes the render methods. */ void renderItem(CairoRenderContext *ctx, SPItem *item); + + /** If _omitText is true, no text will be output to the PDF document. + The PDF will be exactly the same as if the text was written to it and then erased. */ + bool _omitText; }; // FIXME: this should be a static method of CairoRenderer -- cgit v1.2.3 From 7b45e3a1ecaabfef62c786e59aeb8023981dfbba Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 20 Feb 2010 23:07:44 +0100 Subject: initial work, plugging in a LaTeX renderer to write the text stuff to a .tex file. implementation of renderer is all that is left to do :) (bzr r9101.1.2) --- src/extension/internal/CMakeLists.txt | 1 + src/extension/internal/Makefile_insert | 2 + src/extension/internal/cairo-renderer-pdf-out.cpp | 76 +++- src/extension/internal/cairo-renderer.cpp | 2 + src/extension/internal/pdflatex-renderer.cpp | 428 ++++++++++++++++++++++ src/extension/internal/pdflatex-renderer.h | 82 +++++ 6 files changed, 581 insertions(+), 10 deletions(-) create mode 100644 src/extension/internal/pdflatex-renderer.cpp create mode 100644 src/extension/internal/pdflatex-renderer.h (limited to 'src') diff --git a/src/extension/internal/CMakeLists.txt b/src/extension/internal/CMakeLists.txt index c9c00e05b..3412b740c 100644 --- a/src/extension/internal/CMakeLists.txt +++ b/src/extension/internal/CMakeLists.txt @@ -20,6 +20,7 @@ latex-pstricks.cpp latex-pstricks-out.cpp odf.cpp pdfinput +pdflatex-renderer.cpp pdf-input-cairo.cpp pov-out.cpp javafx-out.cpp diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index d2ba9b3eb..881b3ec22 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -109,6 +109,8 @@ ink_common_sources += \ extension/internal/javafx-out.h \ extension/internal/gdkpixbuf-input.h \ extension/internal/gdkpixbuf-input.cpp \ + extension/internal/pdflatex-renderer.h \ + extension/internal/pdflatex-renderer.cpp \ extension/internal/pdfinput/svg-builder.h \ extension/internal/pdfinput/svg-builder.cpp \ extension/internal/pdfinput/pdf-parser.h \ diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index a62d2cb14..ba23f4bcc 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -20,6 +20,7 @@ #include "cairo-renderer-pdf-out.h" #include "cairo-render-context.h" #include "cairo-renderer.h" +#include "pdflatex-renderer.h" #include #include "extension/system.h" #include "extension/print.h" @@ -33,6 +34,8 @@ #include "sp-item.h" #include "sp-root.h" +#include <2geom/matrix.h> + namespace Inkscape { namespace Extension { namespace Internal { @@ -48,7 +51,7 @@ CairoRendererPdfOutput::check (Inkscape::Extension::Extension * module) static bool pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level, - bool texttopath, bool texttolatex, bool filtertobitmap, int resolution, + bool texttopath, bool omittext, bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas) { sp_document_ensure_up_to_date(doc); @@ -83,7 +86,7 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int CairoRenderContext *ctx = renderer->createContext(); ctx->setPDFLevel(level); ctx->setTextToPath(texttopath); - renderer->_omitText = texttolatex; + renderer->_omitText = omittext; ctx->setFilterToBitmap(filtertobitmap); ctx->setBitmapResolution(resolution); @@ -107,6 +110,45 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int return ret; } +static bool +latex_render_document_text_to_file( SPDocument *doc, gchar const *filename, + const gchar * const exportId, bool exportDrawing, bool exportCanvas) +{ + sp_document_ensure_up_to_date(doc); + +/* Start */ + + SPItem *base = NULL; + + bool pageBoundingBox = true; + if (exportId && strcmp(exportId, "")) { + // we want to export the given item only + base = SP_ITEM(doc->getObjectById(exportId)); + pageBoundingBox = exportCanvas; + } + else { + // we want to export the entire document from root + base = SP_ITEM(sp_document_root(doc)); + pageBoundingBox = !exportDrawing; + } + + if (!base) + return false; + + /* Create renderer */ + PDFLaTeXRenderer *renderer = new PDFLaTeXRenderer(); + + /* Render document */ + bool ret = renderer->setupDocument(doc, pageBoundingBox, base); + if (ret) { + renderer->renderItem(base); + } + + delete renderer; + + return ret; +} + /** \brief This function calls the output module with the filename @@ -195,15 +237,29 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, g_warning("Parameter might not exist"); } - gchar * final_name; - final_name = g_strdup_printf("> %s", filename); - ret = pdf_render_document_to_file(doc, final_name, level, - new_textToPath, new_textToLaTeX, new_blurToBitmap, new_bitmapResolution, - new_exportId, new_exportDrawing, new_exportCanvas); - g_free(final_name); + // Create PDF file + { + gchar * final_name; + final_name = g_strdup_printf("> %s", filename); + ret = pdf_render_document_to_file(doc, final_name, level, + new_textToPath, new_textToLaTeX, new_blurToBitmap, new_bitmapResolution, + new_exportId, new_exportDrawing, new_exportCanvas); + g_free(final_name); + + if (!ret) + throw Inkscape::Extension::Output::save_failed(); + } + + // Create LaTeX file (if requested) + if (new_textToLaTeX) { + gchar * tex_filename; + tex_filename = g_strdup_printf("%s.tex", filename); + ret = latex_render_document_text_to_file(doc, tex_filename, new_exportId, new_exportDrawing, new_exportCanvas); + g_free(tex_filename); - if (!ret) - throw Inkscape::Extension::Output::save_failed(); + if (!ret) + throw Inkscape::Extension::Output::save_failed(); + } } #include "clear-n_.h" diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 6d75c1e5d..6e4bb3b7e 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -598,6 +598,8 @@ CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item) bool CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool pageBoundingBox, SPItem *base) { +// PLEASE note when making changes to the boundingbox and transform calculation, corresponding changes should be made to PDFLaTeXRenderer::setupDocument !!! + g_assert( ctx != NULL ); if (!base) diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp new file mode 100644 index 000000000..bcababf8e --- /dev/null +++ b/src/extension/internal/pdflatex-renderer.cpp @@ -0,0 +1,428 @@ +#define EXTENSION_INTERNAL_PDF_LATEX_RENDERER_CPP + +/** \file + * Rendering LaTeX file (pdf+latex output) + */ +/* + * Authors: + * Johan Engelen + * Miklos Erdelyi + * + * Copyright (C) 2006-2010 Authors + * + * Licensed under GNU GPL + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef PANGO_ENABLE_BACKEND +#define PANGO_ENABLE_BACKEND +#endif + +#ifndef PANGO_ENABLE_ENGINE +#define PANGO_ENABLE_ENGINE +#endif + + +#include +#include + +#include "libnr/nr-rect.h" +#include "libnrtype/Layout-TNG.h" +#include <2geom/transforms.h> +#include <2geom/pathvector.h> + +#include + +#include +#include "display/nr-arena.h" +#include "display/nr-arena-item.h" +#include "display/nr-arena-group.h" +#include "display/curve.h" +#include "display/canvas-bpath.h" +#include "sp-item.h" +#include "sp-item-group.h" +#include "style.h" +#include "marker.h" +#include "sp-linear-gradient.h" +#include "sp-radial-gradient.h" +#include "sp-root.h" +#include "sp-use.h" +#include "sp-text.h" +#include "sp-flowtext.h" +#include "sp-mask.h" +#include "sp-clippath.h" + +#include +#include "helper/png-write.h" +#include "helper/pixbuf-ops.h" + +#include "pdflatex-renderer.h" +#include "extension/system.h" + +#include "io/sys.h" + +#include + +// include support for only the compiled-in surface types +#ifdef CAIRO_HAS_PDF_SURFACE +#include +#endif +#ifdef CAIRO_HAS_PS_SURFACE +#include +#endif + +//#define TRACE(_args) g_printf _args +#define TRACE(_args) +//#define TEST(_args) _args +#define TEST(_args) + +// FIXME: expose these from sp-clippath/mask.cpp +struct SPClipPathView { + SPClipPathView *next; + unsigned int key; + NRArenaItem *arenaitem; + NRRect bbox; +}; + +struct SPMaskView { + SPMaskView *next; + unsigned int key; + NRArenaItem *arenaitem; + NRRect bbox; +}; + +namespace Inkscape { +namespace Extension { +namespace Internal { + +PDFLaTeXRenderer::PDFLaTeXRenderer(void) + : _m(Geom::identity()) +{} + +PDFLaTeXRenderer::~PDFLaTeXRenderer(void) +{ + /* restore default signal handling for SIGPIPE */ +#if !defined(_WIN32) && !defined(__WIN32__) + (void) signal(SIGPIPE, SIG_DFL); +#endif + + return; +} + +void +PDFLaTeXRenderer::sp_group_render(SPItem *item) +{ + SPGroup *group = SP_GROUP(item); + + GSList *l = g_slist_reverse(group->childList(false)); + while (l) { + SPObject *o = SP_OBJECT (l->data); + if (SP_IS_ITEM(o)) { + renderItem (SP_ITEM (o)); + } + l = g_slist_remove (l, o); + } +} + +void +PDFLaTeXRenderer::sp_use_render(SPItem *item) +{ +/* + bool translated = false; + SPUse *use = SP_USE(item); + + if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) { + Geom::Matrix tp(Geom::Translate(use->x.computed, use->y.computed)); + ctx->pushState(); + ctx->transform(&tp); + translated = true; + } + + if (use->child && SP_IS_ITEM(use->child)) { + renderItem(SP_ITEM(use->child)); + } + + if (translated) { + ctx->popState(); + } +*/ +} + +void +PDFLaTeXRenderer::sp_text_render(SPItem *item) +{ + SPText *group = SP_TEXT (item); +/* +implement +*/ +} + +void +PDFLaTeXRenderer::sp_flowtext_render(SPItem *item) +{ + SPFlowtext *group = SP_FLOWTEXT(item); +/* +implement +*/ +} + +void +PDFLaTeXRenderer::sp_root_render(SPItem *item) +{ + SPRoot *root = SP_ROOT(item); + +/* + if (!ctx->getCurrentState()->has_overflow && SP_OBJECT(item)->parent) + ctx->addClippingRect(root->x.computed, root->y.computed, root->width.computed, root->height.computed); + + ctx->pushState(); + setStateForItem(ctx, item); + Geom::Matrix tempmat (root->c2p); + ctx->transform(&tempmat); + sp_group_render(item, ctx); + ctx->popState(); +*/ +} + +void +PDFLaTeXRenderer::sp_item_invoke_render(SPItem *item) +{ + // Check item's visibility + if (item->isHidden()) { + return; + } + + if (SP_IS_ROOT(item)) { + TRACE(("root\n")); + return sp_root_render(item); + } else if (SP_IS_GROUP(item)) { + TRACE(("group\n")); + return sp_group_render(item); + } else if (SP_IS_USE(item)) { + TRACE(("use begin---\n")); + sp_use_render(item); + TRACE(("---use end\n")); + } else if (SP_IS_TEXT(item)) { + TRACE(("text\n")); + return sp_text_render(item); + } else if (SP_IS_FLOWTEXT(item)) { + TRACE(("flowtext\n")); + return sp_flowtext_render(item); + } + // We are not interested in writing the other SPItem types to LaTeX +} + +void +PDFLaTeXRenderer::setStateForItem(SPItem const *item) +{ +/* + SPStyle const *style = SP_OBJECT_STYLE(item); + ctx->setStateForStyle(style); + + CairoRenderState *state = ctx->getCurrentState(); + state->clip_path = item->clip_ref->getObject(); + state->mask = item->mask_ref->getObject(); + state->item_transform = Geom::Matrix (item->transform); + + // If parent_has_userspace is true the parent state's transform + // has to be used for the mask's/clippath's context. + // This is so because we use the image's/(flow)text's transform for positioning + // instead of explicitly specifying it and letting the renderer do the + // transformation before rendering the item. + if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item) || SP_IS_IMAGE(item)) + state->parent_has_userspace = TRUE; + TRACE(("setStateForItem opacity: %f\n", state->opacity)); +*/ +} + +void +PDFLaTeXRenderer::renderItem(SPItem *item) +{ +/* + ctx->pushState(); + setStateForItem(ctx, item); + + CairoRenderState *state = ctx->getCurrentState(); + state->need_layer = ( state->mask || state->clip_path || state->opacity != 1.0 ); + + // Draw item on a temporary surface so a mask, clip path, or opacity can be applied to it. + if (state->need_layer) { + state->merge_opacity = FALSE; + ctx->pushLayer(); + } + Geom::Matrix tempmat (item->transform); + ctx->transform(&tempmat); + sp_item_invoke_render(item, ctx); + + if (state->need_layer) + ctx->popLayer(); + + ctx->popState(); +*/ +} + +bool +PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *base) +{ +// The boundingbox calculation here should be exactly the same as the one by CairoRenderer::setupDocument ! + + if (!base) + base = SP_ITEM(sp_document_root(doc)); + + NRRect d; + if (pageBoundingBox) { + d.x0 = d.y0 = 0; + d.x1 = ceil(sp_document_width(doc)); + d.y1 = ceil(sp_document_height(doc)); + } else { + sp_item_invoke_bbox(base, &d, sp_item_i2d_affine(base), TRUE, SPItem::RENDERING_BBOX); + } + + // convert from px to pt + d.x0 *= PT_PER_PX; + d.x1 *= PT_PER_PX; + d.y0 *= PT_PER_PX; + d.y1 *= PT_PER_PX; + + double _width = d.x1-d.x0; + double _height = d.y1-d.y0; + + if (!pageBoundingBox) + { + double high = sp_document_height(doc); + high *= PT_PER_PX; + + transform( Geom::Translate( -d.x0 * PX_PER_PT, + (d.y1 - high) * PX_PER_PT ) ); + } + + return true; +} + +void +PDFLaTeXRenderer::transform(Geom::Matrix const &transform) +{ + _m *= transform; +} + + +/* +#include "macros.h" // SP_PRINT_* + +// Apply an SVG clip path +void +PDFLaTeXRenderer::applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp) +{ + g_assert( ctx != NULL && ctx->_is_valid ); + + if (cp == NULL) + return; + + CairoRenderContext::CairoRenderMode saved_mode = ctx->getRenderMode(); + ctx->setRenderMode(CairoRenderContext::RENDER_MODE_CLIP); + + Geom::Matrix saved_ctm; + if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { + //SP_PRINT_DRECT("clipd", cp->display->bbox); + NRRect clip_bbox(cp->display->bbox); + Geom::Matrix t(Geom::Scale(clip_bbox.x1 - clip_bbox.x0, clip_bbox.y1 - clip_bbox.y0)); + t[4] = clip_bbox.x0; + t[5] = clip_bbox.y0; + t *= ctx->getCurrentState()->transform; + ctx->getTransform(&saved_ctm); + ctx->setTransform(&t); + } + + TRACE(("BEGIN clip\n")); + SPObject *co = SP_OBJECT(cp); + for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + if (SP_IS_ITEM(child)) { + SPItem *item = SP_ITEM(child); + + // combine transform of the item in clippath and the item using clippath: + Geom::Matrix tempmat (item->transform); + tempmat = tempmat * (ctx->getCurrentState()->item_transform); + + // render this item in clippath + ctx->pushState(); + ctx->transform(&tempmat); + setStateForItem(ctx, item); + sp_item_invoke_render(item, ctx); + ctx->popState(); + } + } + TRACE(("END clip\n")); + + // do clipping only if this was the first call to applyClipPath + if (ctx->getClipMode() == CairoRenderContext::CLIP_MODE_PATH + && saved_mode == CairoRenderContext::RENDER_MODE_NORMAL) + cairo_clip(ctx->_cr); + + if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) + ctx->setTransform(&saved_ctm); + + ctx->setRenderMode(saved_mode); +} + +// Apply an SVG mask +void +PDFLaTeXRenderer::applyMask(CairoRenderContext *ctx, SPMask const *mask) +{ + g_assert( ctx != NULL && ctx->_is_valid ); + + if (mask == NULL) + return; + + //SP_PRINT_DRECT("maskd", &mask->display->bbox); + NRRect mask_bbox(mask->display->bbox); + // TODO: should the bbox be transformed if maskUnits != userSpaceOnUse ? + if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { + Geom::Matrix t(Geom::Scale(mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0)); + t[4] = mask_bbox.x0; + t[5] = mask_bbox.y0; + t *= ctx->getCurrentState()->transform; + ctx->setTransform(&t); + } + + // Clip mask contents... but... + // The mask's bounding box is the "geometric bounding box" which doesn't allow for + // filters which extend outside the bounding box. So don't clip. + // ctx->addClippingRect(mask_bbox.x0, mask_bbox.y0, mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0); + + ctx->pushState(); + + TRACE(("BEGIN mask\n")); + SPObject *co = SP_OBJECT(mask); + for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + if (SP_IS_ITEM(child)) { + SPItem *item = SP_ITEM(child); + renderItem(ctx, item); + } + } + TRACE(("END mask\n")); + + ctx->popState(); +} +*/ + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + +#undef TRACE + +/* End of GNU GPL code */ + +/* + 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 : diff --git a/src/extension/internal/pdflatex-renderer.h b/src/extension/internal/pdflatex-renderer.h new file mode 100644 index 000000000..21609e892 --- /dev/null +++ b/src/extension/internal/pdflatex-renderer.h @@ -0,0 +1,82 @@ +#ifndef EXTENSION_INTERNAL_PDF_LATEX_RENDERER_H_SEEN +#define EXTENSION_INTERNAL_PDF_LATEX_RENDERER_H_SEEN + +/** \file + * Declaration of PDFLaTeXRenderer, used for rendering the accompanying LaTeX file when saving PDF output + LaTeX + */ +/* + * Authors: + * Johan Engelen + * + * Copyright (C) 2010 Authors + * + * Licensed under GNU GPL + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "extension/extension.h" +#include +#include + +#include "style.h" + +#include + +#include <2geom/matrix.h> + +class SPClipPath; +class SPMask; +class SPItem; + +namespace Inkscape { +namespace Extension { +namespace Internal { + +class PDFLaTeXRenderer { +public: + PDFLaTeXRenderer(); + virtual ~PDFLaTeXRenderer(); + + void setStateForItem(SPItem const *item); + +// void applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp); +// void applyMask(CairoRenderContext *ctx, SPMask const *mask); + + /** Initializes the PDFLaTeXRenderer according to the specified + SPDocument. Important to set the boundingbox to the pdf boundingbox */ + bool setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *base); + + /** Traverses the object tree and invokes the render methods. */ + void renderItem(SPItem *item); + +protected: + void transform(Geom::Matrix const &transform); + Geom::Matrix _m; // the transform for current item + + void sp_item_invoke_render(SPItem *item); + void sp_root_render(SPItem *item); + void sp_group_render(SPItem *item); + void sp_use_render(SPItem *item); + void sp_text_render(SPItem *item); + void sp_flowtext_render(SPItem *item); +}; + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + +#endif /* !EXTENSION_INTERNAL_CAIRO_RENDERER_H_SEEN */ + +/* + 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 : -- cgit v1.2.3 From 07f0d475c37240d4c150b34d6efde7b12d5409a3 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 21 Feb 2010 00:55:27 +0100 Subject: add --export-pdf-latex option to the cmdline (bzr r9101.1.3) --- src/main.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 75e882e99..6b87df194 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -143,6 +143,7 @@ enum { SP_ARG_EXPORT_PS, SP_ARG_EXPORT_EPS, SP_ARG_EXPORT_PDF, + SP_ARG_EXPORT_PDF_LATEX, #ifdef WIN32 SP_ARG_EXPORT_EMF, #endif //WIN32 @@ -181,6 +182,7 @@ static gchar *sp_export_dpi = NULL; static gchar *sp_export_area = NULL; static gboolean sp_export_area_drawing = FALSE; static gboolean sp_export_area_page = FALSE; +static gboolean sp_export_pdf_latex = FALSE; static gchar *sp_export_width = NULL; static gchar *sp_export_height = NULL; static gchar *sp_export_id = NULL; @@ -224,6 +226,7 @@ static void resetCommandlineGlobals() { sp_export_area = NULL; sp_export_area_drawing = FALSE; sp_export_area_page = FALSE; + sp_export_pdf_latex = FALSE; sp_export_width = NULL; sp_export_height = NULL; sp_export_id = NULL; @@ -372,6 +375,11 @@ struct poptOption options[] = { N_("Export document to a PDF file"), N_("FILENAME")}, + {"export-pdf-latex", 0, + POPT_ARG_NONE, &sp_export_pdf_latex, SP_ARG_EXPORT_PDF_LATEX, + N_("Export PDF without text. Besides the PDF, a LaTeX file is exported, putting the text on top of the PDF file. Include the result in LaTeX like: \\input{latexfile.tex}"), + NULL}, + #ifdef WIN32 {"export-emf", 'M', POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF, @@ -646,6 +654,7 @@ main(int argc, char **argv) || !strncmp(argv[i], "--export-eps", 12) || !strcmp(argv[i], "-A") || !strncmp(argv[i], "--export-pdf", 12) + || !strncmp(argv[i], "--export-pdf-latex", 18) #ifdef WIN32 || !strcmp(argv[i], "-M") || !strncmp(argv[i], "--export-emf", 12) @@ -1518,6 +1527,12 @@ static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime (*i)->set_param_bool("textToPath", FALSE); } + if (sp_export_pdf_latex) { + (*i)->set_param_bool("textToLaTeX", TRUE); + } else { + (*i)->set_param_bool("textToLaTeX", FALSE); + } + if (sp_export_ignore_filters) { (*i)->set_param_bool("blurToBitmap", FALSE); } else { -- cgit v1.2.3 From 76be5817cf9fdf8d74868516412bf9f46562a8a8 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 21 Feb 2010 01:05:44 +0100 Subject: writePreamble and writePostamble (bzr r9101.1.4) --- src/extension/internal/cairo-renderer-pdf-out.cpp | 9 +- src/extension/internal/pdflatex-renderer.cpp | 177 +++++++++++++++++++++- src/extension/internal/pdflatex-renderer.h | 10 ++ 3 files changed, 189 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index ba23f4bcc..f308f58ca 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -138,10 +138,13 @@ latex_render_document_text_to_file( SPDocument *doc, gchar const *filename, /* Create renderer */ PDFLaTeXRenderer *renderer = new PDFLaTeXRenderer(); - /* Render document */ - bool ret = renderer->setupDocument(doc, pageBoundingBox, base); + bool ret = renderer->setTargetFile(filename); if (ret) { - renderer->renderItem(base); + /* Render document */ + bool ret = renderer->setupDocument(doc, pageBoundingBox, base); + if (ret) { + renderer->renderItem(base); + } } delete renderer; diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp index bcababf8e..2d8c98ca4 100644 --- a/src/extension/internal/pdflatex-renderer.cpp +++ b/src/extension/internal/pdflatex-renderer.cpp @@ -10,6 +10,8 @@ * * Copyright (C) 2006-2010 Authors * + * Most of the pre- and postamble is copied from GNUPlot's epslatex terminal output :-) + * * Licensed under GNU GPL */ @@ -98,20 +100,184 @@ namespace Inkscape { namespace Extension { namespace Internal { + PDFLaTeXRenderer::PDFLaTeXRenderer(void) - : _m(Geom::identity()) + : _stream(NULL), + _filename(NULL), + _m(Geom::identity()), + _width(0), + _height(0) {} PDFLaTeXRenderer::~PDFLaTeXRenderer(void) { + if (_stream) { + writePostamble(); + + fclose(_stream); + } + /* restore default signal handling for SIGPIPE */ #if !defined(_WIN32) && !defined(__WIN32__) (void) signal(SIGPIPE, SIG_DFL); #endif + if (_filename) { + g_free(_filename); + } + return; } +/** This should create the output LaTeX file, and assign it to _stream. + * @return Returns true when succesfull + */ +bool +PDFLaTeXRenderer::setTargetFile(gchar const *filename) { + if (filename != NULL) { + _filename = g_strdup(filename); + while (isspace(*filename)) filename += 1; + Inkscape::IO::dump_fopen_call(filename, "K"); + FILE *osf = Inkscape::IO::fopen_utf8name(filename, "w+"); + if (!osf) { + fprintf(stderr, "inkscape: fopen(%s): %s\n", + filename, strerror(errno)); + return false; + } + _stream = osf; + } + + if (_stream) { + /* fixme: this is kinda icky */ +#if !defined(_WIN32) && !defined(__WIN32__) + (void) signal(SIGPIPE, SIG_IGN); +#endif + } + + fprintf(_stream, "%%%% Creator: Inkscape %s, www.inkscape.org\n", PACKAGE_STRING); + fprintf(_stream, "%%%% PDF + LaTeX output extension by Johan Engelen, 2010\n"); + /* flush this to test output stream as early as possible */ + if (fflush(_stream)) { + if (ferror(_stream)) { + g_print("Error %d on LaTeX file output stream: %s\n", errno, + g_strerror(errno)); + } + g_print("Output to LaTeX file failed\n"); + /* fixme: should use pclose() for pipes */ + fclose(_stream); + _stream = NULL; + fflush(stdout); + return false; + } + + writePreamble(); + + return true; +} + +/* Most of this preamble is copied from GNUPlot's epslatex terminal output :-) */ +static char const preamble[] = +"\\begingroup \n" +" \\makeatletter \n" +" \\providecommand\\color[2][]{%% \n" +" \\GenericError{(gnuplot) \\space\\space\\space\\@spaces}{%% \n" +" Package color not loaded in conjunction with \n" +" terminal option `colourtext'%% \n" +" }{See the gnuplot documentation for explanation.%% \n" +" }{Either use 'blacktext' in gnuplot or load the package \n" +" color.sty in LaTeX.}%% \n" +" \\renewcommand\\color[2][]{}%% \n" +" }%% \n" +" \\providecommand\\includegraphics[2][]{%% \n" +" \\GenericError{(gnuplot) \\space\\space\\space\\@spaces}{%% \n" +" Package graphicx or graphics not loaded%% \n" +" }{See the gnuplot documentation for explanation.%% \n" +" }{The gnuplot epslatex terminal needs graphicx.sty or graphics.sty.}%% \n" +" \\renewcommand\\includegraphics[2][]{}%% \n" +" }%% \n" +" \\providecommand\\rotatebox[2]{#2}%% \n" +" \\@ifundefined{ifGPcolor}{%% \n" +" \\newif\\ifGPcolor \n" +" \\GPcolorfalse \n" +" }{}%% \n" +" \\@ifundefined{ifGPblacktext}{%% \n" +" \\newif\\ifGPblacktext \n" +" \\GPblacktexttrue \n" +" }{}%% \n" +" %% define a \\g@addto@macro without @ in the name: \n" +" \\let\\gplgaddtomacro\\g@addto@macro \n" +" %% define empty templates for all commands taking text: \n" +" \\gdef\\gplbacktext{}%% \n" +" \\gdef\\gplfronttext{}%% \n" +" \\makeatother \n" +" \\ifGPblacktext \n" +" %% no textcolor at all \n" +" \\def\\colorrgb#1{}%% \n" +" \\def\\colorgray#1{}%% \n" +" \\else \n" +" %% gray or color? \n" +" \\ifGPcolor \n" +" \\def\\colorrgb#1{\\color[rgb]{#1}}%% \n" +" \\def\\colorgray#1{\\color[gray]{#1}}%% \n" +" \\expandafter\\def\\csname LTw\\endcsname{\\color{white}}%% \n" +" \\expandafter\\def\\csname LTb\\endcsname{\\color{black}}%% \n" +" \\expandafter\\def\\csname LTa\\endcsname{\\color{black}}%% \n" +" \\expandafter\\def\\csname LT0\\endcsname{\\color[rgb]{1,0,0}}%% \n" +" \\expandafter\\def\\csname LT1\\endcsname{\\color[rgb]{0,1,0}}%% \n" +" \\expandafter\\def\\csname LT2\\endcsname{\\color[rgb]{0,0,1}}%% \n" +" \\expandafter\\def\\csname LT3\\endcsname{\\color[rgb]{1,0,1}}%% \n" +" \\expandafter\\def\\csname LT4\\endcsname{\\color[rgb]{0,1,1}}%% \n" +" \\expandafter\\def\\csname LT5\\endcsname{\\color[rgb]{1,1,0}}%% \n" +" \\expandafter\\def\\csname LT6\\endcsname{\\color[rgb]{0,0,0}}%% \n" +" \\expandafter\\def\\csname LT7\\endcsname{\\color[rgb]{1,0.3,0}}%% \n" +" \\expandafter\\def\\csname LT8\\endcsname{\\color[rgb]{0.5,0.5,0.5}}%% \n" +" \\else \n" +" %% gray \n" +" \\def\\colorrgb#1{\\color{black}}%% \n" +" \\def\\colorgray#1{\\color[gray]{#1}}%% \n" +" \\expandafter\\def\\csname LTw\\endcsname{\\color{white}}% \n" +" \\expandafter\\def\\csname LTb\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LTa\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LT0\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LT1\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LT2\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LT3\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LT4\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LT5\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LT6\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LT7\\endcsname{\\color{black}}% \n" +" \\expandafter\\def\\csname LT8\\endcsname{\\color{black}}% \n" +" \\fi \n" +" \\fi \n" +" \\setlength{\\unitlength}{0.0500bp}%% \n"; + +static char const postamble1[] = +" }%% \n" +" \\gplgaddtomacro\\gplfronttext{% \n" +" }%% \n" +" \\gplbacktext \n"; + +static char const postamble2[] = +" \\gplfronttext \n" +" \\end{picture}% \n" +"\\endgroup \n"; + +void +PDFLaTeXRenderer::writePreamble() +{ + fprintf(_stream, "%s", preamble); +} +void +PDFLaTeXRenderer::writePostamble() +{ + fprintf(_stream, "%s", postamble1); + + // TODO: strip path from filename on Windows + fprintf(_stream, " \\put(0,0){\\includegraphics{%s}}%%\n", _filename); + + fprintf(_stream, "%s", postamble2); +} + void PDFLaTeXRenderer::sp_group_render(SPItem *item) { @@ -287,18 +453,21 @@ PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *b d.y0 *= PT_PER_PX; d.y1 *= PT_PER_PX; - double _width = d.x1-d.x0; - double _height = d.y1-d.y0; + _width = d.x1-d.x0; + _height = d.y1-d.y0; if (!pageBoundingBox) { double high = sp_document_height(doc); high *= PT_PER_PX; - transform( Geom::Translate( -d.x0 * PX_PER_PT, + transform( Geom::Translate( -d.x0 * PX_PER_PT, (d.y1 - high) * PX_PER_PT ) ); } + // write the info to LaTeX: + + return true; } diff --git a/src/extension/internal/pdflatex-renderer.h b/src/extension/internal/pdflatex-renderer.h index 21609e892..856631f95 100644 --- a/src/extension/internal/pdflatex-renderer.h +++ b/src/extension/internal/pdflatex-renderer.h @@ -40,6 +40,8 @@ public: PDFLaTeXRenderer(); virtual ~PDFLaTeXRenderer(); + bool setTargetFile(gchar const *filename); + void setStateForItem(SPItem const *item); // void applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp); @@ -53,8 +55,16 @@ public: void renderItem(SPItem *item); protected: + FILE * _stream; + gchar * _filename; + void transform(Geom::Matrix const &transform); Geom::Matrix _m; // the transform for current item + double _width; + double _height; + + void writePreamble(); + void writePostamble(); void sp_item_invoke_render(SPItem *item); void sp_root_render(SPItem *item); -- cgit v1.2.3 From 9a944fdc46e88fc8ba1d7e437a04dc4d5ed0df21 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 21 Feb 2010 02:23:33 +0100 Subject: start outputting text to tex. position is wrong. filename of pdf is wrong in latex code (bzr r9101.1.5) --- src/extension/internal/pdflatex-renderer.cpp | 95 +++++++++++++++++----------- 1 file changed, 57 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp index 2d8c98ca4..60b960ddb 100644 --- a/src/extension/internal/pdflatex-renderer.cpp +++ b/src/extension/internal/pdflatex-renderer.cpp @@ -56,6 +56,7 @@ #include "sp-flowtext.h" #include "sp-mask.h" #include "sp-clippath.h" +#include "text-editing.h" #include #include "helper/png-write.h" @@ -76,7 +77,7 @@ #include #endif -//#define TRACE(_args) g_printf _args +//#define TRACE(_args) g_message(_args) #define TRACE(_args) //#define TEST(_args) _args #define TEST(_args) @@ -135,8 +136,9 @@ PDFLaTeXRenderer::~PDFLaTeXRenderer(void) bool PDFLaTeXRenderer::setTargetFile(gchar const *filename) { if (filename != NULL) { - _filename = g_strdup(filename); while (isspace(*filename)) filename += 1; + + _filename = g_strdup(filename); Inkscape::IO::dump_fopen_call(filename, "K"); FILE *osf = Inkscape::IO::fopen_utf8name(filename, "w+"); if (!osf) { @@ -249,7 +251,7 @@ static char const preamble[] = " \\expandafter\\def\\csname LT8\\endcsname{\\color{black}}% \n" " \\fi \n" " \\fi \n" -" \\setlength{\\unitlength}{0.0500bp}%% \n"; +" \\setlength{\\unitlength}{1pt}% \n"; static char const postamble1[] = " }%% \n" @@ -273,7 +275,7 @@ PDFLaTeXRenderer::writePostamble() fprintf(_stream, "%s", postamble1); // TODO: strip path from filename on Windows - fprintf(_stream, " \\put(0,0){\\includegraphics{%s}}%%\n", _filename); + fprintf(_stream, " \\put(0,0){\\includegraphics{%s.pdf}}%%\n", _filename); fprintf(_stream, "%s", postamble2); } @@ -320,18 +322,34 @@ PDFLaTeXRenderer::sp_use_render(SPItem *item) void PDFLaTeXRenderer::sp_text_render(SPItem *item) { - SPText *group = SP_TEXT (item); -/* -implement -*/ + SPText *textobj = SP_TEXT (item); + + gchar *str = sp_te_get_string_multiline(item); + Geom::Point pos = SP_TEXT(item)->attributes.firstXY(); + gchar *alignment = "lb"; + + // write to LaTeX + Inkscape::SVGOStringStream os; + + os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){\\makebox(0,0)[" << alignment << "]{\\strut{}" << str << "}}%%\n"; + + fprintf(_stream, "%s", os.str().c_str()); } void PDFLaTeXRenderer::sp_flowtext_render(SPItem *item) { - SPFlowtext *group = SP_FLOWTEXT(item); -/* -implement +/* SPFlowtext *group = SP_FLOWTEXT(item); + + // write to LaTeX + Inkscape::SVGOStringStream os; + + os << " \\begin{picture}(" << _width << "," << _height << ")%%\n"; + os << " \\gplgaddtomacro\\gplbacktext{%%\n"; + os << " \\csname LTb\\endcsname%%\n"; + os << "\\put(0,0){\\makebox(0,0)[lb]{\\strut{}Position}}%%\n"; + + fprintf(_stream, "%s", os.str().c_str()); */ } @@ -340,17 +358,12 @@ PDFLaTeXRenderer::sp_root_render(SPItem *item) { SPRoot *root = SP_ROOT(item); -/* - if (!ctx->getCurrentState()->has_overflow && SP_OBJECT(item)->parent) - ctx->addClippingRect(root->x.computed, root->y.computed, root->width.computed, root->height.computed); - - ctx->pushState(); - setStateForItem(ctx, item); - Geom::Matrix tempmat (root->c2p); - ctx->transform(&tempmat); - sp_group_render(item, ctx); - ctx->popState(); -*/ +// ctx->pushState(); +// setStateForItem(ctx, item); +// Geom::Matrix tempmat (root->c2p); +// ctx->transform(&tempmat); + sp_group_render(item); +// ctx->popState(); } void @@ -361,6 +374,7 @@ PDFLaTeXRenderer::sp_item_invoke_render(SPItem *item) return; } + g_message("hier?"); if (SP_IS_ROOT(item)) { TRACE(("root\n")); return sp_root_render(item); @@ -407,27 +421,25 @@ PDFLaTeXRenderer::setStateForItem(SPItem const *item) void PDFLaTeXRenderer::renderItem(SPItem *item) { -/* - ctx->pushState(); - setStateForItem(ctx, item); +// ctx->pushState(); +// setStateForItem(ctx, item); - CairoRenderState *state = ctx->getCurrentState(); - state->need_layer = ( state->mask || state->clip_path || state->opacity != 1.0 ); +// CairoRenderState *state = ctx->getCurrentState(); +// state->need_layer = ( state->mask || state->clip_path || state->opacity != 1.0 ); // Draw item on a temporary surface so a mask, clip path, or opacity can be applied to it. - if (state->need_layer) { - state->merge_opacity = FALSE; - ctx->pushLayer(); - } +// if (state->need_layer) { +// state->merge_opacity = FALSE; +// ctx->pushLayer(); +// } Geom::Matrix tempmat (item->transform); - ctx->transform(&tempmat); - sp_item_invoke_render(item, ctx); +// ctx->transform(&tempmat); + sp_item_invoke_render(item); - if (state->need_layer) - ctx->popLayer(); +// if (state->need_layer) +// ctx->popLayer(); - ctx->popState(); -*/ +// ctx->popState(); } bool @@ -465,8 +477,15 @@ PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *b (d.y1 - high) * PX_PER_PT ) ); } - // write the info to LaTeX: + // write the info to LaTeX + Inkscape::SVGOStringStream os; + + os << " \\begin{picture}(" << _width << "," << _height << ")%%\n"; + os << " \\gplgaddtomacro\\gplbacktext{%%\n"; + os << " \\csname LTb\\endcsname%%\n"; + os << "\\put(0,0){\\makebox(0,0)[lb]{\\strut{}0,0}}%%\n"; + fprintf(_stream, "%s", os.str().c_str()); return true; } -- cgit v1.2.3 From a6149aae1803244c5a67200bfd953b57a3ee056d Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 21 Feb 2010 11:21:18 +0100 Subject: output test.tex instead of test.pdf.tex which does not work well. strip path from filename on windows (bzr r9101.1.6) --- src/extension/internal/cairo-renderer-pdf-out.cpp | 4 +++- src/extension/internal/pdflatex-renderer.cpp | 20 +++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index f308f58ca..594389c60 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -256,7 +256,9 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, // Create LaTeX file (if requested) if (new_textToLaTeX) { gchar * tex_filename; - tex_filename = g_strdup_printf("%s.tex", filename); + //strip filename of ".pdf", do not add ".tex" here. + gsize n = g_str_has_suffix(filename, ".pdf") ? strlen(filename)-4 : strlen(filename); + tex_filename = g_strndup(filename, n); ret = latex_render_document_text_to_file(doc, tex_filename, new_exportId, new_exportDrawing, new_exportCanvas); g_free(tex_filename); diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp index 60b960ddb..0d2ffcc94 100644 --- a/src/extension/internal/pdflatex-renderer.cpp +++ b/src/extension/internal/pdflatex-renderer.cpp @@ -139,14 +139,17 @@ PDFLaTeXRenderer::setTargetFile(gchar const *filename) { while (isspace(*filename)) filename += 1; _filename = g_strdup(filename); - Inkscape::IO::dump_fopen_call(filename, "K"); - FILE *osf = Inkscape::IO::fopen_utf8name(filename, "w+"); + + gchar *filename_ext = g_strdup_printf("%s.tex", filename); + Inkscape::IO::dump_fopen_call(filename_ext, "K"); + FILE *osf = Inkscape::IO::fopen_utf8name(filename_ext, "w+"); if (!osf) { fprintf(stderr, "inkscape: fopen(%s): %s\n", - filename, strerror(errno)); + filename_ext, strerror(errno)); return false; } _stream = osf; + g_free(filename_ext); } if (_stream) { @@ -158,6 +161,7 @@ PDFLaTeXRenderer::setTargetFile(gchar const *filename) { fprintf(_stream, "%%%% Creator: Inkscape %s, www.inkscape.org\n", PACKAGE_STRING); fprintf(_stream, "%%%% PDF + LaTeX output extension by Johan Engelen, 2010\n"); + fprintf(_stream, "%%%% Accompanies %s.pdf\n", _filename); /* flush this to test output stream as early as possible */ if (fflush(_stream)) { if (ferror(_stream)) { @@ -274,8 +278,14 @@ PDFLaTeXRenderer::writePostamble() { fprintf(_stream, "%s", postamble1); - // TODO: strip path from filename on Windows - fprintf(_stream, " \\put(0,0){\\includegraphics{%s.pdf}}%%\n", _filename); + // strip pathname on windows, as it is probably desired. It is not possible to work without paths on windows yet. (bug) +#ifdef WIN32 + gchar *figurefile = g_path_get_basename(_filename); +#else + gchar *figurefile = g_strdup(_filename); +#endif + fprintf(_stream, " \\put(0,0){\\includegraphics{%s.pdf}}%%\n", figurefile); + g_free(figurefile); fprintf(_stream, "%s", postamble2); } -- cgit v1.2.3 From edbd390b53f84e021ad029a37d221deefd27238c Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 21 Feb 2010 12:39:17 +0100 Subject: fix transforms (bzr r9101.1.7) --- src/extension/internal/pdflatex-renderer.cpp | 56 +++++++++++++++++++--------- src/extension/internal/pdflatex-renderer.h | 7 +++- 2 files changed, 43 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp index 0d2ffcc94..d21457a89 100644 --- a/src/extension/internal/pdflatex-renderer.cpp +++ b/src/extension/internal/pdflatex-renderer.cpp @@ -105,10 +105,11 @@ namespace Internal { PDFLaTeXRenderer::PDFLaTeXRenderer(void) : _stream(NULL), _filename(NULL), - _m(Geom::identity()), _width(0), _height(0) -{} +{ + push_transform(Geom::identity()); +} PDFLaTeXRenderer::~PDFLaTeXRenderer(void) { @@ -334,10 +335,14 @@ PDFLaTeXRenderer::sp_text_render(SPItem *item) { SPText *textobj = SP_TEXT (item); + push_transform(sp_item_i2doc_affine(item)); + gchar *str = sp_te_get_string_multiline(item); - Geom::Point pos = SP_TEXT(item)->attributes.firstXY(); + Geom::Point pos = textobj->attributes.firstXY() * transform(); gchar *alignment = "lb"; + pop_transform(); + // write to LaTeX Inkscape::SVGOStringStream os; @@ -370,10 +375,10 @@ PDFLaTeXRenderer::sp_root_render(SPItem *item) // ctx->pushState(); // setStateForItem(ctx, item); -// Geom::Matrix tempmat (root->c2p); -// ctx->transform(&tempmat); + Geom::Matrix tempmat (root->c2p); + push_transform(tempmat); sp_group_render(item); -// ctx->popState(); + pop_transform(); } void @@ -470,23 +475,22 @@ PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *b } // convert from px to pt - d.x0 *= PT_PER_PX; - d.x1 *= PT_PER_PX; - d.y0 *= PT_PER_PX; - d.y1 *= PT_PER_PX; - - _width = d.x1-d.x0; - _height = d.y1-d.y0; + push_transform( Geom::Scale(PT_PER_PX, PT_PER_PX) ); if (!pageBoundingBox) { double high = sp_document_height(doc); - high *= PT_PER_PX; - transform( Geom::Translate( -d.x0 * PX_PER_PT, - (d.y1 - high) * PX_PER_PT ) ); + push_transform( Geom::Translate( -d.x0, + -d.y0 ) ); } + // flip y-axis + push_transform( Geom::Scale(1,-1) * Geom::Translate(0, sp_document_height(doc)) ); + + _width = (d.x1-d.x0) * PT_PER_PX; + _height = (d.y1-d.y0) * PT_PER_PX; + // write the info to LaTeX Inkscape::SVGOStringStream os; @@ -500,12 +504,28 @@ PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *b return true; } +Geom::Matrix const & +PDFLaTeXRenderer::transform() +{ + return _transform_stack.top(); +} + void -PDFLaTeXRenderer::transform(Geom::Matrix const &transform) +PDFLaTeXRenderer::push_transform(Geom::Matrix const &tr) { - _m *= transform; + if(_transform_stack.size()){ + Geom::Matrix tr_top = _transform_stack.top(); + _transform_stack.push(tr * tr_top); + } else { + _transform_stack.push(tr); + } } +void +PDFLaTeXRenderer::pop_transform() +{ + _transform_stack.pop(); +} /* #include "macros.h" // SP_PRINT_* diff --git a/src/extension/internal/pdflatex-renderer.h b/src/extension/internal/pdflatex-renderer.h index 856631f95..93c06b114 100644 --- a/src/extension/internal/pdflatex-renderer.h +++ b/src/extension/internal/pdflatex-renderer.h @@ -26,6 +26,7 @@ #include #include <2geom/matrix.h> +#include class SPClipPath; class SPMask; @@ -58,8 +59,10 @@ protected: FILE * _stream; gchar * _filename; - void transform(Geom::Matrix const &transform); - Geom::Matrix _m; // the transform for current item + void push_transform(Geom::Matrix const &transform); + Geom::Matrix const & transform(); + void pop_transform(); + std::stack _transform_stack; double _width; double _height; -- cgit v1.2.3 From 4c24ea8784247bc7d1ff715124c2c05236675bb8 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 21 Feb 2010 13:50:05 +0100 Subject: add rotation to text output (the positioning is a little off) (bzr r9101.1.8) --- src/extension/internal/pdflatex-renderer.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp index d21457a89..ef97da444 100644 --- a/src/extension/internal/pdflatex-renderer.cpp +++ b/src/extension/internal/pdflatex-renderer.cpp @@ -335,18 +335,32 @@ PDFLaTeXRenderer::sp_text_render(SPItem *item) { SPText *textobj = SP_TEXT (item); - push_transform(sp_item_i2doc_affine(item)); + Geom::Matrix i2doc = sp_item_i2doc_affine(item); + push_transform(i2doc); gchar *str = sp_te_get_string_multiline(item); Geom::Point pos = textobj->attributes.firstXY() * transform(); gchar *alignment = "lb"; + // get rotation + Geom::Matrix wotransl = i2doc.without_translation(); + double degrees = -180/M_PI * Geom::atan2(wotransl.xAxis()); + pop_transform(); // write to LaTeX Inkscape::SVGOStringStream os; - os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){\\makebox(0,0)[" << alignment << "]{\\strut{}" << str << "}}%%\n"; +// os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){\\makebox(0,0)[" << alignment << "]{\\strut{}" << str << "}}%%\n"; + os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){"; + if (!Geom::are_near(degrees,0.)) { + os << "\\rotatebox{" << degrees << "}{"; + } + os << str; + if (!Geom::are_near(degrees,0.)) { + os << "}"; + } + os << "}%%\n"; fprintf(_stream, "%s", os.str().c_str()); } @@ -497,7 +511,6 @@ PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *b os << " \\begin{picture}(" << _width << "," << _height << ")%%\n"; os << " \\gplgaddtomacro\\gplbacktext{%%\n"; os << " \\csname LTb\\endcsname%%\n"; - os << "\\put(0,0){\\makebox(0,0)[lb]{\\strut{}0,0}}%%\n"; fprintf(_stream, "%s", os.str().c_str()); -- cgit v1.2.3 From 448efe9e05a1e3d8151fd19e00269556db6497ad Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 21 Feb 2010 13:50:53 +0100 Subject: remove g_message (bzr r9101.1.9) --- src/extension/internal/pdflatex-renderer.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp index ef97da444..866070bec 100644 --- a/src/extension/internal/pdflatex-renderer.cpp +++ b/src/extension/internal/pdflatex-renderer.cpp @@ -403,7 +403,6 @@ PDFLaTeXRenderer::sp_item_invoke_render(SPItem *item) return; } - g_message("hier?"); if (SP_IS_ROOT(item)) { TRACE(("root\n")); return sp_root_render(item); -- cgit v1.2.3 From 21ba76c6b6391eba5fb7e41798e1fe294e2fba5b Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 21 Feb 2010 15:42:52 +0100 Subject: add method to scale the image clean up the pre- and postamble add help text on how to use the tex file (bzr r9101.1.10) --- src/extension/internal/pdflatex-renderer.cpp | 135 ++++++--------------------- 1 file changed, 31 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp index 866070bec..5377ae57c 100644 --- a/src/extension/internal/pdflatex-renderer.cpp +++ b/src/extension/internal/pdflatex-renderer.cpp @@ -2,6 +2,8 @@ /** \file * Rendering LaTeX file (pdf+latex output) + * + * The idea stems from GNUPlot's epslatex terminal output :-) */ /* * Authors: @@ -10,8 +12,6 @@ * * Copyright (C) 2006-2010 Authors * - * Most of the pre- and postamble is copied from GNUPlot's epslatex terminal output :-) - * * Licensed under GNU GPL */ @@ -182,90 +182,26 @@ PDFLaTeXRenderer::setTargetFile(gchar const *filename) { return true; } -/* Most of this preamble is copied from GNUPlot's epslatex terminal output :-) */ static char const preamble[] = +"%% To include the image in your LaTeX document, write\n" +"%% \\setlength{\\unitlength}{}\n" +"%% \\input{filename.tex}\n" +"%% instead of\n" +"%% \\includegraphics[width=]{}\n" +"\n" "\\begingroup \n" " \\makeatletter \n" -" \\providecommand\\color[2][]{%% \n" -" \\GenericError{(gnuplot) \\space\\space\\space\\@spaces}{%% \n" -" Package color not loaded in conjunction with \n" -" terminal option `colourtext'%% \n" -" }{See the gnuplot documentation for explanation.%% \n" -" }{Either use 'blacktext' in gnuplot or load the package \n" -" color.sty in LaTeX.}%% \n" -" \\renewcommand\\color[2][]{}%% \n" +" \\providecommand\\color[2][]{% \n" +" \\GenericError{(Inkscape) \\space\\space\\@spaces}{% \n" +" Color is used for the text in Inkscape, but the color package color is not loaded. \n" +" }{Either use black text in Inkscape or load the package \n" +" color.sty in LaTeX.}% \n" +" \\renewcommand\\color[2][]{}% \n" " }%% \n" -" \\providecommand\\includegraphics[2][]{%% \n" -" \\GenericError{(gnuplot) \\space\\space\\space\\@spaces}{%% \n" -" Package graphicx or graphics not loaded%% \n" -" }{See the gnuplot documentation for explanation.%% \n" -" }{The gnuplot epslatex terminal needs graphicx.sty or graphics.sty.}%% \n" -" \\renewcommand\\includegraphics[2][]{}%% \n" -" }%% \n" -" \\providecommand\\rotatebox[2]{#2}%% \n" -" \\@ifundefined{ifGPcolor}{%% \n" -" \\newif\\ifGPcolor \n" -" \\GPcolorfalse \n" -" }{}%% \n" -" \\@ifundefined{ifGPblacktext}{%% \n" -" \\newif\\ifGPblacktext \n" -" \\GPblacktexttrue \n" -" }{}%% \n" -" %% define a \\g@addto@macro without @ in the name: \n" -" \\let\\gplgaddtomacro\\g@addto@macro \n" -" %% define empty templates for all commands taking text: \n" -" \\gdef\\gplbacktext{}%% \n" -" \\gdef\\gplfronttext{}%% \n" -" \\makeatother \n" -" \\ifGPblacktext \n" -" %% no textcolor at all \n" -" \\def\\colorrgb#1{}%% \n" -" \\def\\colorgray#1{}%% \n" -" \\else \n" -" %% gray or color? \n" -" \\ifGPcolor \n" -" \\def\\colorrgb#1{\\color[rgb]{#1}}%% \n" -" \\def\\colorgray#1{\\color[gray]{#1}}%% \n" -" \\expandafter\\def\\csname LTw\\endcsname{\\color{white}}%% \n" -" \\expandafter\\def\\csname LTb\\endcsname{\\color{black}}%% \n" -" \\expandafter\\def\\csname LTa\\endcsname{\\color{black}}%% \n" -" \\expandafter\\def\\csname LT0\\endcsname{\\color[rgb]{1,0,0}}%% \n" -" \\expandafter\\def\\csname LT1\\endcsname{\\color[rgb]{0,1,0}}%% \n" -" \\expandafter\\def\\csname LT2\\endcsname{\\color[rgb]{0,0,1}}%% \n" -" \\expandafter\\def\\csname LT3\\endcsname{\\color[rgb]{1,0,1}}%% \n" -" \\expandafter\\def\\csname LT4\\endcsname{\\color[rgb]{0,1,1}}%% \n" -" \\expandafter\\def\\csname LT5\\endcsname{\\color[rgb]{1,1,0}}%% \n" -" \\expandafter\\def\\csname LT6\\endcsname{\\color[rgb]{0,0,0}}%% \n" -" \\expandafter\\def\\csname LT7\\endcsname{\\color[rgb]{1,0.3,0}}%% \n" -" \\expandafter\\def\\csname LT8\\endcsname{\\color[rgb]{0.5,0.5,0.5}}%% \n" -" \\else \n" -" %% gray \n" -" \\def\\colorrgb#1{\\color{black}}%% \n" -" \\def\\colorgray#1{\\color[gray]{#1}}%% \n" -" \\expandafter\\def\\csname LTw\\endcsname{\\color{white}}% \n" -" \\expandafter\\def\\csname LTb\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LTa\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LT0\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LT1\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LT2\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LT3\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LT4\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LT5\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LT6\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LT7\\endcsname{\\color{black}}% \n" -" \\expandafter\\def\\csname LT8\\endcsname{\\color{black}}% \n" -" \\fi \n" -" \\fi \n" -" \\setlength{\\unitlength}{1pt}% \n"; - -static char const postamble1[] = -" }%% \n" -" \\gplgaddtomacro\\gplfronttext{% \n" -" }%% \n" -" \\gplbacktext \n"; - -static char const postamble2[] = -" \\gplfronttext \n" +" \\providecommand\\rotatebox[2]{#2}% \n" +" \\makeatother \n"; + +static char const postamble[] = " \\end{picture}% \n" "\\endgroup \n"; @@ -277,18 +213,7 @@ PDFLaTeXRenderer::writePreamble() void PDFLaTeXRenderer::writePostamble() { - fprintf(_stream, "%s", postamble1); - - // strip pathname on windows, as it is probably desired. It is not possible to work without paths on windows yet. (bug) -#ifdef WIN32 - gchar *figurefile = g_path_get_basename(_filename); -#else - gchar *figurefile = g_strdup(_filename); -#endif - fprintf(_stream, " \\put(0,0){\\includegraphics{%s.pdf}}%%\n", figurefile); - g_free(figurefile); - - fprintf(_stream, "%s", postamble2); + fprintf(_stream, "%s", postamble); } void @@ -352,7 +277,7 @@ PDFLaTeXRenderer::sp_text_render(SPItem *item) Inkscape::SVGOStringStream os; // os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){\\makebox(0,0)[" << alignment << "]{\\strut{}" << str << "}}%%\n"; - os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){"; + os << " \\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){"; if (!Geom::are_near(degrees,0.)) { os << "\\rotatebox{" << degrees << "}{"; } @@ -360,7 +285,7 @@ PDFLaTeXRenderer::sp_text_render(SPItem *item) if (!Geom::are_near(degrees,0.)) { os << "}"; } - os << "}%%\n"; + os << "}%\n"; fprintf(_stream, "%s", os.str().c_str()); } @@ -487,8 +412,11 @@ PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *b sp_item_invoke_bbox(base, &d, sp_item_i2d_affine(base), TRUE, SPItem::RENDERING_BBOX); } - // convert from px to pt - push_transform( Geom::Scale(PT_PER_PX, PT_PER_PX) ); + // scale all coordinates, such that the width of the image is 1, this is convenient for scaling the image in LaTeX + double scale = 1/(d.x1-d.x0); + _width = (d.x1-d.x0) * scale; + _height = (d.y1-d.y0) * scale; + push_transform( Geom::Scale(scale, scale) ); if (!pageBoundingBox) { @@ -501,15 +429,14 @@ PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *b // flip y-axis push_transform( Geom::Scale(1,-1) * Geom::Translate(0, sp_document_height(doc)) ); - _width = (d.x1-d.x0) * PT_PER_PX; - _height = (d.y1-d.y0) * PT_PER_PX; - // write the info to LaTeX Inkscape::SVGOStringStream os; - os << " \\begin{picture}(" << _width << "," << _height << ")%%\n"; - os << " \\gplgaddtomacro\\gplbacktext{%%\n"; - os << " \\csname LTb\\endcsname%%\n"; + os << " \\begin{picture}(" << _width << "," << _height << ")%\n"; + // strip pathname, as it is probably desired. Having a specific path in the TeX file is not convenient. + gchar *figurefile = g_path_get_basename(_filename); + os << " \\put(0,0){\\includegraphics[width=\\unitlength]{" << figurefile << ".pdf}}%\n"; + g_free(figurefile); fprintf(_stream, "%s", os.str().c_str()); -- cgit v1.2.3 From e0812df4068e0242e6fba24a1416f97e242f2fc7 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 21 Feb 2010 16:54:04 +0100 Subject: fix alignment issue. now the boundingbox is used for aligning, instead of the text anchor point. (bzr r9101.1.11) --- src/extension/internal/pdflatex-renderer.cpp | 40 ++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp index 5377ae57c..b70bac107 100644 --- a/src/extension/internal/pdflatex-renderer.cpp +++ b/src/extension/internal/pdflatex-renderer.cpp @@ -185,9 +185,9 @@ PDFLaTeXRenderer::setTargetFile(gchar const *filename) { static char const preamble[] = "%% To include the image in your LaTeX document, write\n" "%% \\setlength{\\unitlength}{}\n" -"%% \\input{filename.tex}\n" +"%% \\input{.tex}\n" "%% instead of\n" -"%% \\includegraphics[width=]{}\n" +"%% \\includegraphics[width=]{.pdf}\n" "\n" "\\begingroup \n" " \\makeatletter \n" @@ -264,12 +264,34 @@ PDFLaTeXRenderer::sp_text_render(SPItem *item) push_transform(i2doc); gchar *str = sp_te_get_string_multiline(item); - Geom::Point pos = textobj->attributes.firstXY() * transform(); - gchar *alignment = "lb"; + + // get position and alignment + Geom::Point pos; + gchar *alignment = NULL; + Geom::OptRect bbox = item->getBounds(transform()); + Geom::Interval bbox_x = (*bbox)[Geom::X]; + Geom::Interval bbox_y = (*bbox)[Geom::Y]; + SPStyle *style = SP_OBJECT_STYLE (SP_OBJECT(item)); + switch (style->text_anchor.computed) { + case SP_CSS_TEXT_ANCHOR_START: + pos = Geom::Point( bbox_x.min() , bbox_y.middle() ); + alignment = "[l]"; + break; + case SP_CSS_TEXT_ANCHOR_END: + pos = Geom::Point( bbox_x.max() , bbox_y.middle() ); + alignment = "[r]"; + break; + case SP_CSS_TEXT_ANCHOR_MIDDLE: + default: + pos = bbox->midpoint(); + alignment = ""; + break; + } // get rotation Geom::Matrix wotransl = i2doc.without_translation(); double degrees = -180/M_PI * Geom::atan2(wotransl.xAxis()); + bool has_rotation = !Geom::are_near(degrees,0.); pop_transform(); @@ -278,14 +300,16 @@ PDFLaTeXRenderer::sp_text_render(SPItem *item) // os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){\\makebox(0,0)[" << alignment << "]{\\strut{}" << str << "}}%%\n"; os << " \\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){"; - if (!Geom::are_near(degrees,0.)) { + os << "\\makebox(0,0)" << alignment << "{"; + if (has_rotation) { os << "\\rotatebox{" << degrees << "}{"; } os << str; - if (!Geom::are_near(degrees,0.)) { - os << "}"; + if (has_rotation) { + os << "}"; // rotatebox end } - os << "}%\n"; + os << "}"; //makebox end + os << "}%\n"; // put end fprintf(_stream, "%s", os.str().c_str()); } -- cgit v1.2.3 From bde8ed1df082d20ca7bc31f9ede94419cde16b11 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 22 Feb 2010 20:33:37 +0100 Subject: - change cmdline option to --export-latex. - change source file names to reflect that it is "generic" latex renderer - make latex export work for EPS and PS aswell (bzr r9101.1.13) --- src/extension/internal/Makefile_insert | 4 +- src/extension/internal/cairo-ps-out.cpp | 79 ++- src/extension/internal/cairo-renderer-pdf-out.cpp | 50 +- src/extension/internal/latex-text-renderer.cpp | 648 ++++++++++++++++++++++ src/extension/internal/latex-text-renderer.h | 97 ++++ src/extension/internal/pdflatex-renderer.cpp | 609 -------------------- src/extension/internal/pdflatex-renderer.h | 95 ---- src/main.cpp | 16 +- 8 files changed, 825 insertions(+), 773 deletions(-) create mode 100644 src/extension/internal/latex-text-renderer.cpp create mode 100644 src/extension/internal/latex-text-renderer.h delete mode 100644 src/extension/internal/pdflatex-renderer.cpp delete mode 100644 src/extension/internal/pdflatex-renderer.h (limited to 'src') diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index 881b3ec22..3c1ce7f43 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -109,8 +109,8 @@ ink_common_sources += \ extension/internal/javafx-out.h \ extension/internal/gdkpixbuf-input.h \ extension/internal/gdkpixbuf-input.cpp \ - extension/internal/pdflatex-renderer.h \ - extension/internal/pdflatex-renderer.cpp \ + extension/internal/latex-text-renderer.h \ + extension/internal/latex-text-renderer.cpp \ extension/internal/pdfinput/svg-builder.h \ extension/internal/pdfinput/svg-builder.cpp \ extension/internal/pdfinput/pdf-parser.h \ diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index 737bb2885..6f22dbdc7 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -21,6 +21,7 @@ #include "cairo-ps-out.h" #include "cairo-render-context.h" #include "cairo-renderer.h" +#include "latex-text-renderer.h" #include #include "extension/system.h" #include "extension/print.h" @@ -61,7 +62,8 @@ bool CairoEpsOutput::check (Inkscape::Extension::Extension * /*module*/) } static bool -ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level, bool texttopath, bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas, bool eps = false) +ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level, bool texttopath, bool omittext, + bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas, bool eps = false) { sp_document_ensure_up_to_date(doc); @@ -93,6 +95,7 @@ ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int l ctx->setPSLevel(level); ctx->setEPS(eps); ctx->setTextToPath(texttopath); + renderer->_omitText = omittext; ctx->setFilterToBitmap(filtertobitmap); ctx->setBitmapResolution(resolution); @@ -146,6 +149,14 @@ CairoPsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar con new_textToPath = mod->get_param_bool("textToPath"); } catch(...) {} + bool new_textToLaTeX = FALSE; + try { + new_textToLaTeX = mod->get_param_bool("textToLaTeX"); + } + catch(...) { + g_warning("Parameter might not exist"); + } + bool new_blurToBitmap = FALSE; try { new_blurToBitmap = mod->get_param_bool("blurToBitmap"); @@ -171,13 +182,29 @@ CairoPsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar con new_exportId = mod->get_param_string("exportId"); } catch(...) {} - gchar * final_name; - final_name = g_strdup_printf("> %s", filename); - ret = ps_print_document_to_file(doc, final_name, level, new_textToPath, new_blurToBitmap, new_bitmapResolution, new_exportId, new_areaDrawing, new_areaPage); - g_free(final_name); + // Create PS + { + gchar * final_name; + final_name = g_strdup_printf("> %s", filename); + ret = ps_print_document_to_file(doc, final_name, level, new_textToPath, new_textToLaTeX, new_blurToBitmap, new_bitmapResolution, new_exportId, new_areaDrawing, new_areaPage); + g_free(final_name); - if (!ret) - throw Inkscape::Extension::Output::save_failed(); + if (!ret) + throw Inkscape::Extension::Output::save_failed(); + } + + // Create LaTeX file (if requested) + if (new_textToLaTeX) { + gchar * tex_filename; + //strip filename of ".ps", do not add ".tex" here. + gsize n = g_str_has_suffix(filename, ".ps") ? strlen(filename)-3 : strlen(filename); + tex_filename = g_strndup(filename, n); + ret = latex_render_document_text_to_file(doc, tex_filename, new_exportId, new_areaDrawing, new_areaPage); + g_free(tex_filename); + + if (!ret) + throw Inkscape::Extension::Output::save_failed(); + } } @@ -210,6 +237,14 @@ CairoEpsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar co new_textToPath = mod->get_param_bool("textToPath"); } catch(...) {} + bool new_textToLaTeX = FALSE; + try { + new_textToLaTeX = mod->get_param_bool("textToLaTeX"); + } + catch(...) { + g_warning("Parameter might not exist"); + } + bool new_blurToBitmap = FALSE; try { new_blurToBitmap = mod->get_param_bool("blurToBitmap"); @@ -235,13 +270,29 @@ CairoEpsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar co new_exportId = mod->get_param_string("exportId"); } catch(...) {} - gchar * final_name; - final_name = g_strdup_printf("> %s", filename); - ret = ps_print_document_to_file(doc, final_name, level, new_textToPath, new_blurToBitmap, new_bitmapResolution, new_exportId, new_areaDrawing, new_areaPage, true); - g_free(final_name); + // Create EPS + { + gchar * final_name; + final_name = g_strdup_printf("> %s", filename); + ret = ps_print_document_to_file(doc, final_name, level, new_textToPath, new_textToLaTeX, new_blurToBitmap, new_bitmapResolution, new_exportId, new_areaDrawing, new_areaPage, true); + g_free(final_name); - if (!ret) - throw Inkscape::Extension::Output::save_failed(); + if (!ret) + throw Inkscape::Extension::Output::save_failed(); + } + + // Create LaTeX file (if requested) + if (new_textToLaTeX) { + gchar * tex_filename; + //strip filename of ".eps", do not add ".tex" here. + gsize n = g_str_has_suffix(filename, ".eps") ? strlen(filename)-4 : strlen(filename); + tex_filename = g_strndup(filename, n); + ret = latex_render_document_text_to_file(doc, tex_filename, new_exportId, new_areaDrawing, new_areaPage); + g_free(tex_filename); + + if (!ret) + throw Inkscape::Extension::Output::save_failed(); + } } @@ -280,6 +331,7 @@ CairoPsOutput::init (void) #endif "\n" "false\n" + "false\n" "true\n" "90\n" "true\n" @@ -317,6 +369,7 @@ CairoEpsOutput::init (void) #endif "\n" "false\n" + "false\n" "true\n" "90\n" "true\n" diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index 594389c60..1dcfbdf1d 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -5,8 +5,9 @@ * Authors: * Ted Gould * Ulf Erikson + * Johan Engelen * - * Copyright (C) 2004-2006 Authors + * Copyright (C) 2004-2010 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -20,7 +21,7 @@ #include "cairo-renderer-pdf-out.h" #include "cairo-render-context.h" #include "cairo-renderer.h" -#include "pdflatex-renderer.h" +#include "latex-text-renderer.h" #include #include "extension/system.h" #include "extension/print.h" @@ -110,49 +111,6 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int return ret; } -static bool -latex_render_document_text_to_file( SPDocument *doc, gchar const *filename, - const gchar * const exportId, bool exportDrawing, bool exportCanvas) -{ - sp_document_ensure_up_to_date(doc); - -/* Start */ - - SPItem *base = NULL; - - bool pageBoundingBox = true; - if (exportId && strcmp(exportId, "")) { - // we want to export the given item only - base = SP_ITEM(doc->getObjectById(exportId)); - pageBoundingBox = exportCanvas; - } - else { - // we want to export the entire document from root - base = SP_ITEM(sp_document_root(doc)); - pageBoundingBox = !exportDrawing; - } - - if (!base) - return false; - - /* Create renderer */ - PDFLaTeXRenderer *renderer = new PDFLaTeXRenderer(); - - bool ret = renderer->setTargetFile(filename); - if (ret) { - /* Render document */ - bool ret = renderer->setupDocument(doc, pageBoundingBox, base); - if (ret) { - renderer->renderItem(base); - } - } - - delete renderer; - - return ret; -} - - /** \brief This function calls the output module with the filename \param mod unused @@ -287,7 +245,7 @@ CairoRendererPdfOutput::init (void) "<_item value='PDF14'>" N_("PDF 1.4") "\n" "\n" "false\n" - "false\n" + "false\n" "true\n" "90\n" "false\n" diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp new file mode 100644 index 000000000..83bb7c52d --- /dev/null +++ b/src/extension/internal/latex-text-renderer.cpp @@ -0,0 +1,648 @@ +#define EXTENSION_INTERNAL_PDF_LATEX_RENDERER_CPP + +/** \file + * Rendering LaTeX file (pdf+latex output) + * + * The idea stems from GNUPlot's epslatex terminal output :-) + */ +/* + * Authors: + * Johan Engelen + * Miklos Erdelyi + * + * Copyright (C) 2006-2010 Authors + * + * Licensed under GNU GPL + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef PANGO_ENABLE_BACKEND +#define PANGO_ENABLE_BACKEND +#endif + +#ifndef PANGO_ENABLE_ENGINE +#define PANGO_ENABLE_ENGINE +#endif + + +#include +#include + +#include "libnr/nr-rect.h" +#include "libnrtype/Layout-TNG.h" +#include <2geom/transforms.h> +#include <2geom/pathvector.h> + +#include + +#include +#include "display/nr-arena.h" +#include "display/nr-arena-item.h" +#include "display/nr-arena-group.h" +#include "display/curve.h" +#include "display/canvas-bpath.h" +#include "sp-item.h" +#include "sp-item-group.h" +#include "style.h" +#include "marker.h" +#include "sp-linear-gradient.h" +#include "sp-radial-gradient.h" +#include "sp-root.h" +#include "sp-use.h" +#include "sp-text.h" +#include "sp-flowtext.h" +#include "sp-mask.h" +#include "sp-clippath.h" +#include "text-editing.h" + +#include +#include "helper/png-write.h" +#include "helper/pixbuf-ops.h" + +#include "latex-text-renderer.h" +#include "extension/system.h" + +#include "io/sys.h" + +#include + +// include support for only the compiled-in surface types +#ifdef CAIRO_HAS_PDF_SURFACE +#include +#endif +#ifdef CAIRO_HAS_PS_SURFACE +#include +#endif + +//#define TRACE(_args) g_message(_args) +#define TRACE(_args) +//#define TEST(_args) _args +#define TEST(_args) + +// FIXME: expose these from sp-clippath/mask.cpp +struct SPClipPathView { + SPClipPathView *next; + unsigned int key; + NRArenaItem *arenaitem; + NRRect bbox; +}; + +struct SPMaskView { + SPMaskView *next; + unsigned int key; + NRArenaItem *arenaitem; + NRRect bbox; +}; + + +namespace Inkscape { +namespace Extension { +namespace Internal { + +bool +latex_render_document_text_to_file( SPDocument *doc, gchar const *filename, + const gchar * const exportId, bool exportDrawing, bool exportCanvas) +{ + sp_document_ensure_up_to_date(doc); + + SPItem *base = NULL; + + bool pageBoundingBox = true; + if (exportId && strcmp(exportId, "")) { + // we want to export the given item only + base = SP_ITEM(doc->getObjectById(exportId)); + pageBoundingBox = exportCanvas; + } + else { + // we want to export the entire document from root + base = SP_ITEM(sp_document_root(doc)); + pageBoundingBox = !exportDrawing; + } + + if (!base) + return false; + + /* Create renderer */ + LaTeXTextRenderer *renderer = new LaTeXTextRenderer(); + + bool ret = renderer->setTargetFile(filename); + if (ret) { + /* Render document */ + bool ret = renderer->setupDocument(doc, pageBoundingBox, base); + if (ret) { + renderer->renderItem(base); + } + } + + delete renderer; + + return ret; +} + +LaTeXTextRenderer::LaTeXTextRenderer(void) + : _stream(NULL), + _filename(NULL), + _width(0), + _height(0) +{ + push_transform(Geom::identity()); +} + +LaTeXTextRenderer::~LaTeXTextRenderer(void) +{ + if (_stream) { + writePostamble(); + + fclose(_stream); + } + + /* restore default signal handling for SIGPIPE */ +#if !defined(_WIN32) && !defined(__WIN32__) + (void) signal(SIGPIPE, SIG_DFL); +#endif + + if (_filename) { + g_free(_filename); + } + + return; +} + +/** This should create the output LaTeX file, and assign it to _stream. + * @return Returns true when succesfull + */ +bool +LaTeXTextRenderer::setTargetFile(gchar const *filename) { + if (filename != NULL) { + while (isspace(*filename)) filename += 1; + + _filename = g_path_get_basename(filename); + + gchar *filename_ext = g_strdup_printf("%s.tex", filename); + Inkscape::IO::dump_fopen_call(filename_ext, "K"); + FILE *osf = Inkscape::IO::fopen_utf8name(filename_ext, "w+"); + if (!osf) { + fprintf(stderr, "inkscape: fopen(%s): %s\n", + filename_ext, strerror(errno)); + return false; + } + _stream = osf; + g_free(filename_ext); + } + + if (_stream) { + /* fixme: this is kinda icky */ +#if !defined(_WIN32) && !defined(__WIN32__) + (void) signal(SIGPIPE, SIG_IGN); +#endif + } + + fprintf(_stream, "%%%% Creator: Inkscape %s, www.inkscape.org\n", PACKAGE_STRING); + fprintf(_stream, "%%%% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010\n"); + fprintf(_stream, "%%%% Accompanies image file '%s' (pdf, eps, ps)\n", _filename); + fprintf(_stream, "%%%%"); + /* flush this to test output stream as early as possible */ + if (fflush(_stream)) { + if (ferror(_stream)) { + g_print("Error %d on LaTeX file output stream: %s\n", errno, + g_strerror(errno)); + } + g_print("Output to LaTeX file failed\n"); + /* fixme: should use pclose() for pipes */ + fclose(_stream); + _stream = NULL; + fflush(stdout); + return false; + } + + writePreamble(); + + return true; +} + +static char const preamble[] = +"%% To include the image in your LaTeX document, write\n" +"%% \\setlength{\\unitlength}{}\n" +"%% \\input{.tex}\n" +"%% instead of\n" +"%% \\includegraphics[width=]{.pdf}\n" +"\n" +"\\begingroup \n" +" \\makeatletter \n" +" \\providecommand\\color[2][]{% \n" +" \\GenericError{(Inkscape) \\space\\space\\@spaces}{% \n" +" Color is used for the text in Inkscape, but the color package color is not loaded. \n" +" }{Either use black text in Inkscape or load the package \n" +" color.sty in LaTeX.}% \n" +" \\renewcommand\\color[2][]{}% \n" +" }%% \n" +" \\providecommand\\rotatebox[2]{#2}% \n" +" \\makeatother \n"; + +static char const postamble[] = +" \\end{picture}% \n" +"\\endgroup \n"; + +void +LaTeXTextRenderer::writePreamble() +{ + fprintf(_stream, "%s", preamble); +} +void +LaTeXTextRenderer::writePostamble() +{ + fprintf(_stream, "%s", postamble); +} + +void +LaTeXTextRenderer::sp_group_render(SPItem *item) +{ + SPGroup *group = SP_GROUP(item); + + GSList *l = g_slist_reverse(group->childList(false)); + while (l) { + SPObject *o = SP_OBJECT (l->data); + if (SP_IS_ITEM(o)) { + renderItem (SP_ITEM (o)); + } + l = g_slist_remove (l, o); + } +} + +void +LaTeXTextRenderer::sp_use_render(SPItem *item) +{ +/* + bool translated = false; + SPUse *use = SP_USE(item); + + if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) { + Geom::Matrix tp(Geom::Translate(use->x.computed, use->y.computed)); + ctx->pushState(); + ctx->transform(&tp); + translated = true; + } + + if (use->child && SP_IS_ITEM(use->child)) { + renderItem(SP_ITEM(use->child)); + } + + if (translated) { + ctx->popState(); + } +*/ +} + +void +LaTeXTextRenderer::sp_text_render(SPItem *item) +{ + SPText *textobj = SP_TEXT (item); + + Geom::Matrix i2doc = sp_item_i2doc_affine(item); + push_transform(i2doc); + + gchar *str = sp_te_get_string_multiline(item); + + // get position and alignment + Geom::Point pos; + gchar *alignment = NULL; + Geom::OptRect bbox = item->getBounds(transform()); + Geom::Interval bbox_x = (*bbox)[Geom::X]; + Geom::Interval bbox_y = (*bbox)[Geom::Y]; + SPStyle *style = SP_OBJECT_STYLE (SP_OBJECT(item)); + switch (style->text_anchor.computed) { + case SP_CSS_TEXT_ANCHOR_START: + pos = Geom::Point( bbox_x.min() , bbox_y.middle() ); + alignment = "[l]"; + break; + case SP_CSS_TEXT_ANCHOR_END: + pos = Geom::Point( bbox_x.max() , bbox_y.middle() ); + alignment = "[r]"; + break; + case SP_CSS_TEXT_ANCHOR_MIDDLE: + default: + pos = bbox->midpoint(); + alignment = ""; + break; + } + + // get rotation + Geom::Matrix wotransl = i2doc.without_translation(); + double degrees = -180/M_PI * Geom::atan2(wotransl.xAxis()); + bool has_rotation = !Geom::are_near(degrees,0.); + + pop_transform(); + + // write to LaTeX + Inkscape::SVGOStringStream os; + +// os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){\\makebox(0,0)[" << alignment << "]{\\strut{}" << str << "}}%%\n"; + os << " \\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){"; + os << "\\makebox(0,0)" << alignment << "{"; + if (has_rotation) { + os << "\\rotatebox{" << degrees << "}{"; + } + os << str; + if (has_rotation) { + os << "}"; // rotatebox end + } + os << "}"; //makebox end + os << "}%\n"; // put end + + fprintf(_stream, "%s", os.str().c_str()); +} + +void +LaTeXTextRenderer::sp_flowtext_render(SPItem *item) +{ +/* SPFlowtext *group = SP_FLOWTEXT(item); + + // write to LaTeX + Inkscape::SVGOStringStream os; + + os << " \\begin{picture}(" << _width << "," << _height << ")%%\n"; + os << " \\gplgaddtomacro\\gplbacktext{%%\n"; + os << " \\csname LTb\\endcsname%%\n"; + os << "\\put(0,0){\\makebox(0,0)[lb]{\\strut{}Position}}%%\n"; + + fprintf(_stream, "%s", os.str().c_str()); +*/ +} + +void +LaTeXTextRenderer::sp_root_render(SPItem *item) +{ + SPRoot *root = SP_ROOT(item); + +// ctx->pushState(); +// setStateForItem(ctx, item); + Geom::Matrix tempmat (root->c2p); + push_transform(tempmat); + sp_group_render(item); + pop_transform(); +} + +void +LaTeXTextRenderer::sp_item_invoke_render(SPItem *item) +{ + // Check item's visibility + if (item->isHidden()) { + return; + } + + if (SP_IS_ROOT(item)) { + TRACE(("root\n")); + return sp_root_render(item); + } else if (SP_IS_GROUP(item)) { + TRACE(("group\n")); + return sp_group_render(item); + } else if (SP_IS_USE(item)) { + TRACE(("use begin---\n")); + sp_use_render(item); + TRACE(("---use end\n")); + } else if (SP_IS_TEXT(item)) { + TRACE(("text\n")); + return sp_text_render(item); + } else if (SP_IS_FLOWTEXT(item)) { + TRACE(("flowtext\n")); + return sp_flowtext_render(item); + } + // We are not interested in writing the other SPItem types to LaTeX +} + +void +LaTeXTextRenderer::setStateForItem(SPItem const *item) +{ +/* + SPStyle const *style = SP_OBJECT_STYLE(item); + ctx->setStateForStyle(style); + + CairoRenderState *state = ctx->getCurrentState(); + state->clip_path = item->clip_ref->getObject(); + state->mask = item->mask_ref->getObject(); + state->item_transform = Geom::Matrix (item->transform); + + // If parent_has_userspace is true the parent state's transform + // has to be used for the mask's/clippath's context. + // This is so because we use the image's/(flow)text's transform for positioning + // instead of explicitly specifying it and letting the renderer do the + // transformation before rendering the item. + if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item) || SP_IS_IMAGE(item)) + state->parent_has_userspace = TRUE; + TRACE(("setStateForItem opacity: %f\n", state->opacity)); +*/ +} + +void +LaTeXTextRenderer::renderItem(SPItem *item) +{ +// ctx->pushState(); +// setStateForItem(ctx, item); + +// CairoRenderState *state = ctx->getCurrentState(); +// state->need_layer = ( state->mask || state->clip_path || state->opacity != 1.0 ); + + // Draw item on a temporary surface so a mask, clip path, or opacity can be applied to it. +// if (state->need_layer) { +// state->merge_opacity = FALSE; +// ctx->pushLayer(); +// } + Geom::Matrix tempmat (item->transform); +// ctx->transform(&tempmat); + sp_item_invoke_render(item); + +// if (state->need_layer) +// ctx->popLayer(); + +// ctx->popState(); +} + +bool +LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *base) +{ +// The boundingbox calculation here should be exactly the same as the one by CairoRenderer::setupDocument ! + + if (!base) + base = SP_ITEM(sp_document_root(doc)); + + NRRect d; + if (pageBoundingBox) { + d.x0 = d.y0 = 0; + d.x1 = ceil(sp_document_width(doc)); + d.y1 = ceil(sp_document_height(doc)); + } else { + sp_item_invoke_bbox(base, &d, sp_item_i2d_affine(base), TRUE, SPItem::RENDERING_BBOX); + } + + // scale all coordinates, such that the width of the image is 1, this is convenient for scaling the image in LaTeX + double scale = 1/(d.x1-d.x0); + _width = (d.x1-d.x0) * scale; + _height = (d.y1-d.y0) * scale; + push_transform( Geom::Scale(scale, scale) ); + + if (!pageBoundingBox) + { + double high = sp_document_height(doc); + + push_transform( Geom::Translate( -d.x0, + -d.y0 ) ); + } + + // flip y-axis + push_transform( Geom::Scale(1,-1) * Geom::Translate(0, sp_document_height(doc)) ); + + // write the info to LaTeX + Inkscape::SVGOStringStream os; + + os << " \\begin{picture}(" << _width << "," << _height << ")%\n"; + // strip pathname, as it is probably desired. Having a specific path in the TeX file is not convenient. + os << " \\put(0,0){\\includegraphics[width=\\unitlength]{" << _filename << "}}%\n"; + + fprintf(_stream, "%s", os.str().c_str()); + + return true; +} + +Geom::Matrix const & +LaTeXTextRenderer::transform() +{ + return _transform_stack.top(); +} + +void +LaTeXTextRenderer::push_transform(Geom::Matrix const &tr) +{ + if(_transform_stack.size()){ + Geom::Matrix tr_top = _transform_stack.top(); + _transform_stack.push(tr * tr_top); + } else { + _transform_stack.push(tr); + } +} + +void +LaTeXTextRenderer::pop_transform() +{ + _transform_stack.pop(); +} + +/* +#include "macros.h" // SP_PRINT_* + +// Apply an SVG clip path +void +LaTeXTextRenderer::applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp) +{ + g_assert( ctx != NULL && ctx->_is_valid ); + + if (cp == NULL) + return; + + CairoRenderContext::CairoRenderMode saved_mode = ctx->getRenderMode(); + ctx->setRenderMode(CairoRenderContext::RENDER_MODE_CLIP); + + Geom::Matrix saved_ctm; + if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { + //SP_PRINT_DRECT("clipd", cp->display->bbox); + NRRect clip_bbox(cp->display->bbox); + Geom::Matrix t(Geom::Scale(clip_bbox.x1 - clip_bbox.x0, clip_bbox.y1 - clip_bbox.y0)); + t[4] = clip_bbox.x0; + t[5] = clip_bbox.y0; + t *= ctx->getCurrentState()->transform; + ctx->getTransform(&saved_ctm); + ctx->setTransform(&t); + } + + TRACE(("BEGIN clip\n")); + SPObject *co = SP_OBJECT(cp); + for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + if (SP_IS_ITEM(child)) { + SPItem *item = SP_ITEM(child); + + // combine transform of the item in clippath and the item using clippath: + Geom::Matrix tempmat (item->transform); + tempmat = tempmat * (ctx->getCurrentState()->item_transform); + + // render this item in clippath + ctx->pushState(); + ctx->transform(&tempmat); + setStateForItem(ctx, item); + sp_item_invoke_render(item, ctx); + ctx->popState(); + } + } + TRACE(("END clip\n")); + + // do clipping only if this was the first call to applyClipPath + if (ctx->getClipMode() == CairoRenderContext::CLIP_MODE_PATH + && saved_mode == CairoRenderContext::RENDER_MODE_NORMAL) + cairo_clip(ctx->_cr); + + if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) + ctx->setTransform(&saved_ctm); + + ctx->setRenderMode(saved_mode); +} + +// Apply an SVG mask +void +LaTeXTextRenderer::applyMask(CairoRenderContext *ctx, SPMask const *mask) +{ + g_assert( ctx != NULL && ctx->_is_valid ); + + if (mask == NULL) + return; + + //SP_PRINT_DRECT("maskd", &mask->display->bbox); + NRRect mask_bbox(mask->display->bbox); + // TODO: should the bbox be transformed if maskUnits != userSpaceOnUse ? + if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { + Geom::Matrix t(Geom::Scale(mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0)); + t[4] = mask_bbox.x0; + t[5] = mask_bbox.y0; + t *= ctx->getCurrentState()->transform; + ctx->setTransform(&t); + } + + // Clip mask contents... but... + // The mask's bounding box is the "geometric bounding box" which doesn't allow for + // filters which extend outside the bounding box. So don't clip. + // ctx->addClippingRect(mask_bbox.x0, mask_bbox.y0, mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0); + + ctx->pushState(); + + TRACE(("BEGIN mask\n")); + SPObject *co = SP_OBJECT(mask); + for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + if (SP_IS_ITEM(child)) { + SPItem *item = SP_ITEM(child); + renderItem(ctx, item); + } + } + TRACE(("END mask\n")); + + ctx->popState(); +} +*/ + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + +#undef TRACE + +/* End of GNU GPL code */ + +/* + 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 : diff --git a/src/extension/internal/latex-text-renderer.h b/src/extension/internal/latex-text-renderer.h new file mode 100644 index 000000000..a3c419015 --- /dev/null +++ b/src/extension/internal/latex-text-renderer.h @@ -0,0 +1,97 @@ +#ifndef EXTENSION_INTERNAL_PDF_LATEX_RENDERER_H_SEEN +#define EXTENSION_INTERNAL_PDF_LATEX_RENDERER_H_SEEN + +/** \file + * Declaration of LaTeXTextRenderer, used for rendering the accompanying LaTeX file when saving PDF output + LaTeX + */ +/* + * Authors: + * Johan Engelen + * + * Copyright (C) 2010 Authors + * + * Licensed under GNU GPL + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "extension/extension.h" +#include +#include + +#include "style.h" + +#include + +#include <2geom/matrix.h> +#include + +class SPClipPath; +class SPMask; +class SPItem; + +namespace Inkscape { +namespace Extension { +namespace Internal { + +bool latex_render_document_text_to_file(SPDocument *doc, gchar const *filename, const gchar * const exportId, bool exportDrawing, bool exportCanvas); + +class LaTeXTextRenderer { +public: + LaTeXTextRenderer(); + virtual ~LaTeXTextRenderer(); + + bool setTargetFile(gchar const *filename); + + void setStateForItem(SPItem const *item); + +// void applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp); +// void applyMask(CairoRenderContext *ctx, SPMask const *mask); + + /** Initializes the LaTeXTextRenderer according to the specified + SPDocument. Important to set the boundingbox to the pdf boundingbox */ + bool setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *base); + + /** Traverses the object tree and invokes the render methods. */ + void renderItem(SPItem *item); + +protected: + FILE * _stream; + gchar * _filename; + + void push_transform(Geom::Matrix const &transform); + Geom::Matrix const & transform(); + void pop_transform(); + std::stack _transform_stack; + double _width; + double _height; + + void writePreamble(); + void writePostamble(); + + void sp_item_invoke_render(SPItem *item); + void sp_root_render(SPItem *item); + void sp_group_render(SPItem *item); + void sp_use_render(SPItem *item); + void sp_text_render(SPItem *item); + void sp_flowtext_render(SPItem *item); +}; + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + +#endif /* !EXTENSION_INTERNAL_CAIRO_RENDERER_H_SEEN */ + +/* + 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 : diff --git a/src/extension/internal/pdflatex-renderer.cpp b/src/extension/internal/pdflatex-renderer.cpp deleted file mode 100644 index b70bac107..000000000 --- a/src/extension/internal/pdflatex-renderer.cpp +++ /dev/null @@ -1,609 +0,0 @@ -#define EXTENSION_INTERNAL_PDF_LATEX_RENDERER_CPP - -/** \file - * Rendering LaTeX file (pdf+latex output) - * - * The idea stems from GNUPlot's epslatex terminal output :-) - */ -/* - * Authors: - * Johan Engelen - * Miklos Erdelyi - * - * Copyright (C) 2006-2010 Authors - * - * Licensed under GNU GPL - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifndef PANGO_ENABLE_BACKEND -#define PANGO_ENABLE_BACKEND -#endif - -#ifndef PANGO_ENABLE_ENGINE -#define PANGO_ENABLE_ENGINE -#endif - - -#include -#include - -#include "libnr/nr-rect.h" -#include "libnrtype/Layout-TNG.h" -#include <2geom/transforms.h> -#include <2geom/pathvector.h> - -#include - -#include -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" -#include "display/nr-arena-group.h" -#include "display/curve.h" -#include "display/canvas-bpath.h" -#include "sp-item.h" -#include "sp-item-group.h" -#include "style.h" -#include "marker.h" -#include "sp-linear-gradient.h" -#include "sp-radial-gradient.h" -#include "sp-root.h" -#include "sp-use.h" -#include "sp-text.h" -#include "sp-flowtext.h" -#include "sp-mask.h" -#include "sp-clippath.h" -#include "text-editing.h" - -#include -#include "helper/png-write.h" -#include "helper/pixbuf-ops.h" - -#include "pdflatex-renderer.h" -#include "extension/system.h" - -#include "io/sys.h" - -#include - -// include support for only the compiled-in surface types -#ifdef CAIRO_HAS_PDF_SURFACE -#include -#endif -#ifdef CAIRO_HAS_PS_SURFACE -#include -#endif - -//#define TRACE(_args) g_message(_args) -#define TRACE(_args) -//#define TEST(_args) _args -#define TEST(_args) - -// FIXME: expose these from sp-clippath/mask.cpp -struct SPClipPathView { - SPClipPathView *next; - unsigned int key; - NRArenaItem *arenaitem; - NRRect bbox; -}; - -struct SPMaskView { - SPMaskView *next; - unsigned int key; - NRArenaItem *arenaitem; - NRRect bbox; -}; - -namespace Inkscape { -namespace Extension { -namespace Internal { - - -PDFLaTeXRenderer::PDFLaTeXRenderer(void) - : _stream(NULL), - _filename(NULL), - _width(0), - _height(0) -{ - push_transform(Geom::identity()); -} - -PDFLaTeXRenderer::~PDFLaTeXRenderer(void) -{ - if (_stream) { - writePostamble(); - - fclose(_stream); - } - - /* restore default signal handling for SIGPIPE */ -#if !defined(_WIN32) && !defined(__WIN32__) - (void) signal(SIGPIPE, SIG_DFL); -#endif - - if (_filename) { - g_free(_filename); - } - - return; -} - -/** This should create the output LaTeX file, and assign it to _stream. - * @return Returns true when succesfull - */ -bool -PDFLaTeXRenderer::setTargetFile(gchar const *filename) { - if (filename != NULL) { - while (isspace(*filename)) filename += 1; - - _filename = g_strdup(filename); - - gchar *filename_ext = g_strdup_printf("%s.tex", filename); - Inkscape::IO::dump_fopen_call(filename_ext, "K"); - FILE *osf = Inkscape::IO::fopen_utf8name(filename_ext, "w+"); - if (!osf) { - fprintf(stderr, "inkscape: fopen(%s): %s\n", - filename_ext, strerror(errno)); - return false; - } - _stream = osf; - g_free(filename_ext); - } - - if (_stream) { - /* fixme: this is kinda icky */ -#if !defined(_WIN32) && !defined(__WIN32__) - (void) signal(SIGPIPE, SIG_IGN); -#endif - } - - fprintf(_stream, "%%%% Creator: Inkscape %s, www.inkscape.org\n", PACKAGE_STRING); - fprintf(_stream, "%%%% PDF + LaTeX output extension by Johan Engelen, 2010\n"); - fprintf(_stream, "%%%% Accompanies %s.pdf\n", _filename); - /* flush this to test output stream as early as possible */ - if (fflush(_stream)) { - if (ferror(_stream)) { - g_print("Error %d on LaTeX file output stream: %s\n", errno, - g_strerror(errno)); - } - g_print("Output to LaTeX file failed\n"); - /* fixme: should use pclose() for pipes */ - fclose(_stream); - _stream = NULL; - fflush(stdout); - return false; - } - - writePreamble(); - - return true; -} - -static char const preamble[] = -"%% To include the image in your LaTeX document, write\n" -"%% \\setlength{\\unitlength}{}\n" -"%% \\input{.tex}\n" -"%% instead of\n" -"%% \\includegraphics[width=]{.pdf}\n" -"\n" -"\\begingroup \n" -" \\makeatletter \n" -" \\providecommand\\color[2][]{% \n" -" \\GenericError{(Inkscape) \\space\\space\\@spaces}{% \n" -" Color is used for the text in Inkscape, but the color package color is not loaded. \n" -" }{Either use black text in Inkscape or load the package \n" -" color.sty in LaTeX.}% \n" -" \\renewcommand\\color[2][]{}% \n" -" }%% \n" -" \\providecommand\\rotatebox[2]{#2}% \n" -" \\makeatother \n"; - -static char const postamble[] = -" \\end{picture}% \n" -"\\endgroup \n"; - -void -PDFLaTeXRenderer::writePreamble() -{ - fprintf(_stream, "%s", preamble); -} -void -PDFLaTeXRenderer::writePostamble() -{ - fprintf(_stream, "%s", postamble); -} - -void -PDFLaTeXRenderer::sp_group_render(SPItem *item) -{ - SPGroup *group = SP_GROUP(item); - - GSList *l = g_slist_reverse(group->childList(false)); - while (l) { - SPObject *o = SP_OBJECT (l->data); - if (SP_IS_ITEM(o)) { - renderItem (SP_ITEM (o)); - } - l = g_slist_remove (l, o); - } -} - -void -PDFLaTeXRenderer::sp_use_render(SPItem *item) -{ -/* - bool translated = false; - SPUse *use = SP_USE(item); - - if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) { - Geom::Matrix tp(Geom::Translate(use->x.computed, use->y.computed)); - ctx->pushState(); - ctx->transform(&tp); - translated = true; - } - - if (use->child && SP_IS_ITEM(use->child)) { - renderItem(SP_ITEM(use->child)); - } - - if (translated) { - ctx->popState(); - } -*/ -} - -void -PDFLaTeXRenderer::sp_text_render(SPItem *item) -{ - SPText *textobj = SP_TEXT (item); - - Geom::Matrix i2doc = sp_item_i2doc_affine(item); - push_transform(i2doc); - - gchar *str = sp_te_get_string_multiline(item); - - // get position and alignment - Geom::Point pos; - gchar *alignment = NULL; - Geom::OptRect bbox = item->getBounds(transform()); - Geom::Interval bbox_x = (*bbox)[Geom::X]; - Geom::Interval bbox_y = (*bbox)[Geom::Y]; - SPStyle *style = SP_OBJECT_STYLE (SP_OBJECT(item)); - switch (style->text_anchor.computed) { - case SP_CSS_TEXT_ANCHOR_START: - pos = Geom::Point( bbox_x.min() , bbox_y.middle() ); - alignment = "[l]"; - break; - case SP_CSS_TEXT_ANCHOR_END: - pos = Geom::Point( bbox_x.max() , bbox_y.middle() ); - alignment = "[r]"; - break; - case SP_CSS_TEXT_ANCHOR_MIDDLE: - default: - pos = bbox->midpoint(); - alignment = ""; - break; - } - - // get rotation - Geom::Matrix wotransl = i2doc.without_translation(); - double degrees = -180/M_PI * Geom::atan2(wotransl.xAxis()); - bool has_rotation = !Geom::are_near(degrees,0.); - - pop_transform(); - - // write to LaTeX - Inkscape::SVGOStringStream os; - -// os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){\\makebox(0,0)[" << alignment << "]{\\strut{}" << str << "}}%%\n"; - os << " \\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){"; - os << "\\makebox(0,0)" << alignment << "{"; - if (has_rotation) { - os << "\\rotatebox{" << degrees << "}{"; - } - os << str; - if (has_rotation) { - os << "}"; // rotatebox end - } - os << "}"; //makebox end - os << "}%\n"; // put end - - fprintf(_stream, "%s", os.str().c_str()); -} - -void -PDFLaTeXRenderer::sp_flowtext_render(SPItem *item) -{ -/* SPFlowtext *group = SP_FLOWTEXT(item); - - // write to LaTeX - Inkscape::SVGOStringStream os; - - os << " \\begin{picture}(" << _width << "," << _height << ")%%\n"; - os << " \\gplgaddtomacro\\gplbacktext{%%\n"; - os << " \\csname LTb\\endcsname%%\n"; - os << "\\put(0,0){\\makebox(0,0)[lb]{\\strut{}Position}}%%\n"; - - fprintf(_stream, "%s", os.str().c_str()); -*/ -} - -void -PDFLaTeXRenderer::sp_root_render(SPItem *item) -{ - SPRoot *root = SP_ROOT(item); - -// ctx->pushState(); -// setStateForItem(ctx, item); - Geom::Matrix tempmat (root->c2p); - push_transform(tempmat); - sp_group_render(item); - pop_transform(); -} - -void -PDFLaTeXRenderer::sp_item_invoke_render(SPItem *item) -{ - // Check item's visibility - if (item->isHidden()) { - return; - } - - if (SP_IS_ROOT(item)) { - TRACE(("root\n")); - return sp_root_render(item); - } else if (SP_IS_GROUP(item)) { - TRACE(("group\n")); - return sp_group_render(item); - } else if (SP_IS_USE(item)) { - TRACE(("use begin---\n")); - sp_use_render(item); - TRACE(("---use end\n")); - } else if (SP_IS_TEXT(item)) { - TRACE(("text\n")); - return sp_text_render(item); - } else if (SP_IS_FLOWTEXT(item)) { - TRACE(("flowtext\n")); - return sp_flowtext_render(item); - } - // We are not interested in writing the other SPItem types to LaTeX -} - -void -PDFLaTeXRenderer::setStateForItem(SPItem const *item) -{ -/* - SPStyle const *style = SP_OBJECT_STYLE(item); - ctx->setStateForStyle(style); - - CairoRenderState *state = ctx->getCurrentState(); - state->clip_path = item->clip_ref->getObject(); - state->mask = item->mask_ref->getObject(); - state->item_transform = Geom::Matrix (item->transform); - - // If parent_has_userspace is true the parent state's transform - // has to be used for the mask's/clippath's context. - // This is so because we use the image's/(flow)text's transform for positioning - // instead of explicitly specifying it and letting the renderer do the - // transformation before rendering the item. - if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item) || SP_IS_IMAGE(item)) - state->parent_has_userspace = TRUE; - TRACE(("setStateForItem opacity: %f\n", state->opacity)); -*/ -} - -void -PDFLaTeXRenderer::renderItem(SPItem *item) -{ -// ctx->pushState(); -// setStateForItem(ctx, item); - -// CairoRenderState *state = ctx->getCurrentState(); -// state->need_layer = ( state->mask || state->clip_path || state->opacity != 1.0 ); - - // Draw item on a temporary surface so a mask, clip path, or opacity can be applied to it. -// if (state->need_layer) { -// state->merge_opacity = FALSE; -// ctx->pushLayer(); -// } - Geom::Matrix tempmat (item->transform); -// ctx->transform(&tempmat); - sp_item_invoke_render(item); - -// if (state->need_layer) -// ctx->popLayer(); - -// ctx->popState(); -} - -bool -PDFLaTeXRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *base) -{ -// The boundingbox calculation here should be exactly the same as the one by CairoRenderer::setupDocument ! - - if (!base) - base = SP_ITEM(sp_document_root(doc)); - - NRRect d; - if (pageBoundingBox) { - d.x0 = d.y0 = 0; - d.x1 = ceil(sp_document_width(doc)); - d.y1 = ceil(sp_document_height(doc)); - } else { - sp_item_invoke_bbox(base, &d, sp_item_i2d_affine(base), TRUE, SPItem::RENDERING_BBOX); - } - - // scale all coordinates, such that the width of the image is 1, this is convenient for scaling the image in LaTeX - double scale = 1/(d.x1-d.x0); - _width = (d.x1-d.x0) * scale; - _height = (d.y1-d.y0) * scale; - push_transform( Geom::Scale(scale, scale) ); - - if (!pageBoundingBox) - { - double high = sp_document_height(doc); - - push_transform( Geom::Translate( -d.x0, - -d.y0 ) ); - } - - // flip y-axis - push_transform( Geom::Scale(1,-1) * Geom::Translate(0, sp_document_height(doc)) ); - - // write the info to LaTeX - Inkscape::SVGOStringStream os; - - os << " \\begin{picture}(" << _width << "," << _height << ")%\n"; - // strip pathname, as it is probably desired. Having a specific path in the TeX file is not convenient. - gchar *figurefile = g_path_get_basename(_filename); - os << " \\put(0,0){\\includegraphics[width=\\unitlength]{" << figurefile << ".pdf}}%\n"; - g_free(figurefile); - - fprintf(_stream, "%s", os.str().c_str()); - - return true; -} - -Geom::Matrix const & -PDFLaTeXRenderer::transform() -{ - return _transform_stack.top(); -} - -void -PDFLaTeXRenderer::push_transform(Geom::Matrix const &tr) -{ - if(_transform_stack.size()){ - Geom::Matrix tr_top = _transform_stack.top(); - _transform_stack.push(tr * tr_top); - } else { - _transform_stack.push(tr); - } -} - -void -PDFLaTeXRenderer::pop_transform() -{ - _transform_stack.pop(); -} - -/* -#include "macros.h" // SP_PRINT_* - -// Apply an SVG clip path -void -PDFLaTeXRenderer::applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp) -{ - g_assert( ctx != NULL && ctx->_is_valid ); - - if (cp == NULL) - return; - - CairoRenderContext::CairoRenderMode saved_mode = ctx->getRenderMode(); - ctx->setRenderMode(CairoRenderContext::RENDER_MODE_CLIP); - - Geom::Matrix saved_ctm; - if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { - //SP_PRINT_DRECT("clipd", cp->display->bbox); - NRRect clip_bbox(cp->display->bbox); - Geom::Matrix t(Geom::Scale(clip_bbox.x1 - clip_bbox.x0, clip_bbox.y1 - clip_bbox.y0)); - t[4] = clip_bbox.x0; - t[5] = clip_bbox.y0; - t *= ctx->getCurrentState()->transform; - ctx->getTransform(&saved_ctm); - ctx->setTransform(&t); - } - - TRACE(("BEGIN clip\n")); - SPObject *co = SP_OBJECT(cp); - for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { - if (SP_IS_ITEM(child)) { - SPItem *item = SP_ITEM(child); - - // combine transform of the item in clippath and the item using clippath: - Geom::Matrix tempmat (item->transform); - tempmat = tempmat * (ctx->getCurrentState()->item_transform); - - // render this item in clippath - ctx->pushState(); - ctx->transform(&tempmat); - setStateForItem(ctx, item); - sp_item_invoke_render(item, ctx); - ctx->popState(); - } - } - TRACE(("END clip\n")); - - // do clipping only if this was the first call to applyClipPath - if (ctx->getClipMode() == CairoRenderContext::CLIP_MODE_PATH - && saved_mode == CairoRenderContext::RENDER_MODE_NORMAL) - cairo_clip(ctx->_cr); - - if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) - ctx->setTransform(&saved_ctm); - - ctx->setRenderMode(saved_mode); -} - -// Apply an SVG mask -void -PDFLaTeXRenderer::applyMask(CairoRenderContext *ctx, SPMask const *mask) -{ - g_assert( ctx != NULL && ctx->_is_valid ); - - if (mask == NULL) - return; - - //SP_PRINT_DRECT("maskd", &mask->display->bbox); - NRRect mask_bbox(mask->display->bbox); - // TODO: should the bbox be transformed if maskUnits != userSpaceOnUse ? - if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Matrix t(Geom::Scale(mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0)); - t[4] = mask_bbox.x0; - t[5] = mask_bbox.y0; - t *= ctx->getCurrentState()->transform; - ctx->setTransform(&t); - } - - // Clip mask contents... but... - // The mask's bounding box is the "geometric bounding box" which doesn't allow for - // filters which extend outside the bounding box. So don't clip. - // ctx->addClippingRect(mask_bbox.x0, mask_bbox.y0, mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0); - - ctx->pushState(); - - TRACE(("BEGIN mask\n")); - SPObject *co = SP_OBJECT(mask); - for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { - if (SP_IS_ITEM(child)) { - SPItem *item = SP_ITEM(child); - renderItem(ctx, item); - } - } - TRACE(("END mask\n")); - - ctx->popState(); -} -*/ - -} /* namespace Internal */ -} /* namespace Extension */ -} /* namespace Inkscape */ - -#undef TRACE - -/* End of GNU GPL code */ - -/* - 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 : diff --git a/src/extension/internal/pdflatex-renderer.h b/src/extension/internal/pdflatex-renderer.h deleted file mode 100644 index 93c06b114..000000000 --- a/src/extension/internal/pdflatex-renderer.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef EXTENSION_INTERNAL_PDF_LATEX_RENDERER_H_SEEN -#define EXTENSION_INTERNAL_PDF_LATEX_RENDERER_H_SEEN - -/** \file - * Declaration of PDFLaTeXRenderer, used for rendering the accompanying LaTeX file when saving PDF output + LaTeX - */ -/* - * Authors: - * Johan Engelen - * - * Copyright (C) 2010 Authors - * - * Licensed under GNU GPL - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "extension/extension.h" -#include -#include - -#include "style.h" - -#include - -#include <2geom/matrix.h> -#include - -class SPClipPath; -class SPMask; -class SPItem; - -namespace Inkscape { -namespace Extension { -namespace Internal { - -class PDFLaTeXRenderer { -public: - PDFLaTeXRenderer(); - virtual ~PDFLaTeXRenderer(); - - bool setTargetFile(gchar const *filename); - - void setStateForItem(SPItem const *item); - -// void applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp); -// void applyMask(CairoRenderContext *ctx, SPMask const *mask); - - /** Initializes the PDFLaTeXRenderer according to the specified - SPDocument. Important to set the boundingbox to the pdf boundingbox */ - bool setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *base); - - /** Traverses the object tree and invokes the render methods. */ - void renderItem(SPItem *item); - -protected: - FILE * _stream; - gchar * _filename; - - void push_transform(Geom::Matrix const &transform); - Geom::Matrix const & transform(); - void pop_transform(); - std::stack _transform_stack; - double _width; - double _height; - - void writePreamble(); - void writePostamble(); - - void sp_item_invoke_render(SPItem *item); - void sp_root_render(SPItem *item); - void sp_group_render(SPItem *item); - void sp_use_render(SPItem *item); - void sp_text_render(SPItem *item); - void sp_flowtext_render(SPItem *item); -}; - -} /* namespace Internal */ -} /* namespace Extension */ -} /* namespace Inkscape */ - -#endif /* !EXTENSION_INTERNAL_CAIRO_RENDERER_H_SEEN */ - -/* - 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 : diff --git a/src/main.cpp b/src/main.cpp index 6b87df194..4bb5dfdc1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -143,7 +143,7 @@ enum { SP_ARG_EXPORT_PS, SP_ARG_EXPORT_EPS, SP_ARG_EXPORT_PDF, - SP_ARG_EXPORT_PDF_LATEX, + SP_ARG_EXPORT_LATEX, #ifdef WIN32 SP_ARG_EXPORT_EMF, #endif //WIN32 @@ -182,7 +182,7 @@ static gchar *sp_export_dpi = NULL; static gchar *sp_export_area = NULL; static gboolean sp_export_area_drawing = FALSE; static gboolean sp_export_area_page = FALSE; -static gboolean sp_export_pdf_latex = FALSE; +static gboolean sp_export_latex = FALSE; static gchar *sp_export_width = NULL; static gchar *sp_export_height = NULL; static gchar *sp_export_id = NULL; @@ -226,7 +226,7 @@ static void resetCommandlineGlobals() { sp_export_area = NULL; sp_export_area_drawing = FALSE; sp_export_area_page = FALSE; - sp_export_pdf_latex = FALSE; + sp_export_latex = FALSE; sp_export_width = NULL; sp_export_height = NULL; sp_export_id = NULL; @@ -375,9 +375,9 @@ struct poptOption options[] = { N_("Export document to a PDF file"), N_("FILENAME")}, - {"export-pdf-latex", 0, - POPT_ARG_NONE, &sp_export_pdf_latex, SP_ARG_EXPORT_PDF_LATEX, - N_("Export PDF without text. Besides the PDF, a LaTeX file is exported, putting the text on top of the PDF file. Include the result in LaTeX like: \\input{latexfile.tex}"), + {"export-latex", 0, + POPT_ARG_NONE, &sp_export_latex, SP_ARG_EXPORT_LATEX, + N_("Export PDF/PS/EPS without text. Besides the PDF/PS/EPS, a LaTeX file is exported, putting the text on top of the PDF/PS/EPS file. Include the result in LaTeX like: \\input{latexfile.tex}"), NULL}, #ifdef WIN32 @@ -654,7 +654,7 @@ main(int argc, char **argv) || !strncmp(argv[i], "--export-eps", 12) || !strcmp(argv[i], "-A") || !strncmp(argv[i], "--export-pdf", 12) - || !strncmp(argv[i], "--export-pdf-latex", 18) + || !strncmp(argv[i], "--export-latex", 14) #ifdef WIN32 || !strcmp(argv[i], "-M") || !strncmp(argv[i], "--export-emf", 12) @@ -1527,7 +1527,7 @@ static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime (*i)->set_param_bool("textToPath", FALSE); } - if (sp_export_pdf_latex) { + if (sp_export_latex) { (*i)->set_param_bool("textToLaTeX", TRUE); } else { (*i)->set_param_bool("textToLaTeX", FALSE); -- cgit v1.2.3 From 3c2f9385f7e3fa38fcd785d989edd90a167b1f8a Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 22 Feb 2010 21:17:55 +0100 Subject: clean up code (bzr r9101.1.14) --- src/extension/internal/latex-text-renderer.cpp | 231 ++----------------------- src/extension/internal/latex-text-renderer.h | 24 +-- 2 files changed, 15 insertions(+), 240 deletions(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 83bb7c52d..159595a6d 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -1,7 +1,7 @@ -#define EXTENSION_INTERNAL_PDF_LATEX_RENDERER_CPP +#define EXTENSION_INTERNAL_LATEX_TEXT_RENDERER_CPP /** \file - * Rendering LaTeX file (pdf+latex output) + * Rendering LaTeX file (pdf/eps/ps+latex output) * * The idea stems from GNUPlot's epslatex terminal output :-) */ @@ -19,85 +19,30 @@ # include "config.h" #endif -#ifndef PANGO_ENABLE_BACKEND -#define PANGO_ENABLE_BACKEND -#endif - -#ifndef PANGO_ENABLE_ENGINE -#define PANGO_ENABLE_ENGINE -#endif - +#include "latex-text-renderer.h" #include #include -#include "libnr/nr-rect.h" #include "libnrtype/Layout-TNG.h" #include <2geom/transforms.h> -#include <2geom/pathvector.h> - -#include #include -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" -#include "display/nr-arena-group.h" -#include "display/curve.h" -#include "display/canvas-bpath.h" #include "sp-item.h" #include "sp-item-group.h" #include "style.h" -#include "marker.h" -#include "sp-linear-gradient.h" -#include "sp-radial-gradient.h" #include "sp-root.h" #include "sp-use.h" #include "sp-text.h" #include "sp-flowtext.h" -#include "sp-mask.h" -#include "sp-clippath.h" #include "text-editing.h" #include -#include "helper/png-write.h" -#include "helper/pixbuf-ops.h" -#include "latex-text-renderer.h" #include "extension/system.h" #include "io/sys.h" -#include - -// include support for only the compiled-in surface types -#ifdef CAIRO_HAS_PDF_SURFACE -#include -#endif -#ifdef CAIRO_HAS_PS_SURFACE -#include -#endif - -//#define TRACE(_args) g_message(_args) -#define TRACE(_args) -//#define TEST(_args) _args -#define TEST(_args) - -// FIXME: expose these from sp-clippath/mask.cpp -struct SPClipPathView { - SPClipPathView *next; - unsigned int key; - NRArenaItem *arenaitem; - NRRect bbox; -}; - -struct SPMaskView { - SPMaskView *next; - unsigned int key; - NRArenaItem *arenaitem; - NRRect bbox; -}; - - namespace Inkscape { namespace Extension { namespace Internal { @@ -144,9 +89,7 @@ latex_render_document_text_to_file( SPDocument *doc, gchar const *filename, LaTeXTextRenderer::LaTeXTextRenderer(void) : _stream(NULL), - _filename(NULL), - _width(0), - _height(0) + _filename(NULL) { push_transform(Geom::identity()); } @@ -281,8 +224,7 @@ LaTeXTextRenderer::sp_use_render(SPItem *item) if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) { Geom::Matrix tp(Geom::Translate(use->x.computed, use->y.computed)); - ctx->pushState(); - ctx->transform(&tp); + push_transform(tp); translated = true; } @@ -291,7 +233,7 @@ LaTeXTextRenderer::sp_use_render(SPItem *item) } if (translated) { - ctx->popState(); + pop_transform(); } */ } @@ -339,7 +281,6 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) // write to LaTeX Inkscape::SVGOStringStream os; -// os << "\\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){\\makebox(0,0)[" << alignment << "]{\\strut{}" << str << "}}%%\n"; os << " \\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){"; os << "\\makebox(0,0)" << alignment << "{"; if (has_rotation) { @@ -377,8 +318,6 @@ LaTeXTextRenderer::sp_root_render(SPItem *item) { SPRoot *root = SP_ROOT(item); -// ctx->pushState(); -// setStateForItem(ctx, item); Geom::Matrix tempmat (root->c2p); push_transform(tempmat); sp_group_render(item); @@ -394,70 +333,26 @@ LaTeXTextRenderer::sp_item_invoke_render(SPItem *item) } if (SP_IS_ROOT(item)) { - TRACE(("root\n")); return sp_root_render(item); } else if (SP_IS_GROUP(item)) { - TRACE(("group\n")); return sp_group_render(item); } else if (SP_IS_USE(item)) { - TRACE(("use begin---\n")); sp_use_render(item); - TRACE(("---use end\n")); } else if (SP_IS_TEXT(item)) { - TRACE(("text\n")); return sp_text_render(item); } else if (SP_IS_FLOWTEXT(item)) { - TRACE(("flowtext\n")); return sp_flowtext_render(item); } // We are not interested in writing the other SPItem types to LaTeX } -void -LaTeXTextRenderer::setStateForItem(SPItem const *item) -{ -/* - SPStyle const *style = SP_OBJECT_STYLE(item); - ctx->setStateForStyle(style); - - CairoRenderState *state = ctx->getCurrentState(); - state->clip_path = item->clip_ref->getObject(); - state->mask = item->mask_ref->getObject(); - state->item_transform = Geom::Matrix (item->transform); - - // If parent_has_userspace is true the parent state's transform - // has to be used for the mask's/clippath's context. - // This is so because we use the image's/(flow)text's transform for positioning - // instead of explicitly specifying it and letting the renderer do the - // transformation before rendering the item. - if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item) || SP_IS_IMAGE(item)) - state->parent_has_userspace = TRUE; - TRACE(("setStateForItem opacity: %f\n", state->opacity)); -*/ -} - void LaTeXTextRenderer::renderItem(SPItem *item) { -// ctx->pushState(); -// setStateForItem(ctx, item); - -// CairoRenderState *state = ctx->getCurrentState(); -// state->need_layer = ( state->mask || state->clip_path || state->opacity != 1.0 ); - - // Draw item on a temporary surface so a mask, clip path, or opacity can be applied to it. -// if (state->need_layer) { -// state->merge_opacity = FALSE; -// ctx->pushLayer(); -// } - Geom::Matrix tempmat (item->transform); -// ctx->transform(&tempmat); +// push_transform(item->transform); sp_item_invoke_render(item); -// if (state->need_layer) -// ctx->popLayer(); - -// ctx->popState(); +// pop_transform(); } bool @@ -479,16 +374,15 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem * // scale all coordinates, such that the width of the image is 1, this is convenient for scaling the image in LaTeX double scale = 1/(d.x1-d.x0); - _width = (d.x1-d.x0) * scale; - _height = (d.y1-d.y0) * scale; + double _width = (d.x1-d.x0) * scale; + double _height = (d.y1-d.y0) * scale; push_transform( Geom::Scale(scale, scale) ); if (!pageBoundingBox) { double high = sp_document_height(doc); - push_transform( Geom::Translate( -d.x0, - -d.y0 ) ); + push_transform( Geom::Translate(-d.x0, -d.y0) ); } // flip y-axis @@ -529,113 +423,10 @@ LaTeXTextRenderer::pop_transform() _transform_stack.pop(); } -/* -#include "macros.h" // SP_PRINT_* - -// Apply an SVG clip path -void -LaTeXTextRenderer::applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp) -{ - g_assert( ctx != NULL && ctx->_is_valid ); - - if (cp == NULL) - return; - - CairoRenderContext::CairoRenderMode saved_mode = ctx->getRenderMode(); - ctx->setRenderMode(CairoRenderContext::RENDER_MODE_CLIP); - - Geom::Matrix saved_ctm; - if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { - //SP_PRINT_DRECT("clipd", cp->display->bbox); - NRRect clip_bbox(cp->display->bbox); - Geom::Matrix t(Geom::Scale(clip_bbox.x1 - clip_bbox.x0, clip_bbox.y1 - clip_bbox.y0)); - t[4] = clip_bbox.x0; - t[5] = clip_bbox.y0; - t *= ctx->getCurrentState()->transform; - ctx->getTransform(&saved_ctm); - ctx->setTransform(&t); - } - - TRACE(("BEGIN clip\n")); - SPObject *co = SP_OBJECT(cp); - for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { - if (SP_IS_ITEM(child)) { - SPItem *item = SP_ITEM(child); - - // combine transform of the item in clippath and the item using clippath: - Geom::Matrix tempmat (item->transform); - tempmat = tempmat * (ctx->getCurrentState()->item_transform); - - // render this item in clippath - ctx->pushState(); - ctx->transform(&tempmat); - setStateForItem(ctx, item); - sp_item_invoke_render(item, ctx); - ctx->popState(); - } - } - TRACE(("END clip\n")); - - // do clipping only if this was the first call to applyClipPath - if (ctx->getClipMode() == CairoRenderContext::CLIP_MODE_PATH - && saved_mode == CairoRenderContext::RENDER_MODE_NORMAL) - cairo_clip(ctx->_cr); - - if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) - ctx->setTransform(&saved_ctm); - - ctx->setRenderMode(saved_mode); -} - -// Apply an SVG mask -void -LaTeXTextRenderer::applyMask(CairoRenderContext *ctx, SPMask const *mask) -{ - g_assert( ctx != NULL && ctx->_is_valid ); - - if (mask == NULL) - return; - - //SP_PRINT_DRECT("maskd", &mask->display->bbox); - NRRect mask_bbox(mask->display->bbox); - // TODO: should the bbox be transformed if maskUnits != userSpaceOnUse ? - if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Matrix t(Geom::Scale(mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0)); - t[4] = mask_bbox.x0; - t[5] = mask_bbox.y0; - t *= ctx->getCurrentState()->transform; - ctx->setTransform(&t); - } - - // Clip mask contents... but... - // The mask's bounding box is the "geometric bounding box" which doesn't allow for - // filters which extend outside the bounding box. So don't clip. - // ctx->addClippingRect(mask_bbox.x0, mask_bbox.y0, mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0); - - ctx->pushState(); - - TRACE(("BEGIN mask\n")); - SPObject *co = SP_OBJECT(mask); - for (SPObject *child = sp_object_first_child(co) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { - if (SP_IS_ITEM(child)) { - SPItem *item = SP_ITEM(child); - renderItem(ctx, item); - } - } - TRACE(("END mask\n")); - - ctx->popState(); -} -*/ - } /* namespace Internal */ } /* namespace Extension */ } /* namespace Inkscape */ -#undef TRACE - -/* End of GNU GPL code */ - /* Local Variables: mode:c++ diff --git a/src/extension/internal/latex-text-renderer.h b/src/extension/internal/latex-text-renderer.h index a3c419015..69f539314 100644 --- a/src/extension/internal/latex-text-renderer.h +++ b/src/extension/internal/latex-text-renderer.h @@ -1,8 +1,8 @@ -#ifndef EXTENSION_INTERNAL_PDF_LATEX_RENDERER_H_SEEN -#define EXTENSION_INTERNAL_PDF_LATEX_RENDERER_H_SEEN +#ifndef EXTENSION_INTERNAL_LATEX_TEXT_RENDERER_H_SEEN +#define EXTENSION_INTERNAL_LATEX_TEXT_RENDERER_H_SEEN /** \file - * Declaration of LaTeXTextRenderer, used for rendering the accompanying LaTeX file when saving PDF output + LaTeX + * Declaration of LaTeXTextRenderer, used for rendering the accompanying LaTeX file when exporting to PDF/EPS/PS + LaTeX */ /* * Authors: @@ -18,18 +18,9 @@ #endif #include "extension/extension.h" -#include -#include - -#include "style.h" - -#include - #include <2geom/matrix.h> #include -class SPClipPath; -class SPMask; class SPItem; namespace Inkscape { @@ -45,11 +36,6 @@ public: bool setTargetFile(gchar const *filename); - void setStateForItem(SPItem const *item); - -// void applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp); -// void applyMask(CairoRenderContext *ctx, SPMask const *mask); - /** Initializes the LaTeXTextRenderer according to the specified SPDocument. Important to set the boundingbox to the pdf boundingbox */ bool setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *base); @@ -65,8 +51,6 @@ protected: Geom::Matrix const & transform(); void pop_transform(); std::stack _transform_stack; - double _width; - double _height; void writePreamble(); void writePostamble(); @@ -83,7 +67,7 @@ protected: } /* namespace Extension */ } /* namespace Inkscape */ -#endif /* !EXTENSION_INTERNAL_CAIRO_RENDERER_H_SEEN */ +#endif /* !EXTENSION_INTERNAL_LATEX_TEXT_RENDERER_H_SEEN */ /* Local Variables: -- cgit v1.2.3 From ee162daf2703adeba5ffc58574c0a6eb356583e9 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 22 Feb 2010 21:39:08 +0100 Subject: - proper transformations handling - 2geomify some stuff (bzr r9101.1.15) --- src/extension/internal/latex-text-renderer.cpp | 36 ++++++++++++-------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 159595a6d..7290bda56 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -26,6 +26,7 @@ #include "libnrtype/Layout-TNG.h" #include <2geom/transforms.h> +#include <2geom/rect.h> #include #include "sp-item.h" @@ -47,6 +48,10 @@ namespace Inkscape { namespace Extension { namespace Internal { +/** + * This method is called by the PDF, EPS and PS output extensions. + * @param filename This should be the filename without extension to which the tex code should be written. Output goes to .tex. + */ bool latex_render_document_text_to_file( SPDocument *doc, gchar const *filename, const gchar * const exportId, bool exportDrawing, bool exportCanvas) @@ -243,9 +248,6 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) { SPText *textobj = SP_TEXT (item); - Geom::Matrix i2doc = sp_item_i2doc_affine(item); - push_transform(i2doc); - gchar *str = sp_te_get_string_multiline(item); // get position and alignment @@ -272,12 +274,11 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) } // get rotation + Geom::Matrix i2doc = sp_item_i2doc_affine(item); Geom::Matrix wotransl = i2doc.without_translation(); double degrees = -180/M_PI * Geom::atan2(wotransl.xAxis()); bool has_rotation = !Geom::are_near(degrees,0.); - pop_transform(); - // write to LaTeX Inkscape::SVGOStringStream os; @@ -318,8 +319,7 @@ LaTeXTextRenderer::sp_root_render(SPItem *item) { SPRoot *root = SP_ROOT(item); - Geom::Matrix tempmat (root->c2p); - push_transform(tempmat); + push_transform(root->c2p); sp_group_render(item); pop_transform(); } @@ -349,10 +349,9 @@ LaTeXTextRenderer::sp_item_invoke_render(SPItem *item) void LaTeXTextRenderer::renderItem(SPItem *item) { -// push_transform(item->transform); + push_transform(item->transform); sp_item_invoke_render(item); - -// pop_transform(); + pop_transform(); } bool @@ -363,26 +362,25 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem * if (!base) base = SP_ITEM(sp_document_root(doc)); - NRRect d; + Geom::OptRect d; if (pageBoundingBox) { - d.x0 = d.y0 = 0; - d.x1 = ceil(sp_document_width(doc)); - d.y1 = ceil(sp_document_height(doc)); + d = Geom::Rect( Geom::Point(0,0), + Geom::Point(sp_document_width(doc), sp_document_height(doc)) ); } else { - sp_item_invoke_bbox(base, &d, sp_item_i2d_affine(base), TRUE, SPItem::RENDERING_BBOX); + sp_item_invoke_bbox(base, d, sp_item_i2d_affine(base), TRUE, SPItem::RENDERING_BBOX); } // scale all coordinates, such that the width of the image is 1, this is convenient for scaling the image in LaTeX - double scale = 1/(d.x1-d.x0); - double _width = (d.x1-d.x0) * scale; - double _height = (d.y1-d.y0) * scale; + double scale = 1/(d->width()); + double _width = d->width() * scale; + double _height = d->height() * scale; push_transform( Geom::Scale(scale, scale) ); if (!pageBoundingBox) { double high = sp_document_height(doc); - push_transform( Geom::Translate(-d.x0, -d.y0) ); + push_transform( Geom::Translate( - d->min() ) ); } // flip y-axis -- cgit v1.2.3 From 5c391ba25dc2a08f6eeba290847c970e0a1a1433 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 22 Feb 2010 22:52:22 +0100 Subject: also output color to tex. ICC colors do not work yet. (bzr r9101.1.16) --- src/extension/internal/latex-text-renderer.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 7290bda56..e07b17fb8 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -247,6 +247,7 @@ void LaTeXTextRenderer::sp_text_render(SPItem *item) { SPText *textobj = SP_TEXT (item); + SPStyle *style = SP_OBJECT_STYLE (SP_OBJECT(item)); gchar *str = sp_te_get_string_multiline(item); @@ -256,7 +257,6 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) Geom::OptRect bbox = item->getBounds(transform()); Geom::Interval bbox_x = (*bbox)[Geom::X]; Geom::Interval bbox_y = (*bbox)[Geom::Y]; - SPStyle *style = SP_OBJECT_STYLE (SP_OBJECT(item)); switch (style->text_anchor.computed) { case SP_CSS_TEXT_ANCHOR_START: pos = Geom::Point( bbox_x.min() , bbox_y.middle() ); @@ -273,6 +273,20 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) break; } + // determine color (for now, use rgb color model as it is most native to Inkscape) + bool has_color = false; // if the item has no color set, don't force black color + // TODO: how to handle ICC colors? + // give priority to fill color + guint32 rgba = 0; + if (style->fill.set && style->fill.isColor()) { + has_color = true; + rgba = style->fill.value.color.toRGBA32(1.); + } else if (style->stroke.set && style->stroke.isColor()) { + has_color = true; + rgba = style->stroke.value.color.toRGBA32(1.); + } + + // get rotation Geom::Matrix i2doc = sp_item_i2doc_affine(item); Geom::Matrix wotransl = i2doc.without_translation(); @@ -283,6 +297,9 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) Inkscape::SVGOStringStream os; os << " \\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){"; + if (has_color) { + os << "\\color[rgb]{" << SP_RGBA32_R_F(rgba) << "," << SP_RGBA32_G_F(rgba) << "," << SP_RGBA32_B_F(rgba) << "}"; + } os << "\\makebox(0,0)" << alignment << "{"; if (has_rotation) { os << "\\rotatebox{" << degrees << "}{"; -- cgit v1.2.3 From 5ee3de5e8e6315a57cac1f34c9ceb5ef100c162a Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Wed, 24 Feb 2010 22:07:31 +0100 Subject: output clones to latex too (bzr r9101.1.17) --- src/extension/internal/latex-text-renderer.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index e07b17fb8..6c09a7396 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -223,7 +223,6 @@ LaTeXTextRenderer::sp_group_render(SPItem *item) void LaTeXTextRenderer::sp_use_render(SPItem *item) { -/* bool translated = false; SPUse *use = SP_USE(item); @@ -240,7 +239,6 @@ LaTeXTextRenderer::sp_use_render(SPItem *item) if (translated) { pop_transform(); } -*/ } void -- cgit v1.2.3 From 8d7774019aa0bd74ac3fbc194c907643a2c21cab Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Wed, 24 Feb 2010 22:19:52 +0100 Subject: add original width of picture to be able to *not* specify width in latex doc. still work to be done. (bzr r9101.1.18) --- src/extension/internal/latex-text-renderer.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 6c09a7396..6a57f71e6 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -404,6 +404,10 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem * // write the info to LaTeX Inkscape::SVGOStringStream os; + // also write original width to LaTeX + // TODO: add \ifdef statements to be able to choose between specifying width or not to specify it! + os << " %\\setlength{\\unitlength}{" << d->width() * PT_PER_PX << "pt}\n"; + os << " \\begin{picture}(" << _width << "," << _height << ")%\n"; // strip pathname, as it is probably desired. Having a specific path in the TeX file is not convenient. os << " \\put(0,0){\\includegraphics[width=\\unitlength]{" << _filename << "}}%\n"; -- cgit v1.2.3 From a29676e2e739e0b508c3eabbf6bf40b61a70dc38 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Wed, 24 Feb 2010 22:27:16 +0100 Subject: fix bug: don't output scientific notation numbers to latex (bzr r9101.1.19) --- src/extension/internal/latex-text-renderer.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 6a57f71e6..7e7e94801 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -293,6 +293,7 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) // write to LaTeX Inkscape::SVGOStringStream os; + os.setf(std::ios::fixed); // don't use scientific notation os << " \\put(" << pos[Geom::X] << "," << pos[Geom::Y] << "){"; if (has_color) { @@ -319,6 +320,7 @@ LaTeXTextRenderer::sp_flowtext_render(SPItem *item) // write to LaTeX Inkscape::SVGOStringStream os; + os.setf(std::ios::fixed); // no scientific notation os << " \\begin{picture}(" << _width << "," << _height << ")%%\n"; os << " \\gplgaddtomacro\\gplbacktext{%%\n"; @@ -403,6 +405,7 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem * // write the info to LaTeX Inkscape::SVGOStringStream os; + os.setf(std::ios::fixed); // no scientific notation // also write original width to LaTeX // TODO: add \ifdef statements to be able to choose between specifying width or not to specify it! -- cgit v1.2.3 From ce260704f96c6aad4042fb141e778fe7fe351a31 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 25 Feb 2010 00:02:25 +0100 Subject: - align on text anchor - provide better scaling option. default, the image is not scaled. image can be scaled by \def\svgwidth{...} (bzr r9101.1.20) --- src/extension/internal/latex-text-renderer.cpp | 49 ++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 7e7e94801..d44652419 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -151,7 +151,7 @@ LaTeXTextRenderer::setTargetFile(gchar const *filename) { fprintf(_stream, "%%%% Creator: Inkscape %s, www.inkscape.org\n", PACKAGE_STRING); fprintf(_stream, "%%%% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010\n"); fprintf(_stream, "%%%% Accompanies image file '%s' (pdf, eps, ps)\n", _filename); - fprintf(_stream, "%%%%"); + fprintf(_stream, "%%%%\n"); /* flush this to test output stream as early as possible */ if (fflush(_stream)) { if (ferror(_stream)) { @@ -173,9 +173,13 @@ LaTeXTextRenderer::setTargetFile(gchar const *filename) { static char const preamble[] = "%% To include the image in your LaTeX document, write\n" -"%% \\setlength{\\unitlength}{}\n" "%% \\input{.tex}\n" -"%% instead of\n" +"%% instead of\n" +"%% \\includegraphics{.pdf}\n" +"%% To scale the image, write\n" +"%% \\def{\\svgwidth}{}\n" +"%% \\input{.tex}\n" +"%% instead of\n" "%% \\includegraphics[width=]{.pdf}\n" "\n" "\\begingroup \n" @@ -187,8 +191,7 @@ static char const preamble[] = " color.sty in LaTeX.}% \n" " \\renewcommand\\color[2][]{}% \n" " }%% \n" -" \\providecommand\\rotatebox[2]{#2}% \n" -" \\makeatother \n"; +" \\providecommand\\rotatebox[2]{#2}% \n"; static char const postamble[] = " \\end{picture}% \n" @@ -250,26 +253,30 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) gchar *str = sp_te_get_string_multiline(item); // get position and alignment - Geom::Point pos; + // Align vertically on the baseline of the font (retreived from the anchor point) + // Align horizontally on boundingbox + Geom::Coord pos_x; gchar *alignment = NULL; Geom::OptRect bbox = item->getBounds(transform()); Geom::Interval bbox_x = (*bbox)[Geom::X]; - Geom::Interval bbox_y = (*bbox)[Geom::Y]; switch (style->text_anchor.computed) { case SP_CSS_TEXT_ANCHOR_START: - pos = Geom::Point( bbox_x.min() , bbox_y.middle() ); - alignment = "[l]"; + pos_x = bbox_x.min(); + alignment = "[lb]"; break; case SP_CSS_TEXT_ANCHOR_END: - pos = Geom::Point( bbox_x.max() , bbox_y.middle() ); - alignment = "[r]"; + pos_x = bbox_x.max(); + alignment = "[rb]"; break; case SP_CSS_TEXT_ANCHOR_MIDDLE: default: - pos = bbox->midpoint(); - alignment = ""; + pos_x = bbox_x.middle(); + alignment = "[b]"; break; } + Geom::Point anchor = textobj->attributes.firstXY() * transform(); + // If we want to align horizontally on bbox: Geom::Point pos(pos_x, anchor[Geom::Y]); + Geom::Point pos(anchor[Geom::X], anchor[Geom::Y]); // determine color (for now, use rgb color model as it is most native to Inkscape) bool has_color = false; // if the item has no color set, don't force black color @@ -299,11 +306,11 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) if (has_color) { os << "\\color[rgb]{" << SP_RGBA32_R_F(rgba) << "," << SP_RGBA32_G_F(rgba) << "," << SP_RGBA32_B_F(rgba) << "}"; } - os << "\\makebox(0,0)" << alignment << "{"; if (has_rotation) { os << "\\rotatebox{" << degrees << "}{"; } - os << str; + os << "\\makebox(0,0)" << alignment << "{"; + os << "\\smash{" << str << "}"; // smash the text, to be able to put the makebox coordinates at the baseline if (has_rotation) { os << "}"; // rotatebox end } @@ -407,9 +414,15 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem * Inkscape::SVGOStringStream os; os.setf(std::ios::fixed); // no scientific notation - // also write original width to LaTeX - // TODO: add \ifdef statements to be able to choose between specifying width or not to specify it! - os << " %\\setlength{\\unitlength}{" << d->width() * PT_PER_PX << "pt}\n"; + // scaling of the image when including it in LaTeX + + os << " \\ifx \\svgwidth \\@empty\n"; + os << " \\setlength{\\unitlength}{" << d->width() * PT_PER_PX << "pt}\n"; + os << " \\else\n"; + os << " \\setlength{\\unitlength}{\\svgwidth}\n"; + os << " \\fi\n"; + os << " \\global\\let\\svgwidth\\@empty\n"; + os << " \\makeatother\n"; os << " \\begin{picture}(" << _width << "," << _height << ")%\n"; // strip pathname, as it is probably desired. Having a specific path in the TeX file is not convenient. -- cgit v1.2.3 From db2cebbe4b243b26276f9fe2e9dd6213473e6ce9 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 25 Feb 2010 00:15:29 +0100 Subject: remove whitespace (bzr r9101.1.21) --- src/extension/internal/latex-text-renderer.cpp | 36 +++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index d44652419..825291e8c 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -53,7 +53,7 @@ namespace Internal { * @param filename This should be the filename without extension to which the tex code should be written. Output goes to .tex. */ bool -latex_render_document_text_to_file( SPDocument *doc, gchar const *filename, +latex_render_document_text_to_file( SPDocument *doc, gchar const *filename, const gchar * const exportId, bool exportDrawing, bool exportCanvas) { sp_document_ensure_up_to_date(doc); @@ -126,7 +126,7 @@ bool LaTeXTextRenderer::setTargetFile(gchar const *filename) { if (filename != NULL) { while (isspace(*filename)) filename += 1; - + _filename = g_path_get_basename(filename); gchar *filename_ext = g_strdup_printf("%s.tex", filename); @@ -182,20 +182,20 @@ static char const preamble[] = "%% instead of\n" "%% \\includegraphics[width=]{.pdf}\n" "\n" -"\\begingroup \n" -" \\makeatletter \n" -" \\providecommand\\color[2][]{% \n" -" \\GenericError{(Inkscape) \\space\\space\\@spaces}{% \n" -" Color is used for the text in Inkscape, but the color package color is not loaded. \n" -" }{Either use black text in Inkscape or load the package \n" -" color.sty in LaTeX.}% \n" -" \\renewcommand\\color[2][]{}% \n" -" }%% \n" -" \\providecommand\\rotatebox[2]{#2}% \n"; +"\\begingroup\n" +" \\makeatletter\n" +" \\providecommand\\color[2][]{%\n" +" \\GenericError{(Inkscape) \\space\\space\\@spaces}{%\n" +" Color is used for the text in Inkscape, but the color package color is not loaded.\n" +" }{Either use black text in Inkscape or load the package\n" +" color.sty in LaTeX.}%\n" +" \\renewcommand\\color[2][]{}%\n" +" }\n" +" \\providecommand\\rotatebox[2]{#2}\n"; static char const postamble[] = -" \\end{picture}% \n" -"\\endgroup \n"; +" \\end{picture}\n" +"\\endgroup\n"; void LaTeXTextRenderer::writePreamble() @@ -283,10 +283,10 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) // TODO: how to handle ICC colors? // give priority to fill color guint32 rgba = 0; - if (style->fill.set && style->fill.isColor()) { + if (style->fill.set && style->fill.isColor()) { has_color = true; rgba = style->fill.value.color.toRGBA32(1.); - } else if (style->stroke.set && style->stroke.isColor()) { + } else if (style->stroke.set && style->stroke.isColor()) { has_color = true; rgba = style->stroke.value.color.toRGBA32(1.); } @@ -415,12 +415,12 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem * os.setf(std::ios::fixed); // no scientific notation // scaling of the image when including it in LaTeX - + os << " \\ifx \\svgwidth \\@empty\n"; os << " \\setlength{\\unitlength}{" << d->width() * PT_PER_PX << "pt}\n"; os << " \\else\n"; os << " \\setlength{\\unitlength}{\\svgwidth}\n"; - os << " \\fi\n"; + os << " \\fi\n"; os << " \\global\\let\\svgwidth\\@empty\n"; os << " \\makeatother\n"; -- cgit v1.2.3 From 1a16023189984da1735d6b2ea640af683443a136 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 25 Feb 2010 20:03:16 +0100 Subject: fix 2 bugs (bzr r9101.1.22) --- src/extension/internal/latex-text-renderer.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 825291e8c..78b17a000 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -251,32 +251,28 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) SPStyle *style = SP_OBJECT_STYLE (SP_OBJECT(item)); gchar *str = sp_te_get_string_multiline(item); + if (!str) { + return; + } // get position and alignment // Align vertically on the baseline of the font (retreived from the anchor point) - // Align horizontally on boundingbox - Geom::Coord pos_x; + // Align horizontally on anchorpoint gchar *alignment = NULL; - Geom::OptRect bbox = item->getBounds(transform()); - Geom::Interval bbox_x = (*bbox)[Geom::X]; switch (style->text_anchor.computed) { case SP_CSS_TEXT_ANCHOR_START: - pos_x = bbox_x.min(); alignment = "[lb]"; break; case SP_CSS_TEXT_ANCHOR_END: - pos_x = bbox_x.max(); alignment = "[rb]"; break; case SP_CSS_TEXT_ANCHOR_MIDDLE: default: - pos_x = bbox_x.middle(); alignment = "[b]"; break; } Geom::Point anchor = textobj->attributes.firstXY() * transform(); - // If we want to align horizontally on bbox: Geom::Point pos(pos_x, anchor[Geom::Y]); - Geom::Point pos(anchor[Geom::X], anchor[Geom::Y]); + Geom::Point pos(anchor); // determine color (for now, use rgb color model as it is most native to Inkscape) bool has_color = false; // if the item has no color set, don't force black color @@ -393,6 +389,10 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem * } else { sp_item_invoke_bbox(base, d, sp_item_i2d_affine(base), TRUE, SPItem::RENDERING_BBOX); } + if (!d) { + g_message("LaTeXTextRenderer: could not retrieve boundingbox."); + return false; + } // scale all coordinates, such that the width of the image is 1, this is convenient for scaling the image in LaTeX double scale = 1/(d->width()); -- cgit v1.2.3 From 1532813ff2c49d332d43d90ac8642b1983ef9f9b Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 25 Feb 2010 21:34:33 +0100 Subject: prevent extra vertical space after image (bzr r9101.1.23) --- src/extension/internal/latex-text-renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 78b17a000..94e1d9893 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -194,7 +194,7 @@ static char const preamble[] = " \\providecommand\\rotatebox[2]{#2}\n"; static char const postamble[] = -" \\end{picture}\n" +" \\end{picture}%\n" "\\endgroup\n"; void -- cgit v1.2.3 From 5b3a1f074a56d963d80db6314f2448eeb21da3d2 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 25 Feb 2010 22:05:59 +0100 Subject: fix cmakelist for rename (bzr r9101.1.24) --- src/extension/internal/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/internal/CMakeLists.txt b/src/extension/internal/CMakeLists.txt index 3412b740c..8b23cb0ac 100644 --- a/src/extension/internal/CMakeLists.txt +++ b/src/extension/internal/CMakeLists.txt @@ -20,7 +20,7 @@ latex-pstricks.cpp latex-pstricks-out.cpp odf.cpp pdfinput -pdflatex-renderer.cpp +latex-text-renderer.cpp pdf-input-cairo.cpp pov-out.cpp javafx-out.cpp -- cgit v1.2.3