summaryrefslogtreecommitdiffstats
path: root/src/extension
diff options
context:
space:
mode:
authorMartin Owens <doctormo@gmail.com>2014-03-27 01:33:44 +0000
committerMartin Owens <doctormo@gmail.com>2014-03-27 01:33:44 +0000
commit5a4fb2325f60d292b47330f540b26a3279341c90 (patch)
treed2aa7967be25450b83e625025366c618101ae49f /src/extension
parentThe Polar Arrange Tab of the Arrange Dialog now hides the parametric (diff)
parentRemove Snap menu item and improve grid menu item text (diff)
downloadinkscape-5a4fb2325f60d292b47330f540b26a3279341c90.tar.gz
inkscape-5a4fb2325f60d292b47330f540b26a3279341c90.zip
Commit a merge to trunk, with probabal errors
(bzr r11073.1.36)
Diffstat (limited to 'src/extension')
-rw-r--r--src/extension/CMakeLists.txt38
-rw-r--r--src/extension/Makefile_insert1
-rw-r--r--src/extension/dbus/Makefile_insert3
-rw-r--r--src/extension/dbus/application-interface.cpp100
-rw-r--r--src/extension/dbus/application-interface.h39
-rw-r--r--src/extension/dbus/application-interface.xml23
-rw-r--r--src/extension/dbus/dbus-init.cpp121
-rw-r--r--src/extension/dbus/dbus-init.h14
-rw-r--r--src/extension/dbus/doc/spec-to-docbook.xsl2
-rw-r--r--src/extension/dbus/document-interface.cpp721
-rw-r--r--src/extension/dbus/document-interface.h192
-rw-r--r--src/extension/dbus/document-interface.xml32
-rw-r--r--src/extension/dbus/wrapper/inkscape-dbus-wrapper.c20
-rw-r--r--src/extension/dbus/wrapper/inkscape-dbus-wrapper.h8
-rw-r--r--src/extension/dependency.cpp6
-rw-r--r--src/extension/dxf2svg/GPL.txt340
-rw-r--r--src/extension/dxf2svg/LGPL.txt504
-rw-r--r--src/extension/dxf2svg/Makefile21
-rw-r--r--src/extension/dxf2svg/README41
-rw-r--r--src/extension/dxf2svg/aci2rgb.cpp114
-rw-r--r--src/extension/dxf2svg/blocks.cpp83
-rw-r--r--src/extension/dxf2svg/blocks.h38
-rw-r--r--src/extension/dxf2svg/dxf2svg.cpp99
-rw-r--r--src/extension/dxf2svg/dxf_input.inx16
-rw-r--r--src/extension/dxf2svg/dxf_input_windows.inx17
-rw-r--r--src/extension/dxf2svg/entities.cpp996
-rw-r--r--src/extension/dxf2svg/entities.h256
-rw-r--r--src/extension/dxf2svg/entities2elements.cpp678
-rw-r--r--src/extension/dxf2svg/entities2elements.h53
-rw-r--r--src/extension/dxf2svg/read_dxf.cpp275
-rw-r--r--src/extension/dxf2svg/read_dxf.h32
-rw-r--r--src/extension/dxf2svg/tables.cpp211
-rw-r--r--src/extension/dxf2svg/tables.h71
-rw-r--r--src/extension/dxf2svg/tables2svg_info.cpp37
-rw-r--r--src/extension/dxf2svg/tables2svg_info.h9
-rw-r--r--src/extension/dxf2svg/test_dxf.cpp99
-rw-r--r--src/extension/effect.cpp12
-rw-r--r--src/extension/effect.h6
-rw-r--r--src/extension/error-file.cpp11
-rw-r--r--src/extension/execution-env.cpp8
-rw-r--r--src/extension/execution-env.h2
-rw-r--r--src/extension/extension.cpp64
-rw-r--r--src/extension/extension.h33
-rw-r--r--src/extension/implementation/implementation.h3
-rw-r--r--src/extension/implementation/script.cpp109
-rw-r--r--src/extension/implementation/script.h3
-rw-r--r--src/extension/implementation/xslt.cpp2
-rw-r--r--src/extension/init.cpp38
-rw-r--r--src/extension/input.cpp7
-rw-r--r--src/extension/input.h4
-rw-r--r--src/extension/internal/Makefile_insert48
-rw-r--r--src/extension/internal/bitmap/despeckle.cpp2
-rw-r--r--src/extension/internal/bitmap/enhance.cpp2
-rw-r--r--src/extension/internal/bitmap/equalize.cpp2
-rw-r--r--src/extension/internal/bitmap/imagemagick.cpp8
-rw-r--r--src/extension/internal/bitmap/negate.cpp2
-rw-r--r--src/extension/internal/bitmap/normalize.cpp2
-rw-r--r--src/extension/internal/bluredge.cpp7
-rw-r--r--src/extension/internal/cairo-png-out.cpp2
-rw-r--r--src/extension/internal/cairo-ps-out.cpp148
-rw-r--r--src/extension/internal/cairo-render-context.cpp165
-rw-r--r--src/extension/internal/cairo-render-context.h27
-rw-r--r--src/extension/internal/cairo-renderer-pdf-out.cpp83
-rw-r--r--src/extension/internal/cairo-renderer.cpp73
-rw-r--r--src/extension/internal/cairo-renderer.h6
-rw-r--r--src/extension/internal/cdr-input.cpp339
-rw-r--r--src/extension/internal/cdr-input.h58
-rw-r--r--src/extension/internal/emf-inout.cpp3547
-rw-r--r--src/extension/internal/emf-inout.h183
-rw-r--r--src/extension/internal/emf-print.cpp2061
-rw-r--r--src/extension/internal/emf-print.h99
-rw-r--r--src/extension/internal/emf-win32-inout.cpp2524
-rw-r--r--src/extension/internal/emf-win32-inout.h57
-rw-r--r--src/extension/internal/emf-win32-print.cpp948
-rw-r--r--src/extension/internal/filter/bevels.h22
-rw-r--r--src/extension/internal/filter/blurs.h26
-rw-r--r--src/extension/internal/filter/bumps.h71
-rw-r--r--src/extension/internal/filter/color.h322
-rw-r--r--src/extension/internal/filter/distort.h28
-rw-r--r--[-rwxr-xr-x]src/extension/internal/filter/filter-all.cpp3
-rw-r--r--src/extension/internal/filter/filter-file.cpp3
-rw-r--r--src/extension/internal/filter/filter.cpp4
-rw-r--r--src/extension/internal/filter/filter.h2
-rw-r--r--src/extension/internal/filter/image.h2
-rw-r--r--src/extension/internal/filter/morphology.h24
-rw-r--r--src/extension/internal/filter/paint.h143
-rw-r--r--src/extension/internal/filter/protrusions.h2
-rw-r--r--src/extension/internal/filter/shadows.h19
-rw-r--r--src/extension/internal/filter/transparency.h22
-rw-r--r--src/extension/internal/gdkpixbuf-input.cpp163
-rw-r--r--src/extension/internal/grid.cpp51
-rw-r--r--src/extension/internal/image-resolution.cpp380
-rw-r--r--src/extension/internal/image-resolution.h41
-rw-r--r--src/extension/internal/javafx-out.cpp24
-rw-r--r--src/extension/internal/latex-pstricks.cpp19
-rw-r--r--src/extension/internal/latex-text-renderer.cpp55
-rw-r--r--src/extension/internal/latex-text-renderer.h17
-rw-r--r--src/extension/internal/metafile-inout.cpp211
-rw-r--r--src/extension/internal/metafile-inout.h93
-rw-r--r--src/extension/internal/metafile-print.cpp493
-rw-r--r--src/extension/internal/metafile-print.h134
-rw-r--r--src/extension/internal/odf.cpp1315
-rw-r--r--src/extension/internal/odf.h27
-rw-r--r--src/extension/internal/pdf-input-cairo.cpp66
-rw-r--r--src/extension/internal/pdf-input-cairo.h19
-rw-r--r--src/extension/internal/pdfinput/pdf-input.cpp63
-rw-r--r--src/extension/internal/pdfinput/pdf-input.h19
-rw-r--r--src/extension/internal/pdfinput/pdf-parser.cpp824
-rw-r--r--src/extension/internal/pdfinput/svg-builder.cpp112
-rw-r--r--src/extension/internal/pdfinput/svg-builder.h10
-rw-r--r--src/extension/internal/svg.cpp2
-rw-r--r--src/extension/internal/text_reassemble.c2926
-rw-r--r--src/extension/internal/text_reassemble.h387
-rw-r--r--src/extension/internal/vsd-input.cpp339
-rw-r--r--src/extension/internal/vsd-input.h58
-rw-r--r--src/extension/internal/wmf-inout.cpp3135
-rw-r--r--src/extension/internal/wmf-inout.h180
-rw-r--r--src/extension/internal/wmf-print.cpp1578
-rw-r--r--src/extension/internal/wmf-print.h (renamed from src/extension/internal/emf-win32-print.h)72
-rw-r--r--src/extension/internal/wpg-input.cpp8
-rw-r--r--src/extension/output.h2
-rw-r--r--src/extension/param/bool.cpp8
-rw-r--r--src/extension/param/color.cpp4
-rw-r--r--src/extension/param/description.cpp17
-rw-r--r--src/extension/param/enum.cpp31
-rw-r--r--src/extension/param/enum.h5
-rw-r--r--src/extension/param/float.cpp34
-rw-r--r--src/extension/param/int.cpp32
-rw-r--r--src/extension/param/notebook.cpp32
-rw-r--r--src/extension/param/parameter.cpp18
-rw-r--r--src/extension/param/parameter.h6
-rw-r--r--src/extension/param/radiobutton.cpp42
-rw-r--r--src/extension/param/radiobutton.h2
-rw-r--r--src/extension/param/string.cpp12
-rw-r--r--src/extension/prefdialog.cpp43
-rw-r--r--src/extension/prefdialog.h10
-rw-r--r--src/extension/script/InkscapeScript.cpp223
-rw-r--r--src/extension/script/InkscapeScript.h100
-rw-r--r--src/extension/script/Makefile_insert6
-rw-r--r--src/extension/script/makefile.in17
-rw-r--r--src/extension/system.cpp52
-rw-r--r--src/extension/timer.cpp2
142 files changed, 19599 insertions, 10618 deletions
diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt
index 5761b1e8b..9bc30a592 100644
--- a/src/extension/CMakeLists.txt
+++ b/src/extension/CMakeLists.txt
@@ -36,13 +36,17 @@ set(extension_SRC
internal/cairo-render-context.cpp
internal/cairo-renderer.cpp
internal/cairo-renderer-pdf-out.cpp
- internal/emf-win32-inout.cpp
- internal/emf-win32-print.cpp
+ internal/cdr-input.cpp
+ internal/emf-inout.cpp
+ internal/emf-print.cpp
internal/gdkpixbuf-input.cpp
internal/gimpgrad.cpp
internal/grid.cpp
+ internal/image-resolution.cpp
internal/latex-pstricks.cpp
internal/latex-pstricks-out.cpp
+ internal/metafile-inout.cpp
+ internal/metafile-print.cpp
internal/odf.cpp
internal/latex-text-renderer.cpp
internal/pdf-input-cairo.cpp
@@ -50,6 +54,10 @@ set(extension_SRC
internal/javafx-out.cpp
internal/svg.cpp
internal/svgz.cpp
+ internal/text_reassemble.c
+ internal/vsd-input.cpp
+ internal/wmf-inout.cpp
+ internal/wmf-print.cpp
internal/filter/filter-all.cpp
internal/filter/filter-file.cpp
@@ -59,19 +67,6 @@ set(extension_SRC
internal/pdfinput/pdf-parser.cpp
internal/pdfinput/svg-builder.cpp
- script/InkscapeScript.cpp
-
- # dxf2svg/aci2rgb.cpp
- # dxf2svg/entities2elements.cpp
- # dxf2svg/tables2svg_info.cpp
- # dxf2svg/blocks.cpp
- # dxf2svg/entities.cpp
- # dxf2svg/tables.cpp
- # dxf2svg/dxf2svg.cpp
- # dxf2svg/read_dxf.cpp
- # dxf2svg/test_dxf.cpp
-
-
# ------
# Header
db.h
@@ -109,9 +104,10 @@ set(extension_SRC
internal/cairo-render-context.h
internal/cairo-renderer-pdf-out.h
internal/cairo-renderer.h
+ internal/cdr-input.h
internal/clear-n_.h
- internal/emf-win32-inout.h
- internal/emf-win32-print.h
+ internal/emf-inout.h
+ internal/emf-print.h
internal/filter/bevels.h
internal/filter/blurs.h
internal/filter/bumps.h
@@ -129,10 +125,12 @@ set(extension_SRC
internal/gdkpixbuf-input.h
internal/gimpgrad.h
internal/grid.h
+ internal/image-resolution.h
internal/javafx-out.h
internal/latex-pstricks-out.h
internal/latex-pstricks.h
internal/latex-text-renderer.h
+ internal/metafile-print.h
internal/odf.h
internal/pdf-input-cairo.h
internal/pdfinput/pdf-input.h
@@ -141,8 +139,10 @@ set(extension_SRC
internal/pov-out.h
internal/svg.h
internal/svgz.h
-
- script/InkscapeScript.h
+ internal/text_reassemble.h
+ internal/vsd-input.h
+ internal/wmf-inout.h
+ internal/wmf-print.h
)
if(WIN32)
diff --git a/src/extension/Makefile_insert b/src/extension/Makefile_insert
index ffcee5f9a..4e75de13a 100644
--- a/src/extension/Makefile_insert
+++ b/src/extension/Makefile_insert
@@ -3,7 +3,6 @@
ink_common_sources += \
extension/extension.cpp \
extension/extension.h \
- extension/extension-forward.h \
extension/db.cpp \
extension/db.h \
extension/dependency.cpp \
diff --git a/src/extension/dbus/Makefile_insert b/src/extension/dbus/Makefile_insert
index a5eb3fdf4..7d851715e 100644
--- a/src/extension/dbus/Makefile_insert
+++ b/src/extension/dbus/Makefile_insert
@@ -12,7 +12,8 @@ ink_common_sources += \
extension/dbus/application-interface.cpp \
extension/dbus/application-interface.h \
extension/dbus/document-interface.cpp \
- extension/dbus/document-interface.h
+ extension/dbus/document-interface.h \
+ extension/dbus/org.inkscape.service.in
###########################
# Build DBus wrapper files
diff --git a/src/extension/dbus/application-interface.cpp b/src/extension/dbus/application-interface.cpp
index a652b7c96..c0bc19d90 100644
--- a/src/extension/dbus/application-interface.cpp
+++ b/src/extension/dbus/application-interface.cpp
@@ -18,6 +18,8 @@
#include "application-interface.h"
#include <string.h>
#include "dbus-init.h"
+#include "file.h"
+#include "inkscape.h"
G_DEFINE_TYPE(ApplicationInterface, application_interface, G_TYPE_OBJECT)
@@ -37,10 +39,32 @@ application_interface_class_init (ApplicationInterfaceClass *klass)
}
static void
-application_interface_init (ApplicationInterface *object)
+application_interface_init (ApplicationInterface *app_interface)
{
+ dbus_g_error_domain_register (INKSCAPE_ERROR,
+ NULL,
+ INKSCAPE_TYPE_ERROR);
}
+static bool
+ensure_desktop_valid(GError **error)
+{
+ if (!inkscape_use_gui()) {
+ g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Application interface action requires a GUI");
+ return false;
+ }
+ return true;
+}
+
+static bool
+ensure_desktop_not_present(GError **error)
+{
+ if (inkscape_use_gui()) {
+ g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Application interface action requires non-GUI (command line) mode");
+ return false;
+ }
+ return true;
+}
ApplicationInterface *
application_interface_new (void)
@@ -48,32 +72,71 @@ application_interface_new (void)
return (ApplicationInterface*)g_object_new (TYPE_APPLICATION_INTERFACE, NULL);
}
+/*
+ * Error stuff...
+ *
+ * To add a new error type, edit here and in the .h InkscapeError enum.
+ */
+GQuark
+inkscape_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string ("inkscape_error");
+
+ return quark;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType inkscape_error_get_type(void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] =
+ {
+
+ ENUM_ENTRY(INKSCAPE_ERROR_SELECTION, "Incompatible_Selection"),
+ ENUM_ENTRY(INKSCAPE_ERROR_OBJECT, "Incompatible_Object"),
+ ENUM_ENTRY(INKSCAPE_ERROR_VERB, "Failed_Verb"),
+ ENUM_ENTRY(INKSCAPE_ERROR_OTHER, "Generic_Error"),
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static("InkscapeError", values);
+ }
+
+ return etype;
+}
+
/****************************************************************************
DESKTOP FUNCTIONS
****************************************************************************/
gchar*
-application_interface_desktop_new (ApplicationInterface *object,
+application_interface_desktop_new (ApplicationInterface *app_interface,
GError **error)
{
- return (gchar*)Inkscape::Extension::Dbus::init_desktop();
+ g_return_val_if_fail(ensure_desktop_valid(error), NULL);
+ return (gchar*)Inkscape::Extension::Dbus::init_desktop();
}
gchar**
-application_interface_get_desktop_list (ApplicationInterface *object)
+application_interface_get_desktop_list (ApplicationInterface *app_interface)
{
return NULL;
}
gchar*
-application_interface_get_active_desktop (ApplicationInterface *object,
+application_interface_get_active_desktop (ApplicationInterface *app_interface,
GError **error)
{
return NULL;
}
gboolean
-application_interface_set_active_desktop (ApplicationInterface *object,
+application_interface_set_active_desktop (ApplicationInterface *app_interface,
gchar* document_name,
GError **error)
{
@@ -81,15 +144,16 @@ application_interface_set_active_desktop (ApplicationInterface *object,
}
gboolean
-application_interface_desktop_close_all (ApplicationInterface *object,
+application_interface_desktop_close_all (ApplicationInterface *app_interface,
GError **error)
{
return TRUE;
}
gboolean
-application_interface_exit (ApplicationInterface *object, GError **error)
+application_interface_exit (ApplicationInterface *app_interface, GError **error)
{
+ sp_file_exit();
return TRUE;
}
@@ -97,20 +161,32 @@ application_interface_exit (ApplicationInterface *object, GError **error)
DOCUMENT FUNCTIONS
****************************************************************************/
-gchar* application_interface_document_new (ApplicationInterface *object,
+gchar* application_interface_document_new (ApplicationInterface *app_interface,
GError **error)
{
- return (gchar*)Inkscape::Extension::Dbus::init_document();
+ g_return_val_if_fail(ensure_desktop_not_present(error), NULL);
+ return (gchar*)Inkscape::Extension::Dbus::init_document();
+}
+
+gchar*
+application_interface_get_active_document(ApplicationInterface *app_interface,
+ GError **error)
+{
+ gchar *result = (gchar*)Inkscape::Extension::Dbus::init_active_document();
+ if (!result) {
+ g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "No active document");
+ }
+ return result;
}
gchar**
-application_interface_get_document_list (ApplicationInterface *object)
+application_interface_get_document_list (ApplicationInterface *app_interface)
{
return NULL;
}
gboolean
-application_interface_document_close_all (ApplicationInterface *object,
+application_interface_document_close_all (ApplicationInterface *app_interface,
GError **error)
{
return TRUE;
diff --git a/src/extension/dbus/application-interface.h b/src/extension/dbus/application-interface.h
index e782bd1ad..c108402cb 100644
--- a/src/extension/dbus/application-interface.h
+++ b/src/extension/dbus/application-interface.h
@@ -45,46 +45,67 @@ struct _ApplicationInterfaceClass {
GObjectClass parent;
};
+
+typedef enum
+{
+ INKSCAPE_ERROR_SELECTION,
+ INKSCAPE_ERROR_OBJECT,
+ INKSCAPE_ERROR_VERB,
+ INKSCAPE_ERROR_OTHER
+} InkscapeError;
+
+
+
+#define INKSCAPE_ERROR (inkscape_error_quark ())
+#define INKSCAPE_TYPE_ERROR (inkscape_error_get_type ())
+
+GQuark inkscape_error_quark (void);
+GType inkscape_error_get_type (void);
+
/****************************************************************************
DESKTOP FUNCTIONS
****************************************************************************/
gchar*
-application_interface_desktop_new (ApplicationInterface *object,
+application_interface_desktop_new (ApplicationInterface *app_interface,
GError **error);
gchar**
-application_interface_get_desktop_list (ApplicationInterface *object);
+application_interface_get_desktop_list (ApplicationInterface *app_interface);
gchar*
-application_interface_get_active_desktop (ApplicationInterface *object,
+application_interface_get_active_desktop (ApplicationInterface *app_interface,
GError **error);
gboolean
-application_interface_set_active_desktop (ApplicationInterface *object,
+application_interface_set_active_desktop (ApplicationInterface *app_interface,
gchar* document_name,
GError **error);
gboolean
-application_interface_desktop_close_all (ApplicationInterface *object,
+application_interface_desktop_close_all (ApplicationInterface *app_interface,
GError **error);
gboolean
-application_interface_exit (ApplicationInterface *object, GError **error);
+application_interface_exit (ApplicationInterface *app_interface, GError **error);
/****************************************************************************
DOCUMENT FUNCTIONS
****************************************************************************/
gchar*
-application_interface_document_new (ApplicationInterface *object,
+application_interface_document_new (ApplicationInterface *app_interface,
GError **error);
+gchar*
+application_interface_get_active_document(ApplicationInterface *app_interface,
+ GError **error);
+
gchar**
-application_interface_get_document_list (ApplicationInterface *object);
+application_interface_get_document_list (ApplicationInterface *app_interface);
gboolean
-application_interface_document_close_all (ApplicationInterface *object,
+application_interface_document_close_all (ApplicationInterface *app_interface,
GError **error);
diff --git a/src/extension/dbus/application-interface.xml b/src/extension/dbus/application-interface.xml
index ee2c4837b..1553971cc 100644
--- a/src/extension/dbus/application-interface.xml
+++ b/src/extension/dbus/application-interface.xml
@@ -32,7 +32,7 @@
</arg>
<doc:doc>
<doc:description>
- <doc:para>Create a new document interface and return it's location.</doc:para>
+ <doc:para>Create a new document interface and return its location. Only call this when Inkscape is running in GUI mode.</doc:para>
</doc:description>
</doc:doc>
</method>
@@ -45,21 +45,21 @@
</arg>
<doc:doc>
<doc:description>
- <doc:para>List all the interfaces that it is possible to connect to.</doc:para>
+ <doc:para>List all the interfaces that it is possible to connect to. TODO: not implemented.</doc:para>
</doc:description>
</doc:doc>
</method>
<method name="desktop_close_all">
<doc:doc>
<doc:description>
- <doc:para>Close all document interfaces without saving.</doc:para>
+ <doc:para>Close all document interfaces without saving. TODO: not implemented.</doc:para>
</doc:description>
</doc:doc>
</method>
<method name="exit">
<doc:doc>
<doc:description>
- <doc:para>Exit Inkscape without saving. Fairly straightforward. </doc:para>
+ <doc:para>Exit Inkscape without saving. Fairly straightforward.</doc:para>
</doc:description>
</doc:doc>
</method>
@@ -76,6 +76,21 @@
<doc:description>
<doc:para>Originally, there were going to be two interfaces. A desktop and a document. Desktops would be used when the user wanted to see the result of their code and documents would be used when less overhead was desired. Unfortunately as more and more of the code can to rely on the desktop and it's associated support code (including selections and verbs) the document interface was looking more and more limited. Ultimately I decided to just go with the desktop interface since I didn't have a compelling reason for keeping the other one and having two similar interfaces could be very confusing. The desktop interface inherited the document name because I believe it's more familiar to people.</doc:para>
<doc:para>Perhaps it would be best to have an option as to whether or not to create a window and fail with a good error message when they call a function that requires one. Or have a second interface for different use cases but have it be completely different, rather than a subset of the first if there are use cases that support it.</doc:para>
+ <doc:para>UPDATE: 3rd July 2013, Eric Greveson: After having done some initial work to attempt to decouple Inkscape "verbs" from desktops, it is now possible to run a limited subset of actions in command-line mode (with a selection model and document, but no desktop). I believe that the "single document interface" approach, with some functions that may require a GUI, is the better path, and so document interfaces without a desktop are now possible. Most functions still require the desktop to work, though, with the notable exception of selection methods and Boolean operations.</doc:para>
+ <doc:para>As a result, this function should ONLY be called when using Inkscape in command-line mode. Use "desktop_new" instead if running in GUI mode.</doc:para>
+ </doc:description>
+ </doc:doc>
+ </method>
+ <method name="get_active_document">
+ <arg type="s" name="document_name" direction="out" >
+ <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value="error"/>
+ <doc:doc>
+ <doc:summary>This string can be used to connect to the current active document.</doc:summary>
+ </doc:doc>
+ </arg>
+ <doc:doc>
+ <doc:description>
+ <doc:para>Get the location of the current active document (e.g. when running in console mode, when desktops are not available).</doc:para>
</doc:description>
</doc:doc>
</method>
diff --git a/src/extension/dbus/dbus-init.cpp b/src/extension/dbus/dbus-init.cpp
index 1b6baa979..19b48e10d 100644
--- a/src/extension/dbus/dbus-init.cpp
+++ b/src/extension/dbus/dbus-init.cpp
@@ -36,7 +36,14 @@
#include <sstream>
-
+namespace
+{
+ // This stores the bus name to use for this app instance. By default, it
+ // will be set to org.inkscape. However, users may provide other names by
+ // setting command-line parameters when starting Inkscape, so that more
+ // than one instance of Inkscape may be used by external scripts.
+ gchar *instance_bus_name = NULL;
+}
namespace Inkscape {
namespace Extension {
@@ -78,10 +85,53 @@ dbus_register_object (DBusGConnection *connection,
return object;
}
+/*
+ * PRIVATE register a document interface for the document in the given ActionContext, if none exists.
+ * Return the DBus path to the interface (something like /org/inkscape/document_0).
+ * Note that while a DocumentInterface could be used either for a document with no desktop, or a
+ * document with a desktop, this function is only used for creating interfaces in the former case.
+ * Desktop-associated DocumentInterfaces are named /org/inkscape/desktop_0, etc.
+ * FIXME: This state of affairs probably needs tidying up at some point in the future.
+ */
+static gchar *
+dbus_register_document(Inkscape::ActionContext const & target)
+{
+ SPDocument *doc = target.getDocument();
+ g_assert(doc != NULL);
+
+ // Document name is not suitable for DBus name, as it might contain invalid chars
+ std::string name("/org/inkscape/document_");
+ std::stringstream ss;
+ ss << doc->serial();
+ name.append(ss.str());
+
+ DBusGConnection *connection = dbus_get_connection();
+ DBusGProxy *proxy = dbus_get_proxy(connection);
+
+ // Has the document already been registered?
+ if (!dbus_g_connection_lookup_g_object(connection, name.c_str())) {
+ // No - register it
+ DocumentInterface *doc_interface = (DocumentInterface*) dbus_register_object (connection,
+ proxy,
+ TYPE_DOCUMENT_INTERFACE,
+ &dbus_glib_document_interface_object_info,
+ name.c_str());
+
+ // Set the document info for this interface
+ doc_interface->target = target;
+ }
+ return strdup(name.c_str());
+}
+
/* Initialize a Dbus service */
void
init (void)
{
+ if (instance_bus_name == NULL) {
+ // Set the bus name to the default
+ instance_bus_name = strdup("org.inkscape");
+ }
+
guint result;
GError *error = NULL;
DBusGConnection *connection;
@@ -89,7 +139,7 @@ init (void)
connection = dbus_get_connection();
proxy = dbus_get_proxy(connection);
org_freedesktop_DBus_request_name (proxy,
- "org.inkscape",
+ instance_bus_name,
DBUS_NAME_FLAG_DO_NOT_QUEUE, &result, &error);
//create interface for application
dbus_register_object (connection,
@@ -97,40 +147,36 @@ init (void)
TYPE_APPLICATION_INTERFACE,
&dbus_glib_application_interface_object_info,
DBUS_APPLICATION_INTERFACE_PATH);
-} //init
+}
gchar *
-init_document (void) {
- DBusGConnection *connection;
- DBusGProxy *proxy;
- SPDocument *doc;
-
- doc = SPDocument::createNewDoc(NULL, 1, TRUE);
-
- std::string name("/org/inkscape/");
- name.append(doc->getName());
- std::replace(name.begin(), name.end(), ' ', '_');
+init_document (void)
+{
+ // This is for command-line use only
+ g_assert(!inkscape_use_gui());
- connection = dbus_get_connection();
- proxy = dbus_get_proxy(connection);
+ // Create a blank document and get its selection model etc in an ActionContext
+ SPDocument *doc = SPDocument::createNewDoc(NULL, 1, TRUE);
+ inkscape_add_document(doc);
+ return dbus_register_document(inkscape_action_context_for_document(doc));
+}
- dbus_register_object (connection,
- proxy,
- TYPE_DOCUMENT_INTERFACE,
- &dbus_glib_document_interface_object_info,
- name.c_str());
- return strdup(name.c_str());
-} //init_document
+gchar *
+init_active_document()
+{
+ SPDocument *doc = inkscape_active_document();
+ if (!doc) {
+ return NULL;
+ }
+
+ return dbus_register_document(inkscape_active_action_context());
+}
gchar *
dbus_init_desktop_interface (SPDesktop * dt)
{
DBusGConnection *connection;
DBusGProxy *proxy;
- DocumentInterface *obj;
- dbus_g_error_domain_register (INKSCAPE_ERROR,
- NULL,
- INKSCAPE_TYPE_ERROR);
std::string name("/org/inkscape/desktop_");
std::stringstream out;
@@ -142,12 +188,12 @@ dbus_init_desktop_interface (SPDesktop * dt)
connection = dbus_get_connection();
proxy = dbus_get_proxy(connection);
- obj = (DocumentInterface*) dbus_register_object (connection,
+ DocumentInterface *doc_interface = (DocumentInterface*) dbus_register_object (connection,
proxy, TYPE_DOCUMENT_INTERFACE,
&dbus_glib_document_interface_object_info, name.c_str());
- obj->desk = dt;
- obj->updates = TRUE;
- dt->dbus_document_interface=obj;
+ doc_interface->target = Inkscape::ActionContext(dt);
+ doc_interface->updates = TRUE;
+ dt->dbus_document_interface=doc_interface;
return strdup(name.c_str());
}
@@ -162,8 +208,21 @@ init_desktop (void) {
out << dt->dkey;
name.append(out.str());
return strdup(name.c_str());
-} //init_desktop
+}
+void
+dbus_set_bus_name(gchar * bus_name)
+{
+ g_assert(bus_name != NULL);
+ g_assert(instance_bus_name == NULL);
+ instance_bus_name = strdup(bus_name);
+}
+gchar *
+dbus_get_bus_name()
+{
+ g_assert(instance_bus_name != NULL);
+ return instance_bus_name;
+}
} } } /* namespace Inkscape::Extension::Dbus */
diff --git a/src/extension/dbus/dbus-init.h b/src/extension/dbus/dbus-init.h
index 4b07acfb4..7862ad3c3 100644
--- a/src/extension/dbus/dbus-init.h
+++ b/src/extension/dbus/dbus-init.h
@@ -10,7 +10,7 @@
#ifndef INKSCAPE_EXTENSION_DBUS_INIT_H__
#define INKSCAPE_EXTENSION_DBUS_INIT_H__
-#include "desktop.h"
+class SPDesktop;
namespace Inkscape {
namespace Extension {
@@ -22,10 +22,22 @@ void init (void);
gchar * init_document (void);
+gchar * init_active_document ();
+
gchar * init_desktop (void);
gchar * dbus_init_desktop_interface (SPDesktop * dt);
+/** Set the bus name to use. Default is "org.inkscape".
+ This function should only be called once, before init(), if a non-default
+ bus name is required. */
+void dbus_set_bus_name(gchar * bus_name);
+
+/** Get the bus name for this instance. Default is "org.inkscape".
+ This function should only be called after init().
+ The returned gchar * is owned by this module and should not be freed. */
+gchar * dbus_get_bus_name();
+
} } } /* namespace Dbus, Extension, Inkscape */
#endif /* INKSCAPE_EXTENSION_DBUS_INIT_H__ */
diff --git a/src/extension/dbus/doc/spec-to-docbook.xsl b/src/extension/dbus/doc/spec-to-docbook.xsl
index e200a05e0..a4e792df0 100644
--- a/src/extension/dbus/doc/spec-to-docbook.xsl
+++ b/src/extension/dbus/doc/spec-to-docbook.xsl
@@ -491,7 +491,7 @@ See also:
<xsl:template name="pad-spaces">
<xsl:param name="width"/>
- <xsl:variable name="spaces" xml:space="preserve"> </xsl:variable>
+ <xsl:variable name="spaces" select="' '" ></xsl:variable>
<xsl:value-of select="substring($spaces,1,$width)"/>
</xsl:template>
diff --git a/src/extension/dbus/document-interface.cpp b/src/extension/dbus/document-interface.cpp
index c67234b34..221a3e879 100644
--- a/src/extension/dbus/document-interface.cpp
+++ b/src/extension/dbus/document-interface.cpp
@@ -17,8 +17,10 @@
#include "file.h" //IO
#include "document-interface.h"
+#include "application-interface.h"
#include <string.h>
#include <dbus/dbus-glib.h>
+#include "desktop.h"
#include "desktop-handles.h" //sp_desktop_document()
#include "desktop-style.h" //sp_desktop_get_style
#include "display/canvas-text.h" //text
@@ -29,8 +31,10 @@
#include "extension/system.h" //IO
#include "file.h" //IO
#include "helper/action.h" //sp_action_perform
+#include "helper/action-context.h"
#include "inkscape.h" //inkscape_find_desktop_by_dkey, activate desktops
#include "layer-fns.h" //LPOS_BELOW
+#include "layer-model.h"
#include "live_effects/parameter/text.h" //text
#include "print.h" //IO
#include "selection-chemistry.h"// lots of selection functions
@@ -39,6 +43,7 @@
#include "sp-object.h"
#include "sp-root.h"
#include "style.h" //style_write
+#include "util/units.h"
#include "extension/system.h" //IO
@@ -90,12 +95,12 @@
* place to adjust things.
*/
Inkscape::XML::Node *
-get_repr_by_name (SPDesktop *desk, gchar *name, GError **error)
+get_repr_by_name (SPDocument *doc, gchar *name, GError **error)
{
/* ALTERNATIVE (is this faster if only repr is needed?)
Inkscape::XML::Node *node = sp_repr_lookup_name((doc->root)->repr, name);
*/
- SPObject * obj = sp_desktop_document(desk)->getObjectById(name);
+ SPObject * obj = doc->getObjectById(name);
if (!obj)
{
g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name);
@@ -108,9 +113,9 @@ get_repr_by_name (SPDesktop *desk, gchar *name, GError **error)
* See comment for get_repr_by_name, above.
*/
SPObject *
-get_object_by_name (SPDesktop *desk, gchar *name, GError **error)
+get_object_by_name (SPDocument *doc, gchar *name, GError **error)
{
- SPObject * obj = sp_desktop_document(desk)->getObjectById(name);
+ SPObject * obj = doc->getObjectById(name);
if (!obj)
{
g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name);
@@ -182,12 +187,11 @@ selection_get_center_y (Inkscape::Selection *sel){
* they might see the selection box flicker if used in a loop.
*/
const GSList *
-selection_swap(SPDesktop *desk, gchar *name, GError **error)
+selection_swap(Inkscape::Selection *sel, gchar *name, GError **error)
{
- Inkscape::Selection *sel = sp_desktop_selection(desk);
const GSList *oldsel = g_slist_copy((GSList *)sel->list());
- sel->set(get_object_by_name(desk, name, error));
+ sel->set(get_object_by_name(sel->layers()->getDocument(), name, error));
return oldsel;
}
@@ -195,9 +199,8 @@ selection_swap(SPDesktop *desk, gchar *name, GError **error)
* See selection_swap, above
*/
void
-selection_restore(SPDesktop *desk, const GSList * oldsel)
+selection_restore(Inkscape::Selection *sel, const GSList * oldsel)
{
- Inkscape::Selection *sel = sp_desktop_selection(desk);
sel->setList(oldsel);
}
@@ -205,9 +208,8 @@ selection_restore(SPDesktop *desk, const GSList * oldsel)
* Shortcut for creating a Node.
*/
Inkscape::XML::Node *
-dbus_create_node (SPDesktop *desk, const gchar *type)
+dbus_create_node (SPDocument *doc, const gchar *type)
{
- SPDocument * doc = sp_desktop_document (desk);
Inkscape::XML::Document *xml_doc = doc->getReprDoc();
return xml_doc->createElement(type);
@@ -220,25 +222,26 @@ dbus_create_node (SPDesktop *desk, const gchar *type)
* There is probably a better way to do this (use the shape tools default styles)
* but I'm not sure how.
*/
-gchar *finish_create_shape (DocumentInterface *object, GError ** /*error*/, Inkscape::XML::Node *newNode, gchar *desc)
+gchar *finish_create_shape (DocumentInterface *doc_interface, GError ** /*error*/, Inkscape::XML::Node *newNode, gchar *desc)
{
-
- SPCSSAttr *style = sp_desktop_get_style(object->desk, TRUE);
-
+ SPCSSAttr *style = NULL;
+ if (doc_interface->target.getDesktop()) {
+ style = sp_desktop_get_style(doc_interface->target.getDesktop(), TRUE);
+ }
if (style) {
- newNode->setAttribute("style", sp_repr_css_write_string(style), TRUE);
+ Glib::ustring str;
+ sp_repr_css_write_string(style, str);
+ newNode->setAttribute("style", str.c_str(), TRUE);
}
else {
newNode->setAttribute("style", "fill:#0000ff;fill-opacity:1;stroke:#c900b9;stroke-width:0;stroke-miterlimit:0;stroke-opacity:1;stroke-dasharray:none", TRUE);
}
- object->desk->currentLayer()->appendChildRepr(newNode);
- object->desk->currentLayer()->updateRepr();
+ doc_interface->target.getSelection()->layers()->currentLayer()->appendChildRepr(newNode);
+ doc_interface->target.getSelection()->layers()->currentLayer()->updateRepr();
- if (object->updates) {
- Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), 0, (gchar *)desc);
- //} else {
- //document_interface_pause_updates(object, error);
+ if (doc_interface->updates) {
+ Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), 0, (gchar *)desc);
}
return strdup(newNode->attribute("id"));
@@ -253,31 +256,40 @@ gchar *finish_create_shape (DocumentInterface *object, GError ** /*error*/, Inks
* document_interface_call_verb is similar but is called by the user.
*/
gboolean
-dbus_call_verb (DocumentInterface *object, int verbid, GError **error)
+dbus_call_verb (DocumentInterface *doc_interface, int verbid, GError **error)
{
- SPDesktop *desk2 = object->desk;
- desktop_ensure_active (desk2);
-
- if ( desk2 ) {
- Inkscape::Verb *verb = Inkscape::Verb::get( verbid );
- if ( verb ) {
- SPAction *action = verb->get_action(desk2);
- if ( action ) {
- //if (!object->updates)
- //document_interface_pause_updates (object, error);
- sp_action_perform( action, NULL );
- if (object->updates)
- Inkscape::DocumentUndo::done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip()));
- //if (!object->updates)
- //document_interface_pause_updates (object, error);
- return TRUE;
- }
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ if ( desk ) {
+ desktop_ensure_active (desk);
+ }
+ Inkscape::Verb *verb = Inkscape::Verb::get( verbid );
+ if ( verb ) {
+ SPAction *action = verb->get_action(doc_interface->target);
+ if ( action ) {
+ sp_action_perform( action, NULL );
+ if (doc_interface->updates)
+ Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), verb->get_code(), verb->get_tip());
+ return TRUE;
}
}
g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_VERB, "Verb failed to execute");
return FALSE;
}
+/*
+ * Check that the desktop is not NULL. If it is NULL, set the error to a useful message.
+ */
+bool
+ensure_desktop_valid(SPDesktop* desk, GError **error)
+{
+ if (desk) {
+ return true;
+ }
+
+ g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Document interface action requires a GUI");
+ return false;
+}
+
/****************************************************************************
DOCUMENT INTERFACE CLASS STUFF
****************************************************************************/
@@ -308,9 +320,9 @@ document_interface_class_init (DocumentInterfaceClass *klass)
}
static void
-document_interface_init (DocumentInterface *object)
+document_interface_init (DocumentInterface *doc_interface)
{
- object->desk = NULL;
+ doc_interface->target = Inkscape::ActionContext();
}
@@ -320,70 +332,34 @@ document_interface_new (void)
return (DocumentInterface*)g_object_new (TYPE_DOCUMENT_INTERFACE, NULL);
}
-/*
- * Error stuff...
- *
- * To add a new error type, edit here and in the .h InkscapeError enum.
- */
-GQuark
-inkscape_error_quark (void)
-{
- static GQuark quark = 0;
- if (!quark)
- quark = g_quark_from_static_string ("inkscape_error");
-
- return quark;
-}
-
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-GType inkscape_error_get_type(void)
-{
- static GType etype = 0;
-
- if (etype == 0) {
- static const GEnumValue values[] =
- {
-
- ENUM_ENTRY(INKSCAPE_ERROR_SELECTION, "Incompatible_Selection"),
- ENUM_ENTRY(INKSCAPE_ERROR_OBJECT, "Incompatible_Object"),
- ENUM_ENTRY(INKSCAPE_ERROR_VERB, "Failed_Verb"),
- ENUM_ENTRY(INKSCAPE_ERROR_OTHER, "Generic_Error"),
- { 0, 0, 0 }
- };
-
- etype = g_enum_register_static("InkscapeError", values);
- }
- return etype;
-}
/****************************************************************************
MISC FUNCTIONS
****************************************************************************/
-gboolean document_interface_delete_all(DocumentInterface *object, GError ** /*error*/)
+gboolean document_interface_delete_all(DocumentInterface *doc_interface, GError ** /*error*/)
{
- sp_edit_clear_all(object->desk);
+ sp_edit_clear_all(doc_interface->target.getSelection());
return TRUE;
}
gboolean
-document_interface_call_verb (DocumentInterface *object, gchar *verbid, GError **error)
-{
- SPDesktop *desk2 = object->desk;
- desktop_ensure_active (object->desk);
- if ( desk2 ) {
- Inkscape::Verb *verb = Inkscape::Verb::getbyid( verbid );
- if ( verb ) {
- SPAction *action = verb->get_action(desk2);
- if ( action ) {
- sp_action_perform( action, NULL );
- if (object->updates) {
- Inkscape::DocumentUndo::done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip()));
- }
- return TRUE;
+document_interface_call_verb (DocumentInterface *doc_interface, gchar *verbid, GError **error)
+{
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ if ( desk ) {
+ desktop_ensure_active (desk);
+ }
+ Inkscape::Verb *verb = Inkscape::Verb::getbyid( verbid );
+ if ( verb ) {
+ SPAction *action = verb->get_action(doc_interface->target);
+ if ( action ) {
+ sp_action_perform( action, NULL );
+ if (doc_interface->updates) {
+ Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), verb->get_code(), verb->get_tip());
}
+ return TRUE;
}
}
g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_VERB, "Verb '%s' failed to execute or was not found.", verbid);
@@ -396,39 +372,39 @@ document_interface_call_verb (DocumentInterface *object, gchar *verbid, GError *
****************************************************************************/
gchar*
-document_interface_rectangle (DocumentInterface *object, int x, int y,
+document_interface_rectangle (DocumentInterface *doc_interface, int x, int y,
int width, int height, GError **error)
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:rect");
+ Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:rect");
sp_repr_set_int(newNode, "x", x); //could also use newNode->setAttribute()
sp_repr_set_int(newNode, "y", y);
sp_repr_set_int(newNode, "width", width);
sp_repr_set_int(newNode, "height", height);
- return finish_create_shape (object, error, newNode, (gchar *)"create rectangle");
+ return finish_create_shape (doc_interface, error, newNode, (gchar *)"create rectangle");
}
gchar*
-document_interface_ellipse_center (DocumentInterface *object, int cx, int cy,
+document_interface_ellipse_center (DocumentInterface *doc_interface, int cx, int cy,
int rx, int ry, GError **error)
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
+ Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path");
newNode->setAttribute("sodipodi:type", "arc");
sp_repr_set_int(newNode, "sodipodi:cx", cx);
sp_repr_set_int(newNode, "sodipodi:cy", cy);
sp_repr_set_int(newNode, "sodipodi:rx", rx);
sp_repr_set_int(newNode, "sodipodi:ry", ry);
- return finish_create_shape (object, error, newNode, (gchar *)"create circle");
+ return finish_create_shape (doc_interface, error, newNode, (gchar *)"create circle");
}
gchar*
-document_interface_polygon (DocumentInterface *object, int cx, int cy,
+document_interface_polygon (DocumentInterface *doc_interface, int cx, int cy,
int radius, int rotation, int sides,
GError **error)
{
gdouble rot = ((rotation / 180.0) * 3.14159265) - ( 3.14159265 / 2.0);
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
+ Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path");
newNode->setAttribute("inkscape:flatsided", "true");
newNode->setAttribute("sodipodi:type", "star");
sp_repr_set_int(newNode, "sodipodi:cx", cx);
@@ -441,15 +417,15 @@ document_interface_polygon (DocumentInterface *object, int cx, int cy,
sp_repr_set_svg_double(newNode, "sodipodi:arg2", rot);
sp_repr_set_svg_double(newNode, "inkscape:rounded", 0);
- return finish_create_shape (object, error, newNode, (gchar *)"create polygon");
+ return finish_create_shape (doc_interface, error, newNode, (gchar *)"create polygon");
}
gchar*
-document_interface_star (DocumentInterface *object, int cx, int cy,
+document_interface_star (DocumentInterface *doc_interface, int cx, int cy,
int r1, int r2, int sides, gdouble rounded,
gdouble arg1, gdouble arg2, GError **error)
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
+ Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path");
newNode->setAttribute("inkscape:flatsided", "false");
newNode->setAttribute("sodipodi:type", "star");
sp_repr_set_int(newNode, "sodipodi:cx", cx);
@@ -462,35 +438,35 @@ document_interface_star (DocumentInterface *object, int cx, int cy,
sp_repr_set_svg_double(newNode, "sodipodi:arg2", arg2);
sp_repr_set_svg_double(newNode, "inkscape:rounded", rounded);
- return finish_create_shape (object, error, newNode, (gchar *)"create star");
+ return finish_create_shape (doc_interface, error, newNode, (gchar *)"create star");
}
gchar*
-document_interface_ellipse (DocumentInterface *object, int x, int y,
+document_interface_ellipse (DocumentInterface *doc_interface, int x, int y,
int width, int height, GError **error)
{
int rx = width/2;
int ry = height/2;
- return document_interface_ellipse_center (object, x+rx, y+ry, rx, ry, error);
+ return document_interface_ellipse_center (doc_interface, x+rx, y+ry, rx, ry, error);
}
gchar*
-document_interface_line (DocumentInterface *object, int x, int y,
+document_interface_line (DocumentInterface *doc_interface, int x, int y,
int x2, int y2, GError **error)
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
+ Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path");
std::stringstream out;
// Not sure why this works.
out << "m " << x << "," << y << " " << x2 - x << "," << y2 - y;
newNode->setAttribute("d", out.str().c_str());
- return finish_create_shape (object, error, newNode, (gchar *)"create line");
+ return finish_create_shape (doc_interface, error, newNode, (gchar *)"create line");
}
gchar*
-document_interface_spiral (DocumentInterface *object, int cx, int cy,
+document_interface_spiral (DocumentInterface *doc_interface, int cx, int cy,
int r, int revolutions, GError **error)
{
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:path");
+ Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:path");
newNode->setAttribute("sodipodi:type", "spiral");
sp_repr_set_int(newNode, "sodipodi:cx", cx);
sp_repr_set_int(newNode, "sodipodi:cy", cy);
@@ -499,7 +475,7 @@ document_interface_spiral (DocumentInterface *object, int cx, int cy,
sp_repr_set_int(newNode, "sodipodi:t0", 0);
sp_repr_set_int(newNode, "sodipodi:argument", 0);
sp_repr_set_int(newNode, "sodipodi:expansion", 1);
- gchar * retval = finish_create_shape (object, error, newNode, (gchar *)"create spiral");
+ gchar * retval = finish_create_shape (doc_interface, error, newNode, (gchar *)"create spiral");
//Makes sure there is no fill for spirals by default.
gchar* newString = g_strconcat(newNode->attribute("style"), ";fill:none", NULL);
newNode->setAttribute("style", newString);
@@ -508,111 +484,117 @@ document_interface_spiral (DocumentInterface *object, int cx, int cy,
}
gchar*
-document_interface_text (DocumentInterface *object, int x, int y, gchar *text, GError **error)
+document_interface_text (DocumentInterface *doc_interface, int x, int y, gchar *text, GError **error)
{
- Inkscape::XML::Node *text_node = dbus_create_node(object->desk, "svg:text");
+ Inkscape::XML::Node *text_node = dbus_create_node(doc_interface->target.getDocument(), "svg:text");
sp_repr_set_int(text_node, "x", x);
sp_repr_set_int(text_node, "y", y);
//just a workaround so i can get an spitem from the name
- gchar *name = finish_create_shape (object, error, text_node, (gchar *)"create text");
+ gchar *name = finish_create_shape (doc_interface, error, text_node, (gchar *)"create text");
- SPItem* text_obj=(SPItem* )get_object_by_name(object->desk, name, error);
+ SPItem* text_obj=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error);
sp_te_set_repr_text_multiline(text_obj, text);
return name;
}
gchar *
-document_interface_image (DocumentInterface *object, int x, int y, gchar *filename, GError **error)
+document_interface_image (DocumentInterface *doc_interface, int x, int y, gchar *filename, GError **error)
{
gchar * uri = g_filename_to_uri (filename, FALSE, error);
if (!uri)
return FALSE;
- Inkscape::XML::Node *newNode = dbus_create_node(object->desk, "svg:image");
+ Inkscape::XML::Node *newNode = dbus_create_node(doc_interface->target.getDocument(), "svg:image");
sp_repr_set_int(newNode, "x", x);
sp_repr_set_int(newNode, "y", y);
newNode->setAttribute("xlink:href", uri);
- object->desk->currentLayer()->appendChildRepr(newNode);
- object->desk->currentLayer()->updateRepr();
+ doc_interface->target.getSelection()->layers()->currentLayer()->appendChildRepr(newNode);
+ doc_interface->target.getSelection()->layers()->currentLayer()->updateRepr();
- if (object->updates)
- Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), 0, "Imported bitmap.");
+ if (doc_interface->updates)
+ Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), 0, "Imported bitmap.");
//g_free(uri);
return strdup(newNode->attribute("id"));
}
-gchar *document_interface_node(DocumentInterface *object, gchar *type, GError ** /*error*/)
+gchar *document_interface_node(DocumentInterface *doc_interface, gchar *type, GError ** /*error*/)
{
- SPDocument * doc = sp_desktop_document (object->desk);
+ SPDocument * doc = doc_interface->target.getDocument();
Inkscape::XML::Document *xml_doc = doc->getReprDoc();
Inkscape::XML::Node *newNode = xml_doc->createElement(type);
- object->desk->currentLayer()->appendChildRepr(newNode);
- object->desk->currentLayer()->updateRepr();
+ doc_interface->target.getSelection()->layers()->currentLayer()->appendChildRepr(newNode);
+ doc_interface->target.getSelection()->layers()->currentLayer()->updateRepr();
- if (object->updates) {
- Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), 0, (gchar *)"created empty node");
- //} else {
- //document_interface_pause_updates(object, error);
+ if (doc_interface->updates) {
+ Inkscape::DocumentUndo::done(doc, 0, (gchar *)"created empty node");
}
return strdup(newNode->attribute("id"));
}
/****************************************************************************
- ENVIORNMENT FUNCTIONS
+ ENVIRONMENT FUNCTIONS
****************************************************************************/
gdouble
-document_interface_document_get_width (DocumentInterface *object)
+document_interface_document_get_width (DocumentInterface *doc_interface)
{
- return sp_desktop_document(object->desk)->getWidth();
+ return doc_interface->target.getDocument()->getWidth().value("px");
}
gdouble
-document_interface_document_get_height (DocumentInterface *object)
+document_interface_document_get_height (DocumentInterface *doc_interface)
{
- return sp_desktop_document(object->desk)->getHeight();
+ return doc_interface->target.getDocument()->getHeight().value("px");
}
-gchar *document_interface_document_get_css(DocumentInterface *object, GError ** /*error*/)
+gchar *document_interface_document_get_css(DocumentInterface *doc_interface, GError ** error)
{
- SPCSSAttr *current = (object->desk)->current;
- return sp_repr_css_write_string(current);
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_val_if_fail(ensure_desktop_valid(desk, error), NULL);
+ SPCSSAttr *current = desk->current;
+ Glib::ustring str;
+ sp_repr_css_write_string(current, str);
+ return (str.empty() ? NULL : g_strdup (str.c_str()));
}
-gboolean document_interface_document_merge_css(DocumentInterface *object,
- gchar *stylestring, GError ** /*error*/)
+gboolean document_interface_document_merge_css(DocumentInterface *doc_interface,
+ gchar *stylestring, GError ** error)
{
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE);
SPCSSAttr * style = sp_repr_css_attr_new();
sp_repr_css_attr_add_from_string(style, stylestring);
- sp_desktop_set_style(object->desk, style);
+ sp_desktop_set_style(desk, style);
return TRUE;
}
-gboolean document_interface_document_set_css(DocumentInterface *object,
- gchar *stylestring, GError ** /*error*/)
+gboolean document_interface_document_set_css(DocumentInterface *doc_interface,
+ gchar *stylestring, GError ** error)
{
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE);
SPCSSAttr * style = sp_repr_css_attr_new();
sp_repr_css_attr_add_from_string (style, stylestring);
//Memory leak?
- object->desk->current = style;
+ desk->current = style;
return TRUE;
}
gboolean
-document_interface_document_resize_to_fit_selection (DocumentInterface *object,
+document_interface_document_resize_to_fit_selection (DocumentInterface *doc_interface,
GError **error)
{
- return dbus_call_verb (object, SP_VERB_FIT_CANVAS_TO_SELECTION, error);
+ return dbus_call_verb (doc_interface, SP_VERB_FIT_CANVAS_TO_SELECTION, error);
}
gboolean
-document_interface_document_set_display_area (DocumentInterface *object,
+document_interface_document_set_display_area (DocumentInterface *doc_interface,
double x0,
double y0,
double x1,
@@ -620,19 +602,25 @@ document_interface_document_set_display_area (DocumentInterface *object,
double border,
GError **error)
{
- object->desk->set_display_area (x0,
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE);
+ desk->set_display_area (x0,
y0,
x1,
y1,
border, false);
- return TRUE;
+ return TRUE;
}
GArray *
-document_interface_document_get_display_area (DocumentInterface *object)
+document_interface_document_get_display_area (DocumentInterface *doc_interface)
{
- Geom::Rect const d = object->desk->get_display_area();
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ if (!desk) {
+ return NULL;
+ }
+ Geom::Rect const d = desk->get_display_area();
GArray * dArr = g_array_new (TRUE, TRUE, sizeof(double));
@@ -654,10 +642,10 @@ document_interface_document_get_display_area (DocumentInterface *object)
****************************************************************************/
gboolean
-document_interface_set_attribute (DocumentInterface *object, char *shape,
+document_interface_set_attribute (DocumentInterface *doc_interface, char *shape,
char *attribute, char *newval, GError **error)
{
- Inkscape::XML::Node *newNode = get_repr_by_name(object->desk, shape, error);
+ Inkscape::XML::Node *newNode = get_repr_by_name(doc_interface->target.getDocument(), shape, error);
/* ALTERNATIVE (is this faster?)
Inkscape::XML::Node *newnode = sp_repr_lookup_name((doc->root)->repr, name);
@@ -673,11 +661,11 @@ document_interface_set_attribute (DocumentInterface *object, char *shape,
}
gboolean
-document_interface_set_int_attribute (DocumentInterface *object,
+document_interface_set_int_attribute (DocumentInterface *doc_interface,
char *shape, char *attribute,
int newval, GError **error)
{
- Inkscape::XML::Node *newNode = get_repr_by_name (object->desk, shape, error);
+ Inkscape::XML::Node *newNode = get_repr_by_name (doc_interface->target.getDocument(), shape, error);
if (!newNode)
return FALSE;
@@ -687,11 +675,11 @@ document_interface_set_int_attribute (DocumentInterface *object,
gboolean
-document_interface_set_double_attribute (DocumentInterface *object,
+document_interface_set_double_attribute (DocumentInterface *doc_interface,
char *shape, char *attribute,
double newval, GError **error)
{
- Inkscape::XML::Node *newNode = get_repr_by_name (object->desk, shape, error);
+ Inkscape::XML::Node *newNode = get_repr_by_name (doc_interface->target.getDocument(), shape, error);
if (!dbus_check_string (attribute, error, "New value string was empty."))
return FALSE;
@@ -703,10 +691,10 @@ document_interface_set_double_attribute (DocumentInterface *object,
}
gchar *
-document_interface_get_attribute (DocumentInterface *object, char *shape,
+document_interface_get_attribute (DocumentInterface *doc_interface, char *shape,
char *attribute, GError **error)
{
- Inkscape::XML::Node *newNode = get_repr_by_name(object->desk, shape, error);
+ Inkscape::XML::Node *newNode = get_repr_by_name(doc_interface->target.getDocument(), shape, error);
if (!dbus_check_string (attribute, error, "Attribute name empty."))
return NULL;
@@ -717,47 +705,47 @@ document_interface_get_attribute (DocumentInterface *object, char *shape,
}
gboolean
-document_interface_move (DocumentInterface *object, gchar *name, gdouble x,
+document_interface_move (DocumentInterface *doc_interface, gchar *name, gdouble x,
gdouble y, GError **error)
{
- const GSList *oldsel = selection_swap(object->desk, name, error);
+ const GSList *oldsel = selection_swap(doc_interface->target.getSelection(), name, error);
if (!oldsel)
return FALSE;
- sp_selection_move (object->desk, x, 0 - y);
- selection_restore(object->desk, oldsel);
+ sp_selection_move (doc_interface->target.getSelection(), x, 0 - y);
+ selection_restore(doc_interface->target.getSelection(), oldsel);
return TRUE;
}
gboolean
-document_interface_move_to (DocumentInterface *object, gchar *name, gdouble x,
+document_interface_move_to (DocumentInterface *doc_interface, gchar *name, gdouble x,
gdouble y, GError **error)
{
- const GSList *oldsel = selection_swap(object->desk, name, error);
+ const GSList *oldsel = selection_swap(doc_interface->target.getSelection(), name, error);
if (!oldsel)
return FALSE;
- Inkscape::Selection * sel = sp_desktop_selection(object->desk);
- sp_selection_move (object->desk, x - selection_get_center_x(sel),
+ Inkscape::Selection * sel = doc_interface->target.getSelection();
+ sp_selection_move (doc_interface->target.getSelection(), x - selection_get_center_x(sel),
0 - (y - selection_get_center_y(sel)));
- selection_restore(object->desk, oldsel);
+ selection_restore(doc_interface->target.getSelection(), oldsel);
return TRUE;
}
gboolean
-document_interface_object_to_path (DocumentInterface *object,
+document_interface_object_to_path (DocumentInterface *doc_interface,
char *shape, GError **error)
{
- const GSList *oldsel = selection_swap(object->desk, shape, error);
+ const GSList *oldsel = selection_swap(doc_interface->target.getSelection(), shape, error);
if (!oldsel)
return FALSE;
- dbus_call_verb (object, SP_VERB_OBJECT_TO_CURVE, error);
- selection_restore(object->desk, oldsel);
+ dbus_call_verb (doc_interface, SP_VERB_OBJECT_TO_CURVE, error);
+ selection_restore(doc_interface->target.getSelection(), oldsel);
return TRUE;
}
gchar *
-document_interface_get_path (DocumentInterface *object, char *pathname, GError **error)
+document_interface_get_path (DocumentInterface *doc_interface, char *pathname, GError **error)
{
- Inkscape::XML::Node *node = get_repr_by_name(object->desk, pathname, error);
+ Inkscape::XML::Node *node = get_repr_by_name(doc_interface->target.getDocument(), pathname, error);
if (!node)
return NULL;
@@ -771,30 +759,30 @@ document_interface_get_path (DocumentInterface *object, char *pathname, GError *
}
gboolean
-document_interface_transform (DocumentInterface *object, gchar *shape,
+document_interface_transform (DocumentInterface *doc_interface, gchar *shape,
gchar *transformstr, GError **error)
{
//FIXME: This should merge transformations.
gchar trans[] = "transform";
- document_interface_set_attribute (object, shape, trans, transformstr, error);
+ document_interface_set_attribute (doc_interface, shape, trans, transformstr, error);
return TRUE;
}
gchar *
-document_interface_get_css (DocumentInterface *object, gchar *shape,
+document_interface_get_css (DocumentInterface *doc_interface, gchar *shape,
GError **error)
{
gchar style[] = "style";
- return document_interface_get_attribute (object, shape, style, error);
+ return document_interface_get_attribute (doc_interface, shape, style, error);
}
gboolean
-document_interface_modify_css (DocumentInterface *object, gchar *shape,
+document_interface_modify_css (DocumentInterface *doc_interface, gchar *shape,
gchar *cssattrb, gchar *newval, GError **error)
{
// Doesn't like non-variable strings for some reason.
gchar style[] = "style";
- Inkscape::XML::Node *node = get_repr_by_name(object->desk, shape, error);
+ Inkscape::XML::Node *node = get_repr_by_name(doc_interface->target.getDocument(), shape, error);
if (!dbus_check_string (cssattrb, error, "Attribute string empty."))
return FALSE;
@@ -803,17 +791,19 @@ document_interface_modify_css (DocumentInterface *object, gchar *shape,
SPCSSAttr * oldstyle = sp_repr_css_attr (node, style);
sp_repr_css_set_property(oldstyle, cssattrb, newval);
- node->setAttribute (style, sp_repr_css_write_string (oldstyle), TRUE);
+ Glib::ustring str;
+ sp_repr_css_write_string (oldstyle, str);
+ node->setAttribute (style, str.c_str(), TRUE);
return TRUE;
}
gboolean
-document_interface_merge_css (DocumentInterface *object, gchar *shape,
+document_interface_merge_css (DocumentInterface *doc_interface, gchar *shape,
gchar *stylestring, GError **error)
{
gchar style[] = "style";
- Inkscape::XML::Node *node = get_repr_by_name(object->desk, shape, error);
+ Inkscape::XML::Node *node = get_repr_by_name(doc_interface->target.getDocument(), shape, error);
if (!dbus_check_string (stylestring, error, "Style string empty."))
return FALSE;
@@ -826,12 +816,15 @@ document_interface_merge_css (DocumentInterface *object, gchar *shape,
SPCSSAttr * oldstyle = sp_repr_css_attr (node, style);
sp_repr_css_merge(oldstyle, newstyle);
- node->setAttribute (style, sp_repr_css_write_string (oldstyle), TRUE);
+ Glib::ustring str;
+ sp_repr_css_write_string (oldstyle, str);
+ node->setAttribute (style, str.c_str(), TRUE);
+
return TRUE;
}
gboolean
-document_interface_set_color (DocumentInterface *object, gchar *shape,
+document_interface_set_color (DocumentInterface *doc_interface, gchar *shape,
int r, int g, int b, gboolean fill, GError **error)
{
gchar style[15];
@@ -847,29 +840,29 @@ document_interface_set_color (DocumentInterface *object, gchar *shape,
snprintf(style, 15, "stroke:#%.2x%.2x%.2x", r, g, b);
if (strcmp(shape, "document") == 0)
- return document_interface_document_merge_css (object, style, error);
+ return document_interface_document_merge_css (doc_interface, style, error);
- return document_interface_merge_css (object, shape, style, error);
+ return document_interface_merge_css (doc_interface, shape, style, error);
}
gboolean
-document_interface_move_to_layer (DocumentInterface *object, gchar *shape,
+document_interface_move_to_layer (DocumentInterface *doc_interface, gchar *shape,
gchar *layerstr, GError **error)
{
- const GSList *oldsel = selection_swap(object->desk, shape, error);
+ const GSList *oldsel = selection_swap(doc_interface->target.getSelection(), shape, error);
if (!oldsel)
return FALSE;
- document_interface_selection_move_to_layer(object, layerstr, error);
- selection_restore(object->desk, oldsel);
+ document_interface_selection_move_to_layer(doc_interface, layerstr, error);
+ selection_restore(doc_interface->target.getSelection(), oldsel);
return TRUE;
}
-GArray *document_interface_get_node_coordinates(DocumentInterface * /*object*/, gchar * /*shape*/)
+GArray *document_interface_get_node_coordinates(DocumentInterface * /*doc_interface*/, gchar * /*shape*/)
{
//FIXME: Needs lot's of work.
/*
- Inkscape::XML::Node *shapenode = get_repr_by_name (object->desk, shape, error);
+ Inkscape::XML::Node *shapenode = get_repr_by_name (doc_interface->target.getDocument(), shape, error);
if (shapenode == NULL || shapenode->attribute("d") == NULL) {
return FALSE;
}
@@ -884,10 +877,10 @@ GArray *document_interface_get_node_coordinates(DocumentInterface * /*object*/,
gboolean
-document_interface_set_text (DocumentInterface *object, gchar *name, gchar *text, GError **error)
+document_interface_set_text (DocumentInterface *doc_interface, gchar *name, gchar *text, GError **error)
{
- SPItem* text_obj=(SPItem* )get_object_by_name(object->desk, name, error);
+ SPItem* text_obj=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error);
//TODO verify object type
if (!text_obj)
return FALSE;
@@ -899,12 +892,12 @@ document_interface_set_text (DocumentInterface *object, gchar *name, gchar *text
gboolean
-document_interface_text_apply_style (DocumentInterface *object, gchar *name,
+document_interface_text_apply_style (DocumentInterface *doc_interface, gchar *name,
int start_pos, int end_pos, gchar *style, gchar *styleval,
GError **error)
{
- SPItem* text_obj=(SPItem* )get_object_by_name(object->desk, name, error);
+ SPItem* text_obj=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error);
//void sp_te_apply_style(SPItem *text, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPCSSAttr const *css)
//TODO verify object type
@@ -931,34 +924,40 @@ document_interface_text_apply_style (DocumentInterface *object, gchar *name,
****************************************************************************/
gboolean
-document_interface_save (DocumentInterface *object, GError **error)
+document_interface_save (DocumentInterface *doc_interface, GError **error)
{
- SPDocument * doc = sp_desktop_document(object->desk);
+ SPDocument * doc = doc_interface->target.getDocument();
printf("1: %s\n2: %s\n3: %s\n", doc->getURI(), doc->getBase(), doc->getName());
if (doc->getURI())
- return document_interface_save_as (object, doc->getURI(), error);
+ return document_interface_save_as (doc_interface, doc->getURI(), error);
return FALSE;
}
-gboolean document_interface_load(DocumentInterface *object,
+gboolean document_interface_load(DocumentInterface *doc_interface,
gchar *filename, GError ** /*error*/)
{
- desktop_ensure_active(object->desk);
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ if (desk) {
+ desktop_ensure_active(desk);
+ }
const Glib::ustring file(filename);
sp_file_open(file, NULL, TRUE, TRUE);
- if (object->updates) {
- Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), SP_VERB_FILE_OPEN, "Opened File");
+ if (doc_interface->updates) {
+ Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), SP_VERB_FILE_OPEN, "Opened File");
}
return TRUE;
}
gchar *
-document_interface_import (DocumentInterface *object,
+document_interface_import (DocumentInterface *doc_interface,
gchar *filename, GError **error)
{
- desktop_ensure_active (object->desk);
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ if (desk) {
+ desktop_ensure_active(desk);
+ }
const Glib::ustring file(filename);
- SPDocument * doc = sp_desktop_document(object->desk);
+ SPDocument * doc = doc_interface->target.getDocument();
SPObject *new_obj = NULL;
new_obj = file_import(doc, file, NULL);
@@ -966,10 +965,11 @@ document_interface_import (DocumentInterface *object,
}
gboolean
-document_interface_save_as (DocumentInterface *object,
+document_interface_save_as (DocumentInterface *doc_interface,
const gchar *filename, GError **error)
{
- SPDocument * doc = sp_desktop_document(object->desk);
+ // FIXME: Isn't there a verb we can use for this instead?
+ SPDocument * doc = doc_interface->target.getDocument();
#ifdef WITH_GNOME_VFS
const Glib::ustring file(filename);
return file_save_remote(doc, file, NULL, TRUE, TRUE);
@@ -982,18 +982,16 @@ document_interface_save_as (DocumentInterface *object,
Inkscape::Extension::save(NULL, doc, filename,
false, false, true, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS);
} catch (...) {
- //SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
+ // FIXME: catch ... is not usually a great idea, why is it needed here?
return false;
}
- //SP_ACTIVE_DESKTOP->event_log->rememberFileSave();
- //SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, "Document saved.");
return true;
}
-gboolean document_interface_mark_as_unmodified(DocumentInterface *object, GError ** /*error*/)
+gboolean document_interface_mark_as_unmodified(DocumentInterface *doc_interface, GError ** /*error*/)
{
- SPDocument * doc = sp_desktop_document(object->desk);
+ SPDocument * doc = doc_interface->target.getDocument();
if (doc) {
doc->modified_since_save = FALSE;
}
@@ -1002,9 +1000,9 @@ gboolean document_interface_mark_as_unmodified(DocumentInterface *object, GError
/*
gboolean
-document_interface_print_to_file (DocumentInterface *object, GError **error)
+document_interface_print_to_file (DocumentInterface *doc_interface, GError **error)
{
- SPDocument * doc = sp_desktop_document(object->desk);
+ SPDocument * doc = doc_interface->target.getDocument();
sp_print_document_to_file (doc, g_strdup("/home/soren/test.pdf"));
return TRUE;
@@ -1015,27 +1013,27 @@ document_interface_print_to_file (DocumentInterface *object, GError **error)
****************************************************************************/
gboolean
-document_interface_close (DocumentInterface *object, GError **error)
+document_interface_close (DocumentInterface *doc_interface, GError **error)
{
- return dbus_call_verb (object, SP_VERB_FILE_CLOSE_VIEW, error);
+ return dbus_call_verb (doc_interface, SP_VERB_FILE_CLOSE_VIEW, error);
}
gboolean
-document_interface_exit (DocumentInterface *object, GError **error)
+document_interface_exit (DocumentInterface *doc_interface, GError **error)
{
- return dbus_call_verb (object, SP_VERB_FILE_QUIT, error);
+ return dbus_call_verb (doc_interface, SP_VERB_FILE_QUIT, error);
}
gboolean
-document_interface_undo (DocumentInterface *object, GError **error)
+document_interface_undo (DocumentInterface *doc_interface, GError **error)
{
- return dbus_call_verb (object, SP_VERB_EDIT_UNDO, error);
+ return dbus_call_verb (doc_interface, SP_VERB_EDIT_UNDO, error);
}
gboolean
-document_interface_redo (DocumentInterface *object, GError **error)
+document_interface_redo (DocumentInterface *doc_interface, GError **error)
{
- return dbus_call_verb (object, SP_VERB_EDIT_REDO, error);
+ return dbus_call_verb (doc_interface, SP_VERB_EDIT_REDO, error);
}
@@ -1047,48 +1045,46 @@ document_interface_redo (DocumentInterface *object, GError **error)
Need to make sure it plays well with verbs because they are used so much.
****************************************************************************/
-void document_interface_pause_updates(DocumentInterface *object, GError ** /*error*/)
+void document_interface_pause_updates(DocumentInterface *doc_interface, GError ** error)
{
- object->updates = FALSE;
- object->desk->canvas->drawing_disabled = 1;
- //object->desk->canvas->need_redraw = 0;
- //object->desk->canvas->need_repick = 0;
- //sp_desktop_document(object->desk)->root->uflags = FALSE;
- //sp_desktop_document(object->desk)->root->mflags = FALSE;
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_if_fail(ensure_desktop_valid(desk, error));
+ doc_interface->updates = FALSE;
+ desk->canvas->drawing_disabled = 1;
}
-void document_interface_resume_updates(DocumentInterface *object, GError ** /*error*/)
+void document_interface_resume_updates(DocumentInterface *doc_interface, GError ** error)
{
- object->updates = TRUE;
- object->desk->canvas->drawing_disabled = 0;
- //object->desk->canvas->need_redraw = 1;
- //object->desk->canvas->need_repick = 1;
- //sp_desktop_document(object->desk)->root->uflags = TRUE;
- //sp_desktop_document(object->desk)->root->mflags = TRUE;
- //sp_desktop_document(object->desk)->_updateDocument();
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_if_fail(ensure_desktop_valid(desk, error));
+ doc_interface->updates = TRUE;
+ desk->canvas->drawing_disabled = 0;
//FIXME: use better verb than rect.
- Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions");
+ Inkscape::DocumentUndo::done(doc_interface->target.getDocument(), SP_VERB_CONTEXT_RECT, "Multiple actions");
}
-void document_interface_update(DocumentInterface *object, GError ** /*error*/)
+void document_interface_update(DocumentInterface *doc_interface, GError ** error)
{
- sp_desktop_document(object->desk)->getRoot()->uflags = TRUE;
- sp_desktop_document(object->desk)->getRoot()->mflags = TRUE;
- object->desk->enableInteraction();
- sp_desktop_document(object->desk)->_updateDocument();
- object->desk->disableInteraction();
- sp_desktop_document(object->desk)->getRoot()->uflags = FALSE;
- sp_desktop_document(object->desk)->getRoot()->mflags = FALSE;
- //Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions");
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_if_fail(ensure_desktop_valid(desk, error));
+ SPDocument *doc = doc_interface->target.getDocument();
+ doc->getRoot()->uflags = TRUE;
+ doc->getRoot()->mflags = TRUE;
+ desk->enableInteraction();
+ doc->_updateDocument();
+ desk->disableInteraction();
+ doc->getRoot()->uflags = FALSE;
+ doc->getRoot()->mflags = FALSE;
+ //Inkscape::DocumentUndo::done(doc, SP_VERB_CONTEXT_RECT, "Multiple actions");
}
/****************************************************************************
SELECTION FUNCTIONS FIXME: use call_verb where appropriate (once update system is tested.)
****************************************************************************/
-gboolean document_interface_selection_get(DocumentInterface *object, char ***out, GError ** /*error*/)
+gboolean document_interface_selection_get(DocumentInterface *doc_interface, char ***out, GError ** /*error*/)
{
- Inkscape::Selection * sel = sp_desktop_selection(object->desk);
+ Inkscape::Selection * sel = doc_interface->target.getSelection();
GSList const *oldsel = sel->list();
int size = g_slist_length((GSList *) oldsel);
@@ -1106,85 +1102,82 @@ gboolean document_interface_selection_get(DocumentInterface *object, char ***out
}
gboolean
-document_interface_selection_add (DocumentInterface *object, char *name, GError **error)
+document_interface_selection_add (DocumentInterface *doc_interface, char *name, GError **error)
{
- SPObject * obj = get_object_by_name(object->desk, name, error);
+ SPObject * obj = get_object_by_name(doc_interface->target.getDocument(), name, error);
if (!obj)
return FALSE;
- Inkscape::Selection *selection = sp_desktop_selection(object->desk);
+ Inkscape::Selection *selection = doc_interface->target.getSelection();
selection->add(obj);
return TRUE;
}
gboolean
-document_interface_selection_add_list (DocumentInterface *object,
+document_interface_selection_add_list (DocumentInterface *doc_interface,
char **names, GError **error)
{
int i;
for (i=0;names[i] != NULL;i++) {
- document_interface_selection_add(object, names[i], error);
+ document_interface_selection_add(doc_interface, names[i], error);
}
return TRUE;
}
-gboolean document_interface_selection_set(DocumentInterface *object, char *name, GError ** /*error*/)
+gboolean document_interface_selection_set(DocumentInterface *doc_interface, char *name, GError ** /*error*/)
{
- SPDocument * doc = sp_desktop_document(object->desk);
- Inkscape::Selection *selection = sp_desktop_selection(object->desk);
+ SPDocument * doc = doc_interface->target.getDocument();
+ Inkscape::Selection *selection = doc_interface->target.getSelection();
selection->set(doc->getObjectById(name));
return TRUE;
}
gboolean
-document_interface_selection_set_list (DocumentInterface *object,
+document_interface_selection_set_list (DocumentInterface *doc_interface,
gchar **names, GError **error)
{
- sp_desktop_selection(object->desk)->clear();
+ doc_interface->target.getSelection()->clear();
int i;
for (i=0;names[i] != NULL;i++) {
- document_interface_selection_add(object, names[i], error);
+ document_interface_selection_add(doc_interface, names[i], error);
}
return TRUE;
}
-gboolean document_interface_selection_rotate(DocumentInterface *object, int angle, GError ** /*error*/)
+gboolean document_interface_selection_rotate(DocumentInterface *doc_interface, int angle, GError ** /*error*/)
{
- Inkscape::Selection *selection = sp_desktop_selection(object->desk);
+ Inkscape::Selection *selection = doc_interface->target.getSelection();
sp_selection_rotate(selection, angle);
return TRUE;
}
gboolean
-document_interface_selection_delete (DocumentInterface *object, GError **error)
+document_interface_selection_delete (DocumentInterface *doc_interface, GError **error)
{
- //sp_selection_delete (object->desk);
- return dbus_call_verb (object, SP_VERB_EDIT_DELETE, error);
+ return dbus_call_verb (doc_interface, SP_VERB_EDIT_DELETE, error);
}
-gboolean document_interface_selection_clear(DocumentInterface *object, GError ** /*error*/)
+gboolean document_interface_selection_clear(DocumentInterface *doc_interface, GError ** /*error*/)
{
- sp_desktop_selection(object->desk)->clear();
+ doc_interface->target.getSelection()->clear();
return TRUE;
}
gboolean
-document_interface_select_all (DocumentInterface *object, GError **error)
+document_interface_select_all (DocumentInterface *doc_interface, GError **error)
{
- //sp_edit_select_all (object->desk);
- return dbus_call_verb (object, SP_VERB_EDIT_SELECT_ALL, error);
+ return dbus_call_verb (doc_interface, SP_VERB_EDIT_SELECT_ALL, error);
}
gboolean
-document_interface_select_all_in_all_layers(DocumentInterface *object,
+document_interface_select_all_in_all_layers(DocumentInterface *doc_interface,
GError **error)
{
- //sp_edit_select_all_in_all_layers (object->desk);
- return dbus_call_verb (object, SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS, error);
+ return dbus_call_verb (doc_interface, SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS, error);
}
-gboolean document_interface_selection_box(DocumentInterface * /*object*/, int /*x*/, int /*y*/,
+gboolean document_interface_selection_box(DocumentInterface * /*doc_interface*/, int /*x*/, int /*y*/,
int /*x2*/, int /*y2*/, gboolean /*replace*/,
GError ** /*error*/)
{
@@ -1193,63 +1186,49 @@ gboolean document_interface_selection_box(DocumentInterface * /*object*/, int /*
}
gboolean
-document_interface_selection_invert (DocumentInterface *object, GError **error)
+document_interface_selection_invert (DocumentInterface *doc_interface, GError **error)
{
- //sp_edit_invert (object->desk);
- return dbus_call_verb (object, SP_VERB_EDIT_INVERT, error);
+ return dbus_call_verb (doc_interface, SP_VERB_EDIT_INVERT, error);
}
gboolean
-document_interface_selection_group (DocumentInterface *object, GError **error)
+document_interface_selection_group (DocumentInterface *doc_interface, GError **error)
{
- //sp_selection_group (object->desk);
- return dbus_call_verb (object, SP_VERB_SELECTION_GROUP, error);
+ return dbus_call_verb (doc_interface, SP_VERB_SELECTION_GROUP, error);
}
gboolean
-document_interface_selection_ungroup (DocumentInterface *object, GError **error)
+document_interface_selection_ungroup (DocumentInterface *doc_interface, GError **error)
{
- //sp_selection_ungroup (object->desk);
- return dbus_call_verb (object, SP_VERB_SELECTION_UNGROUP, error);
+ return dbus_call_verb (doc_interface, SP_VERB_SELECTION_UNGROUP, error);
}
gboolean
-document_interface_selection_cut (DocumentInterface *object, GError **error)
+document_interface_selection_cut (DocumentInterface *doc_interface, GError **error)
{
- //desktop_ensure_active (object->desk);
- //sp_selection_cut (object->desk);
- return dbus_call_verb (object, SP_VERB_EDIT_CUT, error);
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE);
+ return dbus_call_verb (doc_interface, SP_VERB_EDIT_CUT, error);
}
gboolean
-document_interface_selection_copy (DocumentInterface *object, GError **error)
+document_interface_selection_copy (DocumentInterface *doc_interface, GError **error)
{
- //desktop_ensure_active (object->desk);
- //sp_selection_copy ();
- return dbus_call_verb (object, SP_VERB_EDIT_COPY, error);
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE);
+ return dbus_call_verb (doc_interface, SP_VERB_EDIT_COPY, error);
}
-/*
-gboolean
-document_interface_selection_paste (DocumentInterface *object, GError **error)
-{
- desktop_ensure_active (object->desk);
- if (!object->updates)
- document_interface_pause_updates (object, error);
- sp_selection_paste (object->desk, TRUE);
- if (!object->updates)
- document_interface_pause_updates (object, error);
- return TRUE;
- //return dbus_call_verb (object, SP_VERB_EDIT_PASTE, error);
-}
-*/
+
gboolean
-document_interface_selection_paste (DocumentInterface *object, GError **error)
+document_interface_selection_paste (DocumentInterface *doc_interface, GError **error)
{
- return dbus_call_verb (object, SP_VERB_EDIT_PASTE, error);
+ SPDesktop *desk = doc_interface->target.getDesktop();
+ g_return_val_if_fail(ensure_desktop_valid(desk, error), FALSE);
+ return dbus_call_verb (doc_interface, SP_VERB_EDIT_PASTE, error);
}
-gboolean document_interface_selection_scale(DocumentInterface *object, gdouble grow, GError ** /*error*/)
+gboolean document_interface_selection_scale(DocumentInterface *doc_interface, gdouble grow, GError ** /*error*/)
{
- Inkscape::Selection *selection = sp_desktop_selection(object->desk);
+ Inkscape::Selection *selection = doc_interface->target.getSelection();
if (!selection)
{
return FALSE;
@@ -1258,15 +1237,15 @@ gboolean document_interface_selection_scale(DocumentInterface *object, gdouble g
return TRUE;
}
-gboolean document_interface_selection_move(DocumentInterface *object, gdouble x, gdouble y, GError ** /*error*/)
+gboolean document_interface_selection_move(DocumentInterface *doc_interface, gdouble x, gdouble y, GError ** /*error*/)
{
- sp_selection_move(object->desk, x, 0 - y); //switching coordinate systems.
+ sp_selection_move(doc_interface->target.getSelection(), x, 0 - y); //switching coordinate systems.
return TRUE;
}
-gboolean document_interface_selection_move_to(DocumentInterface *object, gdouble x, gdouble y, GError ** /*error*/)
+gboolean document_interface_selection_move_to(DocumentInterface *doc_interface, gdouble x, gdouble y, GError ** /*error*/)
{
- Inkscape::Selection * sel = sp_desktop_selection(object->desk);
+ Inkscape::Selection * sel = doc_interface->target.getSelection();
Geom::OptRect sel_bbox = sel->visualBounds();
if (sel_bbox) {
@@ -1280,18 +1259,19 @@ gboolean document_interface_selection_move_to(DocumentInterface *object, gdouble
// This needs to use lower level cut_impl and paste_impl (messy)
// See the built-in sp_selection_to_next_layer and duplicate.
gboolean
-document_interface_selection_move_to_layer (DocumentInterface *object,
+document_interface_selection_move_to_layer (DocumentInterface *doc_interface,
gchar *layerstr, GError **error)
{
- SPDesktop * dt = object->desk;
+ SPDesktop *dt = doc_interface->target.getDesktop();
+ g_return_val_if_fail(ensure_desktop_valid(dt, error), FALSE);
- Inkscape::Selection *selection = sp_desktop_selection(dt);
+ Inkscape::Selection *selection = doc_interface->target.getSelection();
// check if something is selected
if (selection->isEmpty())
return FALSE;
- SPObject *next = get_object_by_name(object->desk, layerstr, error);
+ SPObject *next = get_object_by_name(doc_interface->target.getDocument(), layerstr, error);
if (!next)
return FALSE;
@@ -1300,7 +1280,7 @@ document_interface_selection_move_to_layer (DocumentInterface *object,
sp_selection_cut(dt);
- dt->setCurrentLayer(next);
+ doc_interface->target.getSelection()->layers()->setCurrentLayer(next);
sp_selection_paste(dt, TRUE);
}
@@ -1308,9 +1288,9 @@ document_interface_selection_move_to_layer (DocumentInterface *object,
}
GArray *
-document_interface_selection_get_center (DocumentInterface *object)
+document_interface_selection_get_center (DocumentInterface *doc_interface)
{
- Inkscape::Selection * sel = sp_desktop_selection(object->desk);
+ Inkscape::Selection * sel = doc_interface->target.getSelection();
if (sel)
{
@@ -1327,52 +1307,46 @@ document_interface_selection_get_center (DocumentInterface *object)
}
gboolean
-document_interface_selection_to_path (DocumentInterface *object, GError **error)
+document_interface_selection_to_path (DocumentInterface *doc_interface, GError **error)
{
- return dbus_call_verb (object, SP_VERB_OBJECT_TO_CURVE, error);
+ return dbus_call_verb (doc_interface, SP_VERB_OBJECT_TO_CURVE, error);
}
-gchar *
-document_interface_selection_combine (DocumentInterface *object, gchar *cmd,
+gboolean
+document_interface_selection_combine (DocumentInterface *doc_interface, gchar *cmd, char ***newpaths,
GError **error)
{
if (strcmp(cmd, "union") == 0)
- dbus_call_verb (object, SP_VERB_SELECTION_UNION, error);
+ dbus_call_verb (doc_interface, SP_VERB_SELECTION_UNION, error);
else if (strcmp(cmd, "intersection") == 0)
- dbus_call_verb (object, SP_VERB_SELECTION_INTERSECT, error);
+ dbus_call_verb (doc_interface, SP_VERB_SELECTION_INTERSECT, error);
else if (strcmp(cmd, "difference") == 0)
- dbus_call_verb (object, SP_VERB_SELECTION_DIFF, error);
+ dbus_call_verb (doc_interface, SP_VERB_SELECTION_DIFF, error);
else if (strcmp(cmd, "exclusion") == 0)
- dbus_call_verb (object, SP_VERB_SELECTION_SYMDIFF, error);
- else
- return NULL;
-
- if (sp_desktop_selection(object->desk)->singleRepr() != NULL)
- return g_strdup((sp_desktop_selection(object->desk)->singleRepr())->attribute("id"));
- return NULL;
-}
-
-gboolean
-document_interface_selection_divide (DocumentInterface *object, char ***out, GError **error)
-{
- dbus_call_verb (object, SP_VERB_SELECTION_CUT, error);
+ dbus_call_verb (doc_interface, SP_VERB_SELECTION_SYMDIFF, error);
+ else if (strcmp(cmd, "division") == 0)
+ dbus_call_verb (doc_interface, SP_VERB_SELECTION_CUT, error);
+ else {
+ g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OTHER, "Operation command not recognised");
+ return FALSE;
+ }
- return document_interface_selection_get (object, out, error);
+ return document_interface_selection_get (doc_interface, newpaths, error);
}
gboolean
-document_interface_selection_change_level (DocumentInterface *object, gchar *cmd,
+document_interface_selection_change_level (DocumentInterface *doc_interface, gchar *cmd,
GError **error)
{
if (strcmp(cmd, "raise") == 0)
- return dbus_call_verb (object, SP_VERB_SELECTION_RAISE, error);
+ return dbus_call_verb (doc_interface, SP_VERB_SELECTION_RAISE, error);
if (strcmp(cmd, "lower") == 0)
- return dbus_call_verb (object, SP_VERB_SELECTION_LOWER, error);
+ return dbus_call_verb (doc_interface, SP_VERB_SELECTION_LOWER, error);
if ((strcmp(cmd, "to_top") == 0) || (strcmp(cmd, "to_front") == 0))
- return dbus_call_verb (object, SP_VERB_SELECTION_TO_FRONT, error);
+ return dbus_call_verb (doc_interface, SP_VERB_SELECTION_TO_FRONT, error);
if ((strcmp(cmd, "to_bottom") == 0) || (strcmp(cmd, "to_back") == 0))
- return dbus_call_verb (object, SP_VERB_SELECTION_TO_BACK, error);
+ return dbus_call_verb (doc_interface, SP_VERB_SELECTION_TO_BACK, error);
return TRUE;
}
@@ -1380,58 +1354,58 @@ document_interface_selection_change_level (DocumentInterface *object, gchar *cmd
LAYER FUNCTIONS
****************************************************************************/
-gchar *document_interface_layer_new(DocumentInterface *object, GError ** /*error*/)
+gchar *document_interface_layer_new(DocumentInterface *doc_interface, GError ** /*error*/)
{
- SPDesktop * dt = object->desk;
- SPObject *new_layer = Inkscape::create_layer(dt->currentRoot(), dt->currentLayer(), Inkscape::LPOS_BELOW);
- dt->setCurrentLayer(new_layer);
+ Inkscape::LayerModel * layers = doc_interface->target.getSelection()->layers();
+ SPObject *new_layer = Inkscape::create_layer(layers->currentRoot(), layers->currentLayer(), Inkscape::LPOS_BELOW);
+ layers->setCurrentLayer(new_layer);
return g_strdup(get_name_from_object(new_layer));
}
gboolean
-document_interface_layer_set (DocumentInterface *object,
+document_interface_layer_set (DocumentInterface *doc_interface,
gchar *layerstr, GError **error)
{
- SPObject * obj = get_object_by_name (object->desk, layerstr, error);
+ SPObject * obj = get_object_by_name (doc_interface->target.getDocument(), layerstr, error);
if (!obj)
return FALSE;
- object->desk->setCurrentLayer (obj);
+ doc_interface->target.getSelection()->layers()->setCurrentLayer (obj);
return TRUE;
}
-gchar **document_interface_layer_get_all(DocumentInterface * /*object*/)
+gchar **document_interface_layer_get_all(DocumentInterface * /*doc_interface*/)
{
//FIXME: implement.
return NULL;
}
gboolean
-document_interface_layer_change_level (DocumentInterface *object,
+document_interface_layer_change_level (DocumentInterface *doc_interface,
gchar *cmd, GError **error)
{
if (strcmp(cmd, "raise") == 0)
- return dbus_call_verb (object, SP_VERB_LAYER_RAISE, error);
+ return dbus_call_verb (doc_interface, SP_VERB_LAYER_RAISE, error);
if (strcmp(cmd, "lower") == 0)
- return dbus_call_verb (object, SP_VERB_LAYER_LOWER, error);
+ return dbus_call_verb (doc_interface, SP_VERB_LAYER_LOWER, error);
if ((strcmp(cmd, "to_top") == 0) || (strcmp(cmd, "to_front") == 0))
- return dbus_call_verb (object, SP_VERB_LAYER_TO_TOP, error);
+ return dbus_call_verb (doc_interface, SP_VERB_LAYER_TO_TOP, error);
if ((strcmp(cmd, "to_bottom") == 0) || (strcmp(cmd, "to_back") == 0))
- return dbus_call_verb (object, SP_VERB_LAYER_TO_BOTTOM, error);
+ return dbus_call_verb (doc_interface, SP_VERB_LAYER_TO_BOTTOM, error);
return TRUE;
}
gboolean
-document_interface_layer_next (DocumentInterface *object, GError **error)
+document_interface_layer_next (DocumentInterface *doc_interface, GError **error)
{
- return dbus_call_verb (object, SP_VERB_LAYER_NEXT, error);
+ return dbus_call_verb (doc_interface, SP_VERB_LAYER_NEXT, error);
}
gboolean
-document_interface_layer_previous (DocumentInterface *object, GError **error)
+document_interface_layer_previous (DocumentInterface *doc_interface, GError **error)
{
- return dbus_call_verb (object, SP_VERB_LAYER_PREV, error);
+ return dbus_call_verb (doc_interface, SP_VERB_LAYER_PREV, error);
}
@@ -1441,7 +1415,6 @@ document_interface_layer_previous (DocumentInterface *object, GError **error)
DocumentInterface *fugly;
gboolean dbus_send_ping (SPDesktop* desk, SPItem *item)
{
- //DocumentInterface *obj;
if (!item) return TRUE;
g_signal_emit (desk->dbus_document_interface, signals[OBJECT_MOVED_SIGNAL], 0, item->getId());
return TRUE;
@@ -1451,9 +1424,9 @@ gboolean dbus_send_ping (SPDesktop* desk, SPItem *item)
gboolean
-document_interface_get_children (DocumentInterface *object, char *name, char ***out, GError **error)
+document_interface_get_children (DocumentInterface *doc_interface, char *name, char ***out, GError **error)
{
- SPItem* parent=(SPItem* )get_object_by_name(object->desk, name, error);
+ SPItem* parent=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error);
GSList const *children = parent->childList(false);
@@ -1474,9 +1447,9 @@ document_interface_get_children (DocumentInterface *object, char *name, char **
gchar*
-document_interface_get_parent (DocumentInterface *object, char *name, GError **error)
+document_interface_get_parent (DocumentInterface *doc_interface, char *name, GError **error)
{
- SPItem* node=(SPItem* )get_object_by_name(object->desk, name, error);
+ SPItem* node=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error);
SPObject* parent=node->parent;
@@ -1487,8 +1460,8 @@ document_interface_get_parent (DocumentInterface *object, char *name, GError **
#if 0
//just pseudo code
gboolean
-document_interface_get_xpath (DocumentInterface *object, char *xpath_expression, char ***out, GError **error){
- SPDocument * doc = sp_desktop_document (object->desk);
+document_interface_get_xpath (DocumentInterface *doc_interface, char *xpath_expression, char ***out, GError **error){
+ SPDocument * doc = doc_interface->target.getDocument();
Inkscape::XML::Document *repr = doc->getReprDoc();
xmlXPathObjectPtr xpathObj;
diff --git a/src/extension/dbus/document-interface.h b/src/extension/dbus/document-interface.h
index e7e55cb7d..27460de52 100644
--- a/src/extension/dbus/document-interface.h
+++ b/src/extension/dbus/document-interface.h
@@ -30,9 +30,10 @@
#undef DBUS_MESSAGE_TYPE_ERROR
#undef DBUS_MESSAGE_TYPE_SIGNAL
-#include "desktop.h"
+#include "helper/action-context.h"
-#define DBUS_DOCUMENT_INTERFACE_PATH "/org/inkscape/document"
+class SPDesktop;
+class SPItem;
#define TYPE_DOCUMENT_INTERFACE (document_interface_get_type ())
#define DOCUMENT_INTERFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TYPE_DOCUMENT_INTERFACE, DocumentInterface))
@@ -47,8 +48,8 @@ typedef struct _DocumentInterface DocumentInterface;
typedef struct _DocumentInterfaceClass DocumentInterfaceClass;
struct _DocumentInterface {
- GObject parent;
- SPDesktop *desk;
+ GObject parent;
+ Inkscape::ActionContext target; ///< stores information about which document, selection, desktop etc this interface is linked to
gboolean updates;
};
@@ -56,19 +57,7 @@ struct _DocumentInterfaceClass {
GObjectClass parent;
};
-typedef enum
-{
- INKSCAPE_ERROR_SELECTION,
- INKSCAPE_ERROR_OBJECT,
- INKSCAPE_ERROR_VERB,
- INKSCAPE_ERROR_OTHER
-} InkscapeError;
-#define INKSCAPE_ERROR (inkscape_error_quark ())
-#define INKSCAPE_TYPE_ERROR (inkscape_error_get_type ())
-
-GQuark inkscape_error_quark (void);
-GType inkscape_error_get_type (void);
struct DBUSPoint {
int x;
@@ -79,10 +68,10 @@ struct DBUSPoint {
****************************************************************************/
gboolean
-document_interface_delete_all (DocumentInterface *object, GError **error);
+document_interface_delete_all (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_call_verb (DocumentInterface *object,
+document_interface_call_verb (DocumentInterface *doc_interface,
gchar *verbid, GError **error);
/****************************************************************************
@@ -90,48 +79,48 @@ document_interface_call_verb (DocumentInterface *object,
****************************************************************************/
gchar*
-document_interface_rectangle (DocumentInterface *object, int x, int y,
+document_interface_rectangle (DocumentInterface *doc_interface, int x, int y,
int width, int height, GError **error);
gchar*
-document_interface_ellipse (DocumentInterface *object, int x, int y,
+document_interface_ellipse (DocumentInterface *doc_interface, int x, int y,
int width, int height, GError **error);
gchar*
-document_interface_polygon (DocumentInterface *object, int cx, int cy,
+document_interface_polygon (DocumentInterface *doc_interface, int cx, int cy,
int radius, int rotation, int sides,
GError **error);
gchar*
-document_interface_star (DocumentInterface *object, int cx, int cy,
+document_interface_star (DocumentInterface *doc_interface, int cx, int cy,
int r1, int r2, int sides, gdouble rounded,
gdouble arg1, gdouble arg2, GError **error);
gchar*
-document_interface_spiral (DocumentInterface *object, int cx, int cy,
+document_interface_spiral (DocumentInterface *doc_interface, int cx, int cy,
int r, int revolutions, GError **error);
gchar*
-document_interface_line (DocumentInterface *object, int x, int y,
+document_interface_line (DocumentInterface *doc_interface, int x, int y,
int x2, int y2, GError **error);
gchar*
-document_interface_text (DocumentInterface *object, int x, int y,
+document_interface_text (DocumentInterface *doc_interface, int x, int y,
gchar *text, GError **error);
gboolean
-document_interface_set_text (DocumentInterface *object, gchar *name,
+document_interface_set_text (DocumentInterface *doc_interface, gchar *name,
gchar *text, GError **error);
gboolean
-document_interface_text_apply_style (DocumentInterface *object, gchar *name,
+document_interface_text_apply_style (DocumentInterface *doc_interface, gchar *name,
int start_pos, int end_pos, gchar *style, gchar *styleval,
GError **error);
gchar *
-document_interface_image (DocumentInterface *object, int x, int y,
+document_interface_image (DocumentInterface *doc_interface, int x, int y,
gchar *filename, GError **error);
gchar*
-document_interface_node (DocumentInterface *object, gchar *svgtype,
+document_interface_node (DocumentInterface *doc_interface, gchar *svgtype,
GError **error);
@@ -139,27 +128,27 @@ document_interface_node (DocumentInterface *object, gchar *svgtype,
ENVIORNMENT FUNCTIONS
****************************************************************************/
gdouble
-document_interface_document_get_width (DocumentInterface *object);
+document_interface_document_get_width (DocumentInterface *doc_interface);
gdouble
-document_interface_document_get_height (DocumentInterface *object);
+document_interface_document_get_height (DocumentInterface *doc_interface);
gchar *
-document_interface_document_get_css (DocumentInterface *object, GError **error);
+document_interface_document_get_css (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_document_merge_css (DocumentInterface *object,
+document_interface_document_merge_css (DocumentInterface *doc_interface,
gchar *stylestring, GError **error);
gboolean
-document_interface_document_set_css (DocumentInterface *object,
+document_interface_document_set_css (DocumentInterface *doc_interface,
gchar *stylestring, GError **error);
gboolean
-document_interface_document_resize_to_fit_selection (DocumentInterface *object,
+document_interface_document_resize_to_fit_selection (DocumentInterface *doc_interface,
GError **error);
gboolean
-document_interface_document_set_display_area (DocumentInterface *object,
+document_interface_document_set_display_area (DocumentInterface *doc_interface,
double x0,
double y0,
double x1,
@@ -167,95 +156,95 @@ document_interface_document_set_display_area (DocumentInterface *object,
double border,
GError **error);
GArray *
-document_interface_document_get_display_area (DocumentInterface *object);
+document_interface_document_get_display_area (DocumentInterface *doc_interface);
/****************************************************************************
OBJECT FUNCTIONS
****************************************************************************/
gboolean
-document_interface_set_attribute (DocumentInterface *object,
+document_interface_set_attribute (DocumentInterface *doc_interface,
char *shape, char *attribute,
char *newval, GError **error);
gboolean
-document_interface_set_int_attribute (DocumentInterface *object,
+document_interface_set_int_attribute (DocumentInterface *doc_interface,
char *shape, char *attribute,
int newval, GError **error);
gboolean
-document_interface_set_double_attribute (DocumentInterface *object,
+document_interface_set_double_attribute (DocumentInterface *doc_interface,
char *shape, char *attribute,
double newval, GError **error);
gchar *
-document_interface_get_attribute (DocumentInterface *object,
+document_interface_get_attribute (DocumentInterface *doc_interface,
char *shape, char *attribute, GError **error);
gboolean
-document_interface_move (DocumentInterface *object, gchar *name,
+document_interface_move (DocumentInterface *doc_interface, gchar *name,
gdouble x, gdouble y, GError **error);
gboolean
-document_interface_move_to (DocumentInterface *object, gchar *name,
+document_interface_move_to (DocumentInterface *doc_interface, gchar *name,
gdouble x, gdouble y, GError **error);
gboolean
-document_interface_object_to_path (DocumentInterface *object,
+document_interface_object_to_path (DocumentInterface *doc_interface,
char *shape, GError **error);
gchar *
-document_interface_get_path (DocumentInterface *object,
+document_interface_get_path (DocumentInterface *doc_interface,
char *pathname, GError **error);
gboolean
-document_interface_transform (DocumentInterface *object, gchar *shape,
+document_interface_transform (DocumentInterface *doc_interface, gchar *shape,
gchar *transformstr, GError **error);
gchar *
-document_interface_get_css (DocumentInterface *object, gchar *shape,
+document_interface_get_css (DocumentInterface *doc_interface, gchar *shape,
GError **error);
gboolean
-document_interface_modify_css (DocumentInterface *object, gchar *shape,
+document_interface_modify_css (DocumentInterface *doc_interface, gchar *shape,
gchar *cssattrb, gchar *newval, GError **error);
gboolean
-document_interface_merge_css (DocumentInterface *object, gchar *shape,
+document_interface_merge_css (DocumentInterface *doc_interface, gchar *shape,
gchar *stylestring, GError **error);
gboolean
-document_interface_set_color (DocumentInterface *object, gchar *shape,
+document_interface_set_color (DocumentInterface *doc_interface, gchar *shape,
int r, int g, int b, gboolean fill, GError **error);
gboolean
-document_interface_move_to_layer (DocumentInterface *object, gchar *shape,
+document_interface_move_to_layer (DocumentInterface *doc_interface, gchar *shape,
gchar *layerstr, GError **error);
GArray *
-document_interface_get_node_coordinates (DocumentInterface *object, gchar *shape);
+document_interface_get_node_coordinates (DocumentInterface *doc_interface, gchar *shape);
/****************************************************************************
FILE I/O FUNCTIONS
****************************************************************************/
gboolean
-document_interface_save (DocumentInterface *object, GError **error);
+document_interface_save (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_load (DocumentInterface *object,
+document_interface_load (DocumentInterface *doc_interface,
gchar *filename, GError **error);
gboolean
-document_interface_save_as (DocumentInterface *object,
+document_interface_save_as (DocumentInterface *doc_interface,
const gchar *filename, GError **error);
gboolean
-document_interface_mark_as_unmodified (DocumentInterface *object, GError **error);
+document_interface_mark_as_unmodified (DocumentInterface *doc_interface, GError **error);
/*
gboolean
-document_interface_print_to_file (DocumentInterface *object, GError **error);
+document_interface_print_to_file (DocumentInterface *doc_interface, GError **error);
*/
/****************************************************************************
@@ -263,125 +252,120 @@ document_interface_print_to_file (DocumentInterface *object, GError **error);
****************************************************************************/
gboolean
-document_interface_close (DocumentInterface *object, GError **error);
+document_interface_close (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_exit (DocumentInterface *object, GError **error);
+document_interface_exit (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_undo (DocumentInterface *object, GError **error);
+document_interface_undo (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_redo (DocumentInterface *object, GError **error);
+document_interface_redo (DocumentInterface *doc_interface, GError **error);
/****************************************************************************
UPDATE FUNCTIONS
****************************************************************************/
void
-document_interface_pause_updates (DocumentInterface *object, GError **error);
+document_interface_pause_updates (DocumentInterface *doc_interface, GError **error);
void
-document_interface_resume_updates (DocumentInterface *object, GError **error);
+document_interface_resume_updates (DocumentInterface *doc_interface, GError **error);
void
-document_interface_update (DocumentInterface *object, GError **error);
+document_interface_update (DocumentInterface *doc_interface, GError **error);
/****************************************************************************
SELECTION FUNCTIONS
****************************************************************************/
gboolean
-document_interface_selection_get (DocumentInterface *object, char ***out, GError **error);
+document_interface_selection_get (DocumentInterface *doc_interface, char ***out, GError **error);
gboolean
-document_interface_selection_add (DocumentInterface *object,
+document_interface_selection_add (DocumentInterface *doc_interface,
char *name, GError **error);
gboolean
-document_interface_selection_add_list (DocumentInterface *object,
+document_interface_selection_add_list (DocumentInterface *doc_interface,
char **names, GError **error);
gboolean
-document_interface_selection_set (DocumentInterface *object,
+document_interface_selection_set (DocumentInterface *doc_interface,
char *name, GError **error);
gboolean
-document_interface_selection_set_list (DocumentInterface *object,
+document_interface_selection_set_list (DocumentInterface *doc_interface,
gchar **names, GError **error);
gboolean
-document_interface_selection_rotate (DocumentInterface *object,
+document_interface_selection_rotate (DocumentInterface *doc_interface,
int angle, GError **error);
gboolean
-document_interface_selection_delete(DocumentInterface *object, GError **error);
+document_interface_selection_delete(DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_selection_clear(DocumentInterface *object, GError **error);
+document_interface_selection_clear(DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_select_all(DocumentInterface *object, GError **error);
+document_interface_select_all(DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_select_all_in_all_layers(DocumentInterface *object,
+document_interface_select_all_in_all_layers(DocumentInterface *doc_interface,
GError **error);
gboolean
-document_interface_selection_box (DocumentInterface *object, int x, int y,
+document_interface_selection_box (DocumentInterface *doc_interface, int x, int y,
int x2, int y2, gboolean replace,
GError **error);
gboolean
-document_interface_selection_invert (DocumentInterface *object, GError **error);
+document_interface_selection_invert (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_selection_group(DocumentInterface *object, GError **error);
+document_interface_selection_group(DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_selection_ungroup(DocumentInterface *object, GError **error);
+document_interface_selection_ungroup(DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_selection_cut(DocumentInterface *object, GError **error);
+document_interface_selection_cut(DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_selection_copy(DocumentInterface *object, GError **error);
+document_interface_selection_copy(DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_selection_paste(DocumentInterface *object, GError **error);
+document_interface_selection_paste(DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_selection_scale (DocumentInterface *object,
+document_interface_selection_scale (DocumentInterface *doc_interface,
gdouble grow, GError **error);
gboolean
-document_interface_selection_move (DocumentInterface *object, gdouble x,
+document_interface_selection_move (DocumentInterface *doc_interface, gdouble x,
gdouble y, GError **error);
gboolean
-document_interface_selection_move_to (DocumentInterface *object, gdouble x,
+document_interface_selection_move_to (DocumentInterface *doc_interface, gdouble x,
gdouble y, GError **error);
gboolean
-document_interface_selection_move_to_layer (DocumentInterface *object,
+document_interface_selection_move_to_layer (DocumentInterface *doc_interface,
gchar *layerstr, GError **error);
GArray *
-document_interface_selection_get_center (DocumentInterface *object);
+document_interface_selection_get_center (DocumentInterface *doc_interface);
gboolean
-document_interface_selection_to_path (DocumentInterface *object, GError **error);
-
-gchar *
-document_interface_selection_combine (DocumentInterface *object, gchar *cmd,
- GError **error);
+document_interface_selection_to_path (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_selection_divide (DocumentInterface *object,
- char ***out, GError **error);
-
+document_interface_selection_combine (DocumentInterface *doc_interface, gchar *cmd, char ***newpaths,
+ GError **error);
gboolean
-document_interface_selection_change_level (DocumentInterface *object, gchar *cmd,
+document_interface_selection_change_level (DocumentInterface *doc_interface, gchar *cmd,
GError **error);
/****************************************************************************
@@ -389,24 +373,24 @@ document_interface_selection_change_level (DocumentInterface *object, gchar *cmd
****************************************************************************/
gchar *
-document_interface_layer_new (DocumentInterface *object, GError **error);
+document_interface_layer_new (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_layer_set (DocumentInterface *object,
+document_interface_layer_set (DocumentInterface *doc_interface,
gchar *layerstr, GError **error);
gchar **
-document_interface_layer_get_all (DocumentInterface *object);
+document_interface_layer_get_all (DocumentInterface *doc_interface);
gboolean
-document_interface_layer_change_level (DocumentInterface *object,
+document_interface_layer_change_level (DocumentInterface *doc_interface,
gchar *cmd, GError **error);
gboolean
-document_interface_layer_next (DocumentInterface *object, GError **error);
+document_interface_layer_next (DocumentInterface *doc_interface, GError **error);
gboolean
-document_interface_layer_previous (DocumentInterface *object, GError **error);
+document_interface_layer_previous (DocumentInterface *doc_interface, GError **error);
@@ -422,13 +406,13 @@ extern DocumentInterface *fugly;
gboolean dbus_send_ping (SPDesktop* desk, SPItem *item);
gboolean
-document_interface_get_children (DocumentInterface *object, char *name, char ***out, GError **error);
+document_interface_get_children (DocumentInterface *doc_interface, char *name, char ***out, GError **error);
gchar*
-document_interface_get_parent (DocumentInterface *object, char *name, GError **error);
+document_interface_get_parent (DocumentInterface *doc_interface, char *name, GError **error);
gchar*
-document_interface_import (DocumentInterface *object,
+document_interface_import (DocumentInterface *doc_interface,
gchar *filename, GError **error);
G_END_DECLS
diff --git a/src/extension/dbus/document-interface.xml b/src/extension/dbus/document-interface.xml
index aeacfae44..7481c0893 100644
--- a/src/extension/dbus/document-interface.xml
+++ b/src/extension/dbus/document-interface.xml
@@ -21,7 +21,7 @@
<node name="/org/inkscape/document"
xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"
>
-
+c
<interface name="org.inkscape.document">
<!-- MISC FUNCTIONS -->
@@ -1348,36 +1348,20 @@
<doc:summary>Type of combination.</doc:summary>
</doc:doc>
</arg>
- <arg type="s" name="newpath" direction="out" >
- <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value="error"/>
+ <arg type="as" name="newpaths" direction="out" >
<doc:doc>
- <doc:summary>The new path created, if there is one. NULL otherwise.</doc:summary>
+ <doc:summary>List of the ids of resulting paths after applying the operation.</doc:summary>
</doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>Will erase all objects in the selection and replace with a single aggregate path.</doc:para>
<doc:para>There are 5 types that can be passed in:</doc:para>
- <doc:para>Union: The new shape is all of the other shapes put together, even if they don't overlap (paths can have multiple non-contiguous areas.)</doc:para>
- <doc:para>Intersection: The new shape is composed of the area where ALL the objects in the selection overlap. If there is no area where all shapes overlap the new shape will be empty.</doc:para>
- <doc:para>Difference: The area of the second shape is subtracted from the first, only works with two objects.</doc:para>
- <doc:para>Exclusion: The new shape is the area(s) where none of the objects in the selection overlaped. Only works with two objects.</doc:para>
- <doc:para>Division: the first object is split into multiple segments by the second object. Only works with two objects and if multiple paths result they are grouped and the group id is returned.</doc:para>
- </doc:description>
- </doc:doc>
- </method>
-
- <method name="selection_divide">
- <arg type="as" name="pieces" direction="out" >
- <!-- <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value=""/> -->
- <doc:doc>
- <doc:summary>List of the ids of resulting paths.</doc:summary>
- </doc:doc>
- </arg>
- <doc:doc>
- <doc:description>
- <doc:para>Returns the result of cutting the bottom object by all other intersecting paths.</doc:para>
- <doc:para>This may make many seperate layers.</doc:para>
+ <doc:para>'union': The new shape is all of the other shapes put together, even if they don't overlap (paths can have multiple non-contiguous areas.)</doc:para>
+ <doc:para>'intersection': The new shape is composed of the area where ALL the objects in the selection overlap. If there is no area where all shapes overlap the new shape will be empty.</doc:para>
+ <doc:para>'difference': The area of the second shape is subtracted from the first, only works with two objects.</doc:para>
+ <doc:para>'exclusion': The new shape is the area(s) where none of the objects in the selection overlaped. Only works with two objects.</doc:para>
+ <doc:para>'division': the first object is split into multiple segments by the second object. Only works with two objects.</doc:para>
</doc:description>
</doc:doc>
</method>
diff --git a/src/extension/dbus/wrapper/inkscape-dbus-wrapper.c b/src/extension/dbus/wrapper/inkscape-dbus-wrapper.c
index 7a33d4f38..c7e453593 100644
--- a/src/extension/dbus/wrapper/inkscape-dbus-wrapper.c
+++ b/src/extension/dbus/wrapper/inkscape-dbus-wrapper.c
@@ -96,7 +96,9 @@ inkscape_desktop_init_dbus ()
GError *error;
DBusGProxy *proxy;
+#if !GLIB_CHECK_VERSION(2,36,0)
g_type_init ();
+#endif
error = NULL;
connection = dbus_g_bus_get (DBUS_BUS_SESSION,
@@ -686,23 +688,13 @@ inkscape_selection_to_path (DocumentInterface *doc, GError **error)
}
//static
-char *
-inkscape_selection_combine (DocumentInterface *doc, const char * IN_type, GError **error)
-{
- char * OUT_newpath;
- DBusGProxy *proxy = doc->proxy;
- org_inkscape_document_selection_combine (proxy, IN_type, &OUT_newpath, error);
- return OUT_newpath;
-}
-
-//static
char **
-inkscape_selection_divide (DocumentInterface *doc, GError **error)
+inkscape_selection_combine (DocumentInterface *doc, const char * IN_type, GError **error)
{
- char ** OUT_pieces;
+ char ** OUT_newpaths;
DBusGProxy *proxy = doc->proxy;
- org_inkscape_document_selection_divide (proxy, &OUT_pieces, error);
- return OUT_pieces;
+ org_inkscape_document_selection_combine (proxy, IN_type, &OUT_newpaths, error);
+ return OUT_newpaths;
}
//static
diff --git a/src/extension/dbus/wrapper/inkscape-dbus-wrapper.h b/src/extension/dbus/wrapper/inkscape-dbus-wrapper.h
index 684f1b142..20830bd65 100644
--- a/src/extension/dbus/wrapper/inkscape-dbus-wrapper.h
+++ b/src/extension/dbus/wrapper/inkscape-dbus-wrapper.h
@@ -8,8 +8,6 @@
//#include <dbus/dbus-glib-bindings.h>
//#include <dbus/dbus-glib-lowlevel.h>
-
-#define DBUS_DOCUMENT_INTERFACE_PATH "/org/inkscape/document"
#define TYPE_DOCUMENT_INTERFACE (document_interface_get_type ())
#define DOCUMENT_INTERFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TYPE_DOCUMENT_INTERFACE, DocumentInterface))
@@ -304,12 +302,8 @@ gboolean
inkscape_selection_to_path (DocumentInterface *doc, GError **error);
//static
-char *
-inkscape_selection_combine (DocumentInterface *doc, const char * IN_type, GError **error);
-
-//static
char **
-inkscape_selection_divide (DocumentInterface *doc, GError **error);
+inkscape_selection_combine (DocumentInterface *doc, const char * IN_type, GError **error);
//static
gboolean
diff --git a/src/extension/dependency.cpp b/src/extension/dependency.cpp
index f53dc93b4..78012ccc8 100644
--- a/src/extension/dependency.cpp
+++ b/src/extension/dependency.cpp
@@ -13,6 +13,8 @@
#endif
#include <glibmm/i18n.h>
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
#include "config.h"
#include "path-prefix.h"
#include "dependency.h"
@@ -120,8 +122,7 @@ Dependency::~Dependency (void)
found then a TRUE is returned. If we get all the way through the
path then a FALSE is returned, the command could not be found.
*/
-bool
-Dependency::check (void) const
+bool Dependency::check (void) const
{
// std::cout << "Checking: " << *this << std::endl;
@@ -214,7 +215,6 @@ Dependency::check (void) const
g_free(orig_path);
return FALSE; /* Reverse logic in this one */
- break;
}
} /* switch _location */
break;
diff --git a/src/extension/dxf2svg/GPL.txt b/src/extension/dxf2svg/GPL.txt
deleted file mode 100644
index 3912109b5..000000000
--- a/src/extension/dxf2svg/GPL.txt
+++ /dev/null
@@ -1,340 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/src/extension/dxf2svg/LGPL.txt b/src/extension/dxf2svg/LGPL.txt
deleted file mode 100644
index 8add30ad5..000000000
--- a/src/extension/dxf2svg/LGPL.txt
+++ /dev/null
@@ -1,504 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-not price. Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
-
-
diff --git a/src/extension/dxf2svg/Makefile b/src/extension/dxf2svg/Makefile
deleted file mode 100644
index d0f06daf0..000000000
--- a/src/extension/dxf2svg/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-objs = read_dxf.o entities.o entities2elements.o tables.o tables2svg_info.o blocks.o
-flags = -O1
-
-dxf2svg : dxf2svg.cpp $(objs)
- g++ $(flags) -o dxf2svg dxf2svg.cpp $(objs)
-
-test : test_dxf.cpp $(objs)
- g++ $(flags) -o test test_dxf.cpp $(objs)
-
-%.o : %.cpp %.h
- g++ $(flags) -c $<
-
-clean :
- rm dxf2svg $(objs)
-
-install:
- echo ****User intervention required****
- echo
- echo Copy dxf2svg executable and dxf2svg.inx to share/extension directory
- echo Make sure file permissions are set correctly
-
diff --git a/src/extension/dxf2svg/README b/src/extension/dxf2svg/README
deleted file mode 100644
index dbf98d2cc..000000000
--- a/src/extension/dxf2svg/README
+++ /dev/null
@@ -1,41 +0,0 @@
-26 Aug 05
-
-To use:
-I have only gotten this to work with Inkscape under linux (debian sarge). But the converter works from the commandline if you want to test it otherwise.
-
-1. Run make and copy dxf2svg to somewhere that is looked at by the PATH variable. Or add the current directory to your path
-2. Copy the dxf_import.inx to ../Inkscape/share/extensions
-3. Run Inkscape
-4. Click on open or import and the dxf option should be there
-
-I have compiled and then succesfully converted dxf files to svg files with the following setups
-
-WinXP Pro, Cygwin, g++ 3.3.3
-Debian Sarge, AMD x86_64, g++ 4.0.2
-RedHat(?), x86(?), g++ 3.2.3
-
-I have weakly tried and failed to compile using
-Borland's free compiler bcc32
-MinGW
-
-What is supported:
-polylines, lines, arc, circles, blocks, text, and a little linetypes
-
-currently not supported but I hope will be in the near future (probably after Sept 05)
-layers, colors, trace, splines, dimentions
-
-If you don't have dxf files of your own, but would like to easily test some I would suggest a few places...
-
-www.newfocus.com -- look under optomechanics. There are a variety of mounts and such that are posted in dxf and pdf
-www.thorlabs.com -- dido what I said about newfocus
-
-Free CAD programs:
-Windows -- A free and not too bad CAD program for windows is CadStd Lite. It exports to dxf and has a variety of samples.
-Windows/Linux -- QCad is ok. It has a lot of nice features but when I used it a year ago it would import dxf files but then you couldn't edit what was imported. It is free but with a time limit. My experience is that it can be a little annoying. Because of that and others comments I didn't use their libraries for dxf reading.
-
-
-Matt Squires
-squiresm@colorado.edu
-
-27 Aug 05, Fixed a fair number of bugs, and broken conversions. LWPOLYLINE works now, text rotation is ok but needs multiple transfomations to get it right, can read broken dxf files (w/o dxf EOF information)
-
diff --git a/src/extension/dxf2svg/aci2rgb.cpp b/src/extension/dxf2svg/aci2rgb.cpp
deleted file mode 100644
index 57e488bfc..000000000
--- a/src/extension/dxf2svg/aci2rgb.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <iostream>
-#include <sstream>
-#include <string>
-
-
-char* RGB(double R, double G, double B);
-char* RGB(double R, double G, double B){
- int r = int (R);
- int g = int (G);
- int b = int (B);
-
- char out[6];
- char *chr_ptr;
- string output;
- stringstream oss;
-
- if (r < 16 ){
- oss << 0;
- }
- oss << hex << r;
-
- if (g < 16 ){
- oss << 0;
- }
- oss << hex << g;
-
- if (b < 16 ){
- oss << 0;
- }
- oss << hex << b;
-
- output = oss.str();
-
- for (int i = 0; i < 6; i++){
- out[i] = output[i];
- }
- chr_ptr = &out;
- return chr_ptr;
-}
-
-
-float aci_to_rgb(int aci);
-
-float aci_to_rgb(int aci)
- {
- aci = abs(aci); // hidden layers have negative color values
- if (aci<10 || aci>249) // values of these ranges are special colors
- {
- switch (aci)
- {
- case 1: return RGB(255,0,0); // basic colors
- case 2: return RGB(255,255,0);
- case 3: return RGB(0,255,0);
- case 4: return RGB(0,255,255);
- case 5: return RGB(0,0,255);
- case 6: return RGB(255,0,255);
- case 7: return RGB(255,255,255);
- case 8: return RGB(128,128,128);
- case 9: return RGB(192,192,192);
- case 250: return RGB(51,51,51); // grey shades
- case 251: return RGB(91,91,91);
- case 252: return RGB(132,132,132);
- case 253: return RGB(173,173,173);
- case 254: return RGB(214,214,214);
- case 255: return RGB(255,255,255);
- case 256: // "by layer"
- // Here you should decide how to handle "by layer" logical color.
- // Maybe it is a good idea to return a value like -1.
- // The outer code will find what is the color of the layer which
- // this entity belongs to.
- return -1;
- }
- }
- // for all the rest of ACI codes
- float H,S,L, R,G,B;
- int remainder = aci % 10;
- H = 1.5f * (aci - remainder - 10); // hue in range 0-360
- S = ((aci % 2) ? 0.5f : 1.0f); // odd colors have 50% of saturation, even - 100%
- // set lighteness, the last digit of aci code stands for this
- if (reminder == 0 || reminder == 1) L = 1.0f;
- if (reminder == 2 || reminder == 3) L = 0.8f;
- if (reminder == 4 || reminder == 5) L = 0.6f;
- if (reminder == 6 || reminder == 7) L = 0.5f;
- if (reminder == 8 || reminder == 9) L = 0.3f;
- // here we have H,S,L set already
- // let's convert it to RGB, first without consideration of S and L
- if (H<=120)
- {
- R = (120-H)/60;
- G = H/60;
- B = 0;
- }
- if (H>120 && H<=240)
- {
- R = 0;
- G = (240-H)/60;
- B = (H-120)/60;
- }
- if (H>240 && H<=360)
- {
- R = (H-240)/60;
- G = 0;
- B = (360-H)/60;
- }
- R = min(R, 1);
- G = min(G, 1);
- B = min(B, 1);
- // influence of S and L
- float max_value = max(R,max(G,B));
- R = (max_value-S*(max_value-R)) * L * 255;
- G = (max_value-S*(max_value-G)) * L * 255;
- B = (max_value-S*(max_value-B)) * L * 255;
- return RGB(R,G,B);
- } \ No newline at end of file
diff --git a/src/extension/dxf2svg/blocks.cpp b/src/extension/dxf2svg/blocks.cpp
deleted file mode 100644
index 36f2b9e7e..000000000
--- a/src/extension/dxf2svg/blocks.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Read Blocks from file and convert to vectors of entities
- *
- * Author:
- * Matt Squires <squiresm@colorado.edu>
- *
- * Copyright (C) 2005 Matt Squires
- *
- * Released under GNU GPL and LGPL, read the file 'GPL.txt' and 'LGPL.txt' for details
- */
-
-
-#include"blocks.h"
-#include<iostream>
-
-block::block(std::vector< std::vector< dxfpair > > sections) : entities( sections ){
- // Inherit most of the functionality of the entitites section
-
- basic_entity( sections[0] );
- block_info( sections[0] );
-}
-
-char* block::name(char* string){
- return( strcpy(string,block_name) );
-}
-
-
-void block::block_info( std::vector< dxfpair > info){
- static char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 2: // Block name
- strcpy( string," "); // Clear the string out
- info[i].value_char(string);
- strcpy(block_name,string);
- break;
- }
- }
-}
-
-
-blocks::blocks(std::vector< std::vector< dxfpair > > sections){
- // Read the main information about the entities section and then put it in the enetites class
- char string[10000];
- std::vector< dxfpair > single_line;
- std::vector< std::vector< dxfpair > > ents;
- ents.clear();
- single_line.clear();
-
- int n_loop = sections.size();
- n_loop--;
- //for(int i = 0; i < (sections.size()-1); i++){ // It is odd but the last value seems to be bad so don't use it
- // I am not really sure if I need the -1. I needed it once upon a time to make things work but I don't have time to test it well right now
- // But sections.size() is an unsigned int so when you subtract 1 it becomes 4294967295 and tries to run the loop so work around that by making n_loop that is signed
- for(int i = 0; i < n_loop; i++){ // It is odd but the last value seems to be bad so don't use it
- sections[i][0].value_char(string);
- ents.clear(); // First clear out the pline information
-
-
- // Get everything from the start of the BLOCK designation to an ENDBLK value
- if ( strncmp(string,"BLOCK",5) == 0 && (i < sections.size())){
- do{
- ents.push_back( sections[i] );
- sections[++i][0].value_char(string);
- }while( strncmp(string,"ENDBLK",6) != 0 && (i < sections.size()-1) );
- blocks_blocks.push_back( block( ents ) );
- }
- }
-}
-
-block blocks::ret_block(char block_name[10000]){
- int string_len = 0;
- char temp[10000];
-
- for (int i = 0; i < blocks_blocks.size();i++){
- string_len = strlen(blocks_blocks[i].name(temp));
- if (strncmp(blocks_blocks[i].name(temp),block_name,string_len) == 0 ) return blocks_blocks[i];
- }
- return blocks_blocks[0];
-}
-
-
-
diff --git a/src/extension/dxf2svg/blocks.h b/src/extension/dxf2svg/blocks.h
deleted file mode 100644
index 27e0b8be1..000000000
--- a/src/extension/dxf2svg/blocks.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Read Blocks from file and convert to vectors of entities
-Matt Squires
-Google SOC 2005
-*/
-
-#ifndef DXF_BLOCKS_H
-#define DXF_BLOCKS_H
-
-#include"read_dxf.h"
-#include"entities.h"
-#include<vector>
-
-
-class block : public entity, public entities{// : public entities, {
- public:
- block( std::vector< std::vector< dxfpair > > sections ); // Group all of the blocks as entities
- char* name(char* string);
- //void blocks_display();
-
-
- protected:
- char block_name[10000];
- double rotation;
-
- private:
- void block_info(std::vector< dxfpair > info);
-};
-
-class blocks{
- public:
- blocks(std::vector< std::vector< dxfpair > > sections);
- block ret_block(char block_name[10000]);
-
- protected:
- std::vector< block > blocks_blocks;
-};
-
-#endif
diff --git a/src/extension/dxf2svg/dxf2svg.cpp b/src/extension/dxf2svg/dxf2svg.cpp
deleted file mode 100644
index 4884ed3fe..000000000
--- a/src/extension/dxf2svg/dxf2svg.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Build a SVG from an dxf, will support conversion to Inkscape types
- *
- * Author:
- * Matt Squires <squiresm@colorado.edu>
- *
- * Copyright (C) 2005 Matt Squires
- *
- * Released under GNU GPL and LGPL, read the file 'GPL.txt' and 'LGPL.txt' for details
- */
-
-
-#include<fstream>
-#include<iostream>
-#include"read_dxf.h"
-#include"entities.h"
-#include"blocks.h"
-#include"entities2elements.h"
-
-
-int main(int argc,char *argv[]){
- // Later include options for different conversions like converting as much as possible into paths
-
- if(argc > 1){
- double scaling = 90; // converstion from in to pt
-
- // Read the DXF file
- std::vector< std::vector< dxfpair > > output, entities_info, tables_info, blocks_info;
- //std::cout << "About to read file \n" << std::endl;
- output = dxf_get_sections(argv[1]);
- //std::cout << "Finished reading file \n" << std::endl;
-
- entities_info = separate_parts(output[4]); // Entities is the 5th part of the file.
- entities ents(entities_info); // Sort entities into their respective parts
-
- tables_info = separate_parts(output[2]); // Tables is the 3rd part of a dxf file.
- tables tbls(tables_info); // Sort the information in the tables
-
- blocks_info = separate_parts(output[3]); // Tables is the 4th part of a dxf file.
- blocks blks(blocks_info); // Sort the information in the tables
-
-
-
- // Get the various file informations
- /*std::vector< polyline > plines = ents.ret_plines();
- std::vector< lwpolyline > lwplines = ents.ret_lwplines();
- std::vector< arc > arcs = ents.ret_arcs();
- std::vector< circle > circs = ents.ret_circles();
- std::vector< line > lns = ents.ret_lines();
- std::vector< text > txts = ents.ret_texts();
- std::vector< insert > ins = ents.ret_inserts();
- */
-
-
- std::vector< layer > layers = tbls.ret_layers();
-
- char units[5] = "in";
- char tmp_char[100000];
- char layer_string[500];
- // int ink = 1; // Assume for now there is no inkscape stuff to add extra
-
- /*if (ink < 1){
- // Write a general svg header
- std::cout << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n\t\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n<svg xmlns=\"http://www.w3.org/2000/svg\"\n\txmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
- std::cout << "\tx=\"0.00000000\"\n\ty=\"0.00000000\"\n\twidth=\"744.09448\"\n\theight=\"-1052.3622\"" << std::endl;
- }
- else{*/
- std::cout << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" << std::endl;
- std::cout << "<!-- Created with dxf2svg -->" << std::endl;
- std::cout << "<svg" << std::endl;
- std::cout << "\txmlns:dc=\"http://purl.org/dc/elements/1.1/\"" << std::endl;
- std::cout << "\txmlns:cc=\"http://web.resource.org/cc/\"" << std::endl;
- std::cout << "\txmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" << std::endl;
- std::cout << "\txmlns:svg=\"http://www.w3.org/2000/svg\"" << std::endl;
- std::cout << "\txmlns=\"http://www.w3.org/2000/svg\"" << std::endl;
- std::cout << "\txmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"" << std::endl;
- std::cout << "\txmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"" << std::endl;
- std::cout << "\t>" << std::endl;
- //}
-
-
- // Now write SVG elements to file
- if ( layers.size() < 1 ){
- write_all(0, ents, tbls, blks, scaling, units, tmp_char);
- }
- else{
- for (int i = 0; i < layers.size(); i++){
- std::cout << "\t<g\n\t\tinkscape:label=\"" << layers[i].name(layer_string) << "\"\n\t\tinkscape:groupmode=\"layer\"\n\t\tid=\"layer" << i+1 << "\">" << std::endl;
- write_by_layer(0, ents, tbls, blks, scaling, units, layers[i].name(layer_string), tmp_char);
- std::cout << "\t</g>" << std::endl;
- }
- }
-
- // Close SVG
- std::cout << "</svg>";
- }
-
- return 0;
-}
diff --git a/src/extension/dxf2svg/dxf_input.inx b/src/extension/dxf2svg/dxf_input.inx
deleted file mode 100644
index b96274ade..000000000
--- a/src/extension/dxf2svg/dxf_input.inx
+++ /dev/null
@@ -1,16 +0,0 @@
-<inkscape-extension>
- <name>DXF Input</name>
- <id>org.inkscape.input.dxf</id>
- <dependency type="executable" description="dxf2svg may come with Inkscape, but is also at http://dxf-svg-convert.sourceforge.net/" location="extensions">dxf2svg</dependency>
- <dependency type="extension">org.inkscape.input.svg</dependency>
- <input>
- <extension>.dxf</extension>
- <mimetype>image/x-svgz</mimetype>
- <filetypename>AutoCAD DXF (*.dxf)</filetypename>
- <filetypetooltip>Import AutoCAD's Document Exchange Format</filetypetooltip>
- <output_extension>org.inkscape.output.svg</output_extension>
- </input>
- <script>
- <command reldir="extensions">dxf2svg</command>
- </script>
-</inkscape-extension>
diff --git a/src/extension/dxf2svg/dxf_input_windows.inx b/src/extension/dxf2svg/dxf_input_windows.inx
deleted file mode 100644
index 7dbe6a11b..000000000
--- a/src/extension/dxf2svg/dxf_input_windows.inx
+++ /dev/null
@@ -1,17 +0,0 @@
-<inkscape-extension>
- <name>DXF Input</name>
- <id>org.inkscape.input.dxf</id>
- <dependency type="executable" description="dxf2svg may come with Inkscape, but is also at
-http://dxf-svg-convert.sourceforge.net/" location="extensions">dxf2svg.exe</dependency>
- <dependency type="extension">org.inkscape.input.svg</dependency>
- <input>
- <extension>.dxf</extension>
- <mimetype>image/x-svgz</mimetype>
- <filetypename>AutoCAD DXF (*.dxf)</filetypename>
- <filetypetooltip>Import AutoCAD's Document Exchange Format</filetypetooltip>
- <output_extension>org.inkscape.output.svg</output_extension>
- </input>
- <script>
- <command reldir="extensions">dxf2svg.exe</command>
- </script>
-</inkscape-extension>
diff --git a/src/extension/dxf2svg/entities.cpp b/src/extension/dxf2svg/entities.cpp
deleted file mode 100644
index 4e2f83ee7..000000000
--- a/src/extension/dxf2svg/entities.cpp
+++ /dev/null
@@ -1,996 +0,0 @@
-/*
- * Class for interpereting the entities found in a DXF file
- *
- * Author:
- * Matt Squires <squiresm@colorado.edu>
- *
- * Copyright (C) 2005 Matt Squires
- *
- * Released under GNU GPL and LGPL, read the file 'GPL.txt' and 'LGPL.txt' for details
- */
-
-
-#include"entities.h"
-#include<iostream>
-#include<math.h>
-
-int detmine_entity(char* value){
- // Common Elements as far as I am concerend
- if ( strncmp(value,"POLYLINE",8) == 0 ) return 0;
- if ( strncmp(value,"ARC",3) == 0 ) return 1;
- if ( strncmp(value,"CIRCLE",6) == 0 ) return 2;
- if ( strncmp(value,"LINE",4) == 0 ) return 3;
- if ( strncmp(value,"SPLINE",6) == 0 ) return 4;
- if ( strncmp(value,"XLINE",5) == 0 ) return 5;
- if ( strncmp(value,"RAY",3) == 0 ) return 6;
- if ( strncmp(value,"DIMENSION",9) == 0 ) return 7;
- if ( strncmp(value,"ELLIPSE",7) == 0 ) return 8;
- if ( strncmp(value,"INSERT",6) == 0 ) return 9;
- if ( strncmp(value,"VERTEX",6) == 0 ) return 10;
- if ( strncmp(value,"TEXT",4) == 0 ) return 11;
-
- // Less Common eletities as far as I am concerend
- if ( strncmp(value,"3DSOLID",7) == 0 ) return 12;
- if ( strncmp(value,"ACAD_PROXY_ENTITY",17) == 0 ) return 13;
- if ( strncmp(value,"ARCALIGNEDTEXT",14) == 0 ) return 14;
- if ( strncmp(value,"ATTDEF",6) == 0 ) return 15;
- if ( strncmp(value,"ATTRIB",6) == 0 ) return 16;
- if ( strncmp(value,"BODY",4) == 0 ) return 17;
- if ( strncmp(value,"HATCH",5) == 0 ) return 18;
- if ( strncmp(value,"IMAGE",5) == 0 ) return 19;
- if ( strncmp(value,"LEADER",6) == 0 ) return 20;
- if ( strncmp(value,"LWPOLYLINE",10) == 0 ) return 21;
- if ( strncmp(value,"MLINE",5) == 0 ) return 22;
- if ( strncmp(value,"MTEXT",5) == 0 ) return 23;
- if ( strncmp(value,"OLEFRAME",8) == 0 ) return 24;
- if ( strncmp(value,"POINT",5) == 0 ) return 25;
- if ( strncmp(value,"REGION",6) == 0 ) return 26;
- if ( strncmp(value,"RTEXT",5) == 0 ) return 27;
- if ( strncmp(value,"SEQEND",6) == 0 ) return 28;
- if ( strncmp(value,"SHAPE",5) == 0 ) return 29;
- if ( strncmp(value,"SOLID",5) == 0 ) return 30;
- if ( strncmp(value,"3DFACE",6) == 0 ) return 31;
- if ( strncmp(value,"TOLERANCE",9) == 0 ) return 32;
- if ( strncmp(value,"TRACE",5) == 0 ) return 33;
- if ( strncmp(value,"VIEWPORT",8) == 0 ) return 34;
- if ( strncmp(value,"WIPEOUT",7) == 0 ) return 35;
- else return -1;
-}
-
-
-void entity::basic_entity( std::vector< dxfpair > info){
- // Extract all of the typical entity information (e.g. layer name, positions)
- static char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 6:
- strcpy( string," "); // Clear the string out
- info[i].value_char(string);
- strcpy(linetype,string);
- break;
- case 8:
- strcpy( string," "); // Clear the string out
- info[i].value_char(string);
- strcpy(layer,string);
- break;
- case 10:
- info[i].value_char(string);
- x = atof(string);
- if ( x < min_x ){
- min_x = x;
- }
- if ( x > max_x ){
- max_x = x;
- }
- break;
- case 20:
- info[i].value_char(string);
- y = atof(string);
- if ( y < min_y ){
- min_y = y;
- }
- if ( y > max_y ){
- max_y = y;
- }
- break;
- case 30:
- info[i].value_char(string);
- z = atof(string);
- break;
- }
- }
-
-}
-
-void entity::entity_display(){
- std::cout << "\tlayer = " << layer << "\n\tlinetype = " << linetype << "\n\tx = " << x << "\ty = " << y << "\tz = " << z << std::flush;
-}
-
-double entity::ret_x(){
- return x;
-}
-
-double entity::ret_y(){
- return y;
-}
-
-double entity::ret_z(){
- return z;
-}
-
-
-char* entity::ret_layer_name(char* string){
- return( strcpy(string,layer) );
-}
-
-char* entity::ret_ltype_name(char* string){
- return( strcpy(string,linetype) );
-}
-
-double entity::ret_min_x(){
- return min_x;
-}
-
-double entity::ret_max_x(){
- return max_x;
-}
-
-double entity::ret_min_y(){
- return min_y;
-}
-
-double entity::ret_max_y(){
- return max_y;
-}
-
-void entity::test_coord(double x, double y){
- if ( x < min_x ){
- min_x = x;
- }
- if ( x > max_x ){
- max_x = x;
- }
- if ( y < min_y ){
- min_y = y;
- }
- if ( y > max_y ){
- max_y = y;
- }
-}
-
-
-void entity::reset_extents(){
- min_x = -1e20;
- max_x = 1e20;
- min_y = -1e20;
- max_y = 1e20;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// VERTEX
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-vertex::vertex( std::vector< dxfpair > info){
- // Get the vertex information
-
- basic_entity( info );
- static char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 42:
- info[i].value_char(string);
- bulge = atof(string);
- break;
- }
- }
-}
-
-double vertex::ret_bulge(){
- return bulge;
-}
-
-void vertex::display(){
- std::cout << "VERTEX\n";
- std::cout << "\tx = " << x << "\ty = " << y << "\tz = " << z << "\tbulge = " << bulge << std::flush;
-}
-
-
-
-
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// POLYLINE
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-// The polyline is handled a little differently compared to the other entities because a POLYLINE is built from a bunch of VERTEX entities
-polyline::polyline( std::vector< std::vector< dxfpair > > sections ){
- buldge = 0;
- pline_flag = 0;
- reset_extents();
- // get the polyline information
- basic_entity( sections[0] );
- points.clear();
- static char string[10000];
- for (int i = 0; i < sections[0].size(); i++){
- switch( sections[0][i].group_code ){
- case 70:
- sections[0][i].value_char(string);
- pline_flag = atoi(string);
- break;
- case 40:
- sections[0][i].value_char(string);
- start_width = atoi(string);
- break;
- case 41:
- sections[0][i].value_char(string);
- end_width = atoi(string);
- break;
- case 75:
- sections[0][i].value_char(string);
- curves_flag = atoi(string);
- break;
- }
- }
- curves_flag = 0;
-
- // Now add the VERTEX entities to the POLYLINE
- for (int i = 1; i < sections.size(); i++){
- points.push_back( vertex( sections[i] ) );
- }
-}
-
-
-std::vector< vertex > polyline::ret_points(){
- return points;
-}
-
-double polyline::bulge(int point){
- return points[point].ret_bulge();
-}
-
-double polyline::bulge_r(int point){
- // Make sure we are not exceeding the bounds of the points vector
- if (point >= (points.size()-1)) return 0;
-
- double dx = points[point+1].ret_x() - points[point].ret_x();
- double dy = points[point+1].ret_y() - points[point].ret_y();
- double bulge = points[point].ret_bulge();
- double l = sqrt(dx*dx + dy*dy);
- double r = fabs(l*(bulge*bulge+1)/bulge/4);
-
- return r;
-}
-
-double polyline::bulge_start_angle(int point){
- // Make sure we are not exceeding the bounds of the points vector
- if (point >= (points.size()-1))
- {
- return 0;
- }
-
- double dx = points[point+1].ret_x() - points[point].ret_x();
- double dy = points[point+1].ret_y() - points[point].ret_y();
- double bulge = points[point].ret_bulge();
- double l = sqrt(dx*dx + dy*dy);
- double r = fabs(l*(bulge*bulge+1)/bulge/4);
-
- if (dx > 0)
- {
- sb *= -1; // Correct for different point ordering and bulge direction
- }
-
- // Now calculate the angle
- double theta = asin(points[point].ret_x()/r);
- if (dy < 0) theta = 6.2831853 - theta; // The angle is greater than pi so fix this because max(asin) = pi
-
- return theta;
-}
-
-double polyline::bulge_end_angle(int point){
- // Make sure we are not exceeding the bounds of the points vector
- if (point >= (points.size()-1))
- {
- return 0;
- }
-
- double dx = points[point+1].ret_x() - points[point].ret_x();
- double dy = points[point+1].ret_y() - points[point].ret_y();
- double bulge = points[point].ret_bulge();
- double l = sqrt(dx*dx + dy*dy);
- double r = fabs(l*(bulge*bulge+1)/bulge/4);
-
- // Now calculate the angle
- double theta = asin(points[point+1].ret_x()/r);
- if (dy < 0) theta = 6.2831853 - theta; // The angle is greater than pi so fix this because max(asin) = pi
-
- return theta;
-}
-
-bool polyline::is_closed(){
- // pline-flag holds info about closed pline in the 1 bit. The info is bit wise encoded so use bit wise operators
- return bool(pline_flag&1);
-}
-
-void polyline::display(){
- std::cout << "POLYLINE\n";
- entity_display();
- std::cout << std::endl;
- for (int i = 0; i < points.size(); i++){
- points[i].display();
- std::cout << std::endl;
- }
- std::cout << std::endl;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// LWPOLYLINE
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-// The lwpolyline is different than the polyline because there are no vertex entities. Use the same basic process as the polyline but parse it out differently
-lwpolyline::lwpolyline( std::vector< dxfpair > section ){
-
- // First break up the data into the same format that is used by the polyline entity
- std::vector< std::vector< dxfpair > > sections;
- std::vector< dxfpair > first;
- std::vector< dxfpair > others;
-
- sections.clear();
- first.clear();
- others.clear();
-
- int gc; // make a shorter name for group_code;
-
- int vertex_part;
- int already_found = 0;
-
- for (int i = 0; i < section.size(); i++){
- gc = section[i].group_code;
- // Encode bitwise information to keep track of what has been found
- vertex_part = 0;
- if (gc == 10 ) vertex_part += 1;
- if (gc == 20 ) vertex_part += 2;
- if (gc == 30 ) vertex_part += 4;
- if (gc == 40 ) vertex_part += 8;
- if (gc == 41 ) vertex_part += 16;
- if (gc == 42 ) vertex_part += 32;
- //std::cout << "\n\nvertex_part = " << vertex_part << std::endl << "already_found = " << already_found << std::endl << "(vertex_part&already_found) = " << (vertex_part&already_found) << std::endl;
- if ( vertex_part == 0 ){
- // If header stuff has been found save it under first.
- // I.E. in a polyline the first set of information is linetype and layer, all of what should be in here
- first.push_back( section[i] );
- }
- else if ( (vertex_part&already_found) == 0 ){
- // Now work on what would be the vertex information
- // New information is still being found so keep saving it
- others.push_back( section[i] );
- //std::cout << "add to others" << std::endl;
- already_found += vertex_part; // Keep track of what has been found
- }
- else{
- sections.push_back( others );
- //std::cout << "sections.size() = " << sections.size() << std::endl;
- // Now clear the information out and start over
- others.clear();
- others.push_back( section[i] );
- already_found = vertex_part;
- }
- }
-
- // Now put on the last data that was found
- if (!others.empty()){
- sections.push_back(others);
- }
-
- reset_extents();
- basic_entity( first );
- points.clear();
- static char string[10000];
- buldge = 0;
- pline_flag = 0;
- curves_flag = 0;
- for (int i = 0; i < first.size(); i++){
- switch( sections[0][i].group_code ){
- case 70:
- first[i].value_char(string);
- pline_flag = atoi(string);
- break;
- case 40:
- first[i].value_char(string);
- start_width = atoi(string);
- break;
- case 41:
- first[i].value_char(string);
- end_width = atoi(string);
- break;
- case 75:
- first[i].value_char(string);
- curves_flag = atoi(string);
- break;
- }
- }
- // Now add the VERTEX entities to the POLYLINE
- for (int i = 0; i < sections.size(); i++){
- points.push_back( vertex( sections[i] ) );
- }
-}
-
-
-
-std::vector< vertex > lwpolyline::ret_points(){
- return points;
-}
-
-
-double lwpolyline::bulge(int point){
- return points[point].ret_bulge();
-}
-
-double lwpolyline::bulge_r(int point){
- // Make sure we are not exceeding the bounds of the points vector
- if (point >= (points.size()-1)) return 0;
-
- double dx = points[point+1].ret_x() - points[point].ret_x();
- double dy = points[point+1].ret_y() - points[point].ret_y();
- double bulge = points[point].ret_bulge();
- double l = sqrt(dx*dx + dy*dy);
- double r = fabs(l*(bulge*bulge+1)/bulge/4);
-
- return r;
-}
-
-double lwpolyline::bulge_start_angle(int point){
- // Make sure we are not exceeding the bounds of the points vector
- if (point >= (points.size()-1)) return 0;
-
- double dx = points[point+1].ret_x() - points[point].ret_x();
- double dy = points[point+1].ret_y() - points[point].ret_y();
- double bulge = points[point].ret_bulge();
- double l = sqrt(dx*dx + dy*dy);
- double r = fabs(l*(bulge*bulge+1)/bulge/4);
-
- // Now calculate the angle
- double theta = asin(points[point].ret_x()/r);
- if (dy < 0) theta = 6.2831853 - theta; // The angle is greater than pi so fix this because max(asin) = pi
-
- return theta;
-}
-
-double lwpolyline::bulge_end_angle(int point){
- // Make sure we are not exceeding the bounds of the points vector
- if (point >= (points.size()-1)) return 0;
-
- double dx = points[point+1].ret_x() - points[point].ret_x();
- double dy = points[point+1].ret_y() - points[point].ret_y();
- double bulge = points[point].ret_bulge();
- double l = sqrt(dx*dx + dy*dy);
- double r = fabs(l*(bulge*bulge+1)/bulge/4);
-
- // Now calculate the angle
- double theta = asin(points[point+1].ret_x()/r);
- if (dy < 0) theta = 6.2831853 - theta; // The angle is greater than pi so fix this because max(asin) = pi
-
- return theta;
-}
-
-bool lwpolyline::is_closed(){
- // pline-flag holds info about closed pline in the 1 bit. The info is bit wise encoded so use bit wise operators
- return bool(pline_flag&1);
-}
-
-void lwpolyline::display(){
- std::cout << "lwpolyline\n";
- entity_display();
- std::cout << std::endl;
- for (int i = 0; i < points.size(); i++){
- points[i].display();
- std::cout << std::endl;
- }
- std::cout << std::endl;
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// ARC
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-arc::arc( std::vector< dxfpair > info){
-
- reset_extents();
- basic_entity( info );
- static char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 40:
- info[i].value_char(string);
- radius = atof(string);
- test_coord(x+radius,y+radius);
- test_coord(x-radius,y-radius);
- break;
- case 50:
- info[i].value_char(string);
- start_angle = atof(string);
- break;
- case 51:
- info[i].value_char(string);
- end_angle = atof(string);
- break;
- default:
- break;
- }
- }
-}
-
-double arc::ret_radius(){
- return radius;
-}
-
-
-double arc::ret_srt_ang(){
- return start_angle;
-}
-
-
-double arc::ret_end_ang(){
- return end_angle;
-}
-
-
-void arc::display(){
- std::cout << "ARC\n";
- entity_display();
- std::cout << "\n\tradius = " << radius << "\tstart_angle = " << start_angle << "end_angle = " << end_angle << std::flush;
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// CIRCLE
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-circle::circle( std::vector< dxfpair > info){
-
- reset_extents();
- basic_entity( info );
- static char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 40:
- info[i].value_char(string);
- radius = atof(string);
- test_coord(x+radius,y+radius);
- test_coord(x-radius,y-radius);
- break;
- }
- }
-}
-
-void circle::display(){
- std::cout << "CIRCLE\n";
- entity_display();
- std::cout << "\n\tradius = " << radius << std::flush;
-}
-
-
-double circle::ret_radius(){
- return radius;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// LINE
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-line::line( std::vector< dxfpair > info){
-
- reset_extents();
- basic_entity( info );
- static char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 11:
- info[i].value_char(string);
- xf = atof(string);
- break;
- case 21:
- info[i].value_char(string);
- yf = atof(string);
- break;
- case 31:
- info[i].value_char(string);
- zf = atof(string);
- break;
- }
- }
- test_coord(xf,yf);
-
-}
-
-void line::display(){
- std::cout << "LINE\n";
- entity_display();
- std::cout << "\n\txf = " << xf << "\tyf = " << yf << "\tzf = " << zf << std::flush;
-}
-
-
-double line::ret_xf(){
- return xf;
-}
-
-double line::ret_yf(){
- return yf;
-}
-
-double line::ret_zf(){
- return zf;
-}
-
-
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// TEXT
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-text::text( std::vector< dxfpair > info){
-
- reset_extents();
- basic_entity( info );
- static char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 1:
- info[i].value_char(dxf_text); // directly copy the text into a string
- break;
- case 40:
- info[i].value_char(string);
- text_height = atof(string);
- break;
- case 50:
- info[i].value_char(string);
- text_rotation = atof(string);
- break;
- }
- }
-}
-
-char * text::ret_text(char *string){
- return( strcpy(string,dxf_text) );
-}
-
-double text::ret_txt_ht(){
- return text_height;
-}
-
-double text::ret_txt_rot(){
- return text_rotation;
-}
-
-void text::display(){
- char tmp[10000];
- std::cout << "TEXT\n";
- entity_display();
- std::cout << "\ndxf_text = " << ret_text(tmp) << std::flush;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// INSERT
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-insert::insert( std::vector< dxfpair > info){
- ret_x_sf = 0;
- ret_y_sf = 0;
- ret_z_sf = 0;
- ret_rotation = 0;
-
- basic_entity( info );
- static char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 2:
- info[i].value_char(block_name); // directly copy the text into a string
- break;
- case 41:
- info[i].value_char(string);
- x_scale_factor = atof(string);
- break;
- case 42:
- info[i].value_char(string);
- y_scale_factor = atof(string);
- break;
- case 43:
- info[i].value_char(string);
- z_scale_factor = atof(string);
- break;
- case 50:
- info[i].value_char(string);
- rotation = atof(string);
- break;
- }
- }
-}
-
-
-char * insert::name(char *string){
- return( strcpy(string,block_name) );
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// entities
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-
-entities::entities(std::vector< std::vector< dxfpair > > sections){
- // Read the main information about the entities section and then put it in the enetites class
- int value;
- char string[10000];
- std::vector< dxfpair > single_line;
- std::vector< std::vector< dxfpair > > pline;
- pline.clear();
- single_line.clear();
-
- for(int i = 0; i < sections.size(); i++){
- sections[i][0].value_char(string);
- value = detmine_entity(string);
- switch( value ){
- case 0:
- // Get everything from the start of the polyline designation to an SEQEND value
- pline.clear(); // First clear out the pline information
- do{
- pline.push_back( sections[i] );
- sections[++i][0].value_char(string);
- }while( strncmp(string,"SEQEND",6) != 0 );
- ents_polyline.push_back( polyline( pline ) );
- break;
-
- case 1:
- // ARC
- ents_arc.push_back( arc( sections[i] ) );
- break;
-
- case 2:
- // CIRCLE
- ents_circle.push_back( circle( sections[i] ) );
- break;
-
- case 3:
- // LINE
- ents_line.push_back( line( sections[i] ) );
- break;
- case 11:
- // TEXT
- ents_text.push_back( text( sections[i] ) );
- break;
- case 21:
- // LWPOLYLINE
- ents_lwpolyline.push_back( lwpolyline( sections[i] ) );
- case 9:
- // INSERT
- ents_insert.push_back( insert( sections[i] ) );
-
- //default:
- // Nothing here
- }
-
- }
-
-}
-
-
-// Maybe all of this could be turned into fewer function by using templates, but no time right now. MBS
-
-std::vector< polyline > entities::ret_plines(){
- std::vector< polyline > pls;
- pls.clear();
- for(int i = 0; i < ents_polyline.size();i++){
- pls.push_back( ents_polyline[i] );
- }
- return pls;
-}
-
-std::vector< lwpolyline > entities::ret_lwplines(){
- std::vector< lwpolyline > lwpls;
- lwpls.clear();
- for(int i = 0; i < ents_lwpolyline.size();i++){
- lwpls.push_back( ents_lwpolyline[i] );
- }
- return lwpls;
-}
-
-
-std::vector< arc > entities::ret_arcs(){
- std::vector< arc > a;
- a.clear();
- for(int i = 0; i < ents_arc.size();i++){
- a.push_back( ents_arc[i] );
- }
- return a;
-}
-
-std::vector< circle > entities::ret_circles(){
- std::vector< circle > circs;
- circs.clear();
- for(int i = 0; i < ents_circle.size();i++){
- circs.push_back( ents_circle[i] );
- }
- return circs;
-}
-
-
-std::vector< line > entities::ret_lines(){
- std::vector< line > lns;
- lns.clear();
- for(int i = 0; i < ents_line.size();i++){
- lns.push_back( ents_line[i] );
- }
- return lns;
-}
-
-
-std::vector< text > entities::ret_texts(){
- std::vector< text > txts;
- txts.clear();
- for(int i = 0; i < ents_text.size();i++){
- txts.push_back( ents_text[i] );
- }
- return txts;
-}
-
-
-std::vector< insert > entities::ret_inserts(){
- std::vector< insert > ins;
- ins.clear();
- for(int i = 0; i < ents_insert.size();i++){
- ins.push_back( ents_insert[i] );
- }
- return ins;
-}
-
-
-
-// Overload the return function to depend on the layer
-std::vector< polyline > entities::ret_plines(char * layer){
- char temp[10000];
- std::vector< polyline > pls;
- pls.clear();
-
- for(int i = 0; i < ents_polyline.size();i++){
- if ( strcmp( layer,ents_polyline[i].ret_layer_name(temp) ) == 0 ){
- pls.push_back( ents_polyline[i] );
- }
- }
- return pls;
-}
-
-
-std::vector< lwpolyline > entities::ret_lwplines(char * layer){
- char temp[10000];
- std::vector< lwpolyline > lwpls;
- lwpls.clear();
-
- for(int i = 0; i < ents_lwpolyline.size();i++){
- if ( strcmp( layer,ents_lwpolyline[i].ret_layer_name(temp) ) == 0 ){
- lwpls.push_back( ents_lwpolyline[i] );
- }
- }
- return lwpls;
-}
-
-
-std::vector< circle > entities::ret_circles(char * layer){
- char temp[10000];
- std::vector< circle > circs;
- circs.clear();
-
- for(int i = 0; i < ents_circle.size();i++){
- if ( strcmp( layer,ents_circle[i].ret_layer_name(temp) ) == 0 ){
- circs.push_back( ents_circle[i] );
- }
- }
- return circs;
-}
-
-
-std::vector< line > entities::ret_lines(char * layer){
- char temp[10000];
- std::vector< line > lns;
- lns.clear();
-
- for(int i = 0; i < ents_line.size();i++){
- if ( strcmp( layer,ents_line[i].ret_layer_name(temp) ) == 0 ){
- lns.push_back( ents_line[i] );
- }
- }
- return lns;
-}
-
-
-std::vector< text > entities::ret_texts(char * layer){
- char temp[10000];
- std::vector< text > txts;
- txts.clear();
-
- for(int i = 0; i < ents_text.size();i++){
- if ( strcmp( layer,ents_text[i].ret_layer_name(temp) ) == 0 ){
- txts.push_back( ents_text[i] );
- }
- }
- return txts;
-}
-
-
-/*std::vector< ellipse > entities::ret_ellipses(char * layer){
- char temp[10000];
- std::vector< polyline > pls;
- pls.clear();
-
- for(int i = 0; i < ents_polyline.size();i++){
- if ( strcmp( layer,ents_polyline[i].ret_layer_name(temp) ) == 0 ){
- pls.push_back( ents_polyline[i] );
- }
- }
- return pls;
-}*/
-
-
-std::vector< arc > entities::ret_arcs(char * layer){
- char temp[10000];
- std::vector< arc > a;
- a.clear();
-
- for(int i = 0; i < ents_arc.size();i++){
- if ( strcmp( layer,ents_arc[i].ret_layer_name(temp) ) == 0 ){
- a.push_back( ents_arc[i] );
- }
- }
- return a;
-}
-
-
-std::vector< insert > entities::ret_inserts(char * layer){
- char temp[10000];
- std::vector< insert > ins;
- ins.clear();
-
- for(int i = 0; i < ents_insert.size();i++){
- if ( strcmp( layer,ents_insert[i].ret_layer_name(temp) ) == 0 ){
- ins.push_back( ents_insert[i] );
- }
- }
- return ins;
-}
-
-
-
-
-void entities::display_all(){
- for (int i = 0; i < ents_polyline.size(); i++){
- ents_polyline[i].display();
- }
- std::cout << std::endl;
- for (int i = 0; i < ents_lwpolyline.size(); i++){
- ents_lwpolyline[i].display();
- }
- std::cout << std::endl;
- for (int i = 0; i < ents_circle.size(); i++){
- ents_circle[i].display();
- }
- std::cout << std::endl;
- for (int i = 0; i < ents_text.size(); i++){
- ents_text[i].display();
- }
-}
-
-
diff --git a/src/extension/dxf2svg/entities.h b/src/extension/dxf2svg/entities.h
deleted file mode 100644
index 3afd949b0..000000000
--- a/src/extension/dxf2svg/entities.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/* Class for interpereting the entities found in a DXF file
-Matt Squires
-Google SOC
-2 July 05
-*/
-
-#ifndef DXF_ENTITIES_H
-#define DXF_ENTITIES_H
-
-#include"read_dxf.h"
-#include<vector>
-
-
-
-
-class entity{
- public:
- void basic_entity( std::vector< dxfpair > info); // Extract all of the typical entity information (e.g. layer name, positions)
- void entity_display();
- double ret_x();
- double ret_y();
- double ret_z();
- char* ret_layer_name(char* string);
- char* ret_ltype_name(char* string);
- double ret_min_x();
- double ret_max_x();
- double ret_min_y();
- double ret_max_y();
-
-
- protected:
- char layer[10000];
- char linetype[10000];
- double x;
- double y;
- double z;
- double min_x;
- double max_x;
- double min_y;
- double max_y;
- void reset_extents();
- void test_coord(double x, double y);
-};
-
-
-
-
-
-class vertex : public entity {
- public:
- vertex( std::vector< dxfpair > info);
- void display();
- double ret_bulge();
-
- private:
- double bulge;
-};
-
-
-
-
-
-class polyline : public entity {
- public:
- polyline( std::vector< std::vector< dxfpair > > sections );
- std::vector< vertex > ret_points();
- double bulge(int point);
- double bulge_r(int point);
- double bulge_start_angle(int point);
- double bulge_end_angle(int point);
- bool is_closed();
- void display();
-
- private:
- double buldge;
- int pline_flag; // 70
- double start_width; // 40
- double end_width; // 41
- int curves_flag;
- std::vector< vertex > points;
-};
-
-class lwpolyline : public entity {
- public:
- lwpolyline( std::vector< dxfpair > section );
- std::vector< vertex > ret_points();
- double bulge(int point);
- double bulge_r(int point);
- double bulge_start_angle(int point);
- double bulge_end_angle(int point);
- bool is_closed();
- void display();
-
- private:
- double buldge;
- int pline_flag; // 70
- double start_width; // 40
- double end_width; // 41
- int curves_flag;
- std::vector< vertex > points;
-};
-
-class arc : public entity {
- public:
- arc( std::vector< dxfpair > info);
- double ret_radius();
- double ret_srt_ang();
- double ret_end_ang();
- void display();
-
- private:
- double radius;
- double start_angle;
- double end_angle;
-};
-
-
-
-
-class circle : public entity {
- public:
- circle( std::vector< dxfpair > info);
- void display();
- double ret_radius();
-
- private:
- double radius;
-};
-
-
-class line : public entity {
- public:
- line( std::vector< dxfpair > info);
- void display();
- double ret_xf();
- double ret_yf();
- double ret_zf();
-
- private:
- double xf;
- double yf;
- double zf;
-};
-
-class ellipse : public entity {
- public:
- ellipse( std::vector< dxfpair > info);
- void display();
- double ret_x_ma;
- double ret_y_ma;
- double ret_z_ma;
- double ret_ratio;
- double ret_start_p;
- double ret_end_p;
-
-
- private:
- double x_major_axis;
- double y_major_axis;
- double z_major_axis;
- double ratio;
- double start_param;
- double end_param;
-};
-
-
-
-class text : public entity {
- public:
- text( std::vector< dxfpair > info);
- void display();
- char * ret_text(char *string);
- double ret_txt_ht();
- double ret_txt_rot();
-
- private:
- char dxf_text[10000];
- double text_height; // dxf 40
- double text_rotation; //dxf 50
-};
-
-
-class insert : public entity {
- public:
- insert( std::vector< dxfpair > info);
- void display();
- char* name(char* string);
- double ret_x_sf;
- double ret_y_sf;
- double ret_z_sf;
- double ret_rotation;
-
- private:
- char block_name[10000];
- double x_scale_factor;
- double y_scale_factor;
- double z_scale_factor;
- double rotation;
-};
-
-
-
-
-
-
-class entities{
- // Well I said that I would only use STL containers internally, but I would have to use a dynamically linked list, and I haven't done for a long time soo STL is my crutch.
- // I also think that there are others in my same boat that prefer stl containers because they are much easier to use
- public:
- entities(std::vector< std::vector< dxfpair > > sections); // Put the various entities into their respective vectors
- void display_all();
- std::vector< polyline > ret_plines();
- std::vector< circle > ret_circles();
- std::vector< line > ret_lines();
- std::vector< text > ret_texts();
- std::vector< ellipse > ret_ellipses();
- std::vector< arc > ret_arcs();
- std::vector< lwpolyline > ret_lwplines();
- std::vector< insert > ret_inserts();
- // Overload the return function to depend on the layer
- std::vector< polyline > ret_plines(char * layer);
- std::vector< circle > ret_circles(char * layer);
- std::vector< line > ret_lines(char * layer);
- std::vector< text > ret_texts(char * layer);
- std::vector< ellipse > ret_ellipses(char * layer);
- std::vector< arc > ret_arcs(char * layer);
- std::vector< lwpolyline > ret_lwplines(char * layer);
- std::vector< insert > ret_inserts(char * layer);
-
- int plines_size();
- int circles_size();
- int lines_size();
- int texts_size();
-
-
-
- private:
- void add_polyline(polyline pline);
- void add_circle(circle circ);
- void add_line(line ln);
-
- std::vector< polyline > ents_polyline;
- std::vector< arc > ents_arc;
- std::vector< circle > ents_circle;
- std::vector< line > ents_line;
- std::vector< ellipse > ents_ellipse;
- std::vector< text > ents_text;
- std::vector< lwpolyline > ents_lwpolyline;
- std::vector< insert > ents_insert;
-
-
-};
-
-
-
-#endif
diff --git a/src/extension/dxf2svg/entities2elements.cpp b/src/extension/dxf2svg/entities2elements.cpp
deleted file mode 100644
index 8a17a0d84..000000000
--- a/src/extension/dxf2svg/entities2elements.cpp
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- * Code for converting dxf entities to SVG elements
- * There are multiple ways for converting different items
- * If possible most DXF enetities will be converted to paths because that is the most flexable object
- *
- * Author:
- * Matt Squires <squiresm@colorado.edu>
- *
- * Copyright (C) 2005 Matt Squires
- *
- * Released under GNU GPL and LGPL, read the file 'GPL.txt' and 'LGPL.txt' for details
- */
-
-
-
-/*
-
-Matt Squires
-SoC 2005
-
-*/
-
-#include "entities2elements.h"
-#include "tables2svg_info.h"
-#include <iostream>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-// The names indicate the DXF entitiy first and the SVG element last
-
-// Common elements
-char* to_arc(double bulge, double r, double start_ang, double end_ang, int precision,char* delim, char * units, double scaling, char *out){
- // This is used for arcs, polylines, and lwpolylines
- char temp[50];
-
- // Assume that we are adding to the input and not starting over
- strcat(out," A ");
- // For arcs there is only one radius
- strcat(out,gcvt(scaling*r,precision,temp) );
- strcat(out,",");
- strcat(out,gcvt(scaling*r,precision,temp) );
-
- strcat(out," 0"); // For arc assume no x-axis rotation. That seems to apply to elipse elements only
- // Determine if it is a large arc
- if ( (end_ang > start_ang) && ( (end_ang - start_ang) > 180) ){
- //strcat(out," 1,0 "); // Large arc flag...Always use a zero sweep flag
- strcat(out," 1, "); // Large arc flag...Always use a zero sweep flag
- }
- else{
- //strcat(out," 0,0 "); // Small arc flag...Always use a zero sweep flag
- strcat(out," 0,");
- }
- // This may be easier if I allow r to be plus and minus, but for now this works
- if (bulge > 0){
- strcat(out,"0 ");
- }
- else{
- strcat(out,"1 ");
- }
-}
-
-// Build Coordinate
-void coord(entity *ent, int precision,char* delim, char * units, double scaling, char *out){
- // Pairs of coords with units will be used so often build a function build a dedicated function for returning such
-
- char temp[20];
- if (units != NULL) scaling = 1; // If units have been defined then ignore the scaling parameter
- strcat(out, gcvt(scaling*ent->ret_x(),precision,temp) ); // There must be a better function for double to ascii conversion that is defined in most libraries
- if (units != NULL) strcat(out, units);
- strcat(out, delim);
- strcat(out, gcvt(-scaling*ent->ret_y(),precision,temp) ); // Because SVG has a the Y-axis pointed down multiply by -1
- if (units != NULL) strcat(out, units);
- strcat(out, " ");
-}
-
-// DXF Polyline -> SVG
-// General function for the conversion of a pline to a SVG element. Very similar functions just make accomidations for parts that may not be supported
-void pline2svg(polyline pline, int type, int precision, char * units, double scaling, tables plot_info, char *out){
- // 0 is pline2path
- // 1 is pline2pline
- // 2 is pline2polygon
-
-
- char delim[2];
-
- std::vector< vertex >::iterator vver_iter;
- std::vector< vertex > points = pline.ret_points();
-
- if (type < 1){
- // Put the first Move To at the first, everything else will be a lineto
- strcpy(delim," ");
- strcat(out, "M ");
- coord( &points[0], precision, delim, units, scaling, out );
- double prev_mag_bulge = sqrt(pow(points[0].ret_bulge(),2)); // Because the bulge value can be positive or negative calculate the magnitude
- if ( prev_mag_bulge > pow(0.1,precision) ){
- to_arc(pline.bulge(0), pline.bulge_r(0), pline.bulge_start_angle(0), pline.bulge_end_angle(0), precision, delim, units, scaling, out);
- }
- for (int i = 1; i < points.size(); i++){
- if ( prev_mag_bulge < pow(0.1,precision) ){
- // If the previous point was a bulge then don't use a line to
- strcat(out, "L ");
- }
- coord( &points[i], precision, delim, units, scaling, out );
- // If bulge > some precsion then add bulge
- double mag_bulge = sqrt(pow(points[i].ret_bulge(),2));
- if ( (mag_bulge > pow(0.1,precision)) && (i < (points.size() - 1) )){
- to_arc(pline.bulge(i), pline.bulge_r(i), pline.bulge_start_angle(i), pline.bulge_end_angle(i), precision, delim, units, scaling, out);
- }
- prev_mag_bulge = mag_bulge;
- }
- if ( pline.is_closed() ){
- strcat(out,"z");
- }
- strcat(out,"\" ");
- }
- else{
- strcpy(delim,",");
- for (int i = 0; i < points.size(); i++){
- coord( &points[i], precision, delim, NULL, scaling, out );
- // If bulge > some precsion then add bulge
- }
- // if the element is a SVG::pline and the DXF::pline is closed then simulate by adding an extra point
- if ( (type == 1) && pline.is_closed() ){
- coord( &points[0], precision, delim, NULL, scaling, out );
- }
- }
-
-}
-
-char* pline2path(polyline pline, char * units, double scaling, tables plot_info){
- // Convert a dxf polyline to a SVG path. This is the closest conversion of the DXF polyline to an SVG element
- char *out_ptr;
- char out[10000] = "<path d=\"";
- entity *ent_ptr = &pline;
- char temp[20];
- int precision = 6;
-
- pline2svg(pline, 0, precision, units, scaling, plot_info, out);
- // Add some line information
- strcat(out,"fill=\"none\" stroke=\"black\" stroke-width=\"1\" ");
- pattern2dasharray(plot_info.ret_ltype( ent_ptr->ret_ltype_name(temp),ent_ptr->ret_layer_name(temp) ), precision, scaling, out); // Add the linetype information
-
- strcat(out," />");
- out_ptr = out;
- return out_ptr;
-}
-
-char* pline2pline(polyline pline, char * units, double scaling, tables plot_info){
- // Convert a dxf polyline to a SVG polyline. The conversion is not 1:1 because the SVG pline doesn't support closed objects or curves
- entity *ent_ptr = &pline;
- char temp[2000];
- int precision = 6;
-
- char out[10000] = "<polyline fill=\"none\" stroke=\"black\" stroke-width=\"1\" ";
- ltype linfo = plot_info.ret_ltype(ent_ptr->ret_ltype_name(temp), ent_ptr->ret_layer_name(temp));
- pattern2dasharray(linfo, precision, scaling, out); // Add the linetype information
- //strcpy(temp," ");
-
- strcat(out,"points=\"");
-
- //strcat(out,"<polyline fill=\"none\" stroke=\"black\" stroke-width=\"1\" points=\"");
- pline2svg(pline, 1, precision, units, scaling, plot_info, out);
- // Add some line information
- // if the DXF pline is closed then add an extra point
-
- strcat(out,"\"/>");
- char *out_ptr = out;
- return out_ptr;
-}
-char* pline2polygon(polyline pline, char * units, double scaling, tables plot_info){
- // Convert a dxf polyline to a SVG polygon. The conversion is not 1:1 because the SVG polygone assumes a closed path. If the pline is not closed it will be forced closed
- //return pline2svg(pline, 2, 6, units, double scaling,out);
-}
-
-
-// DXF LWPolyline -> SVG
-
-
-// This could be a template with polyline and lwpolyline but right now it is not that important
-void lwpline2svg(lwpolyline pline, int type, int precision, char * units, double scaling, tables plot_info, char *out); // General function for the conversion of a pline to a SVG element. Very similar functions just make accomidations for parts that may not be supported
-void lwpline2svg(lwpolyline pline, int type, int precision, char * units, double scaling, tables plot_info, char *out){
- // 0 is pline2path
- // 1 is pline2pline
- // 2 is pline2polygon
-
-
- char delim[2];
-
- std::vector< vertex >::iterator vver_iter;
- std::vector< vertex > points = pline.ret_points();
-
- if (type < 1){
- // Put the first Move To at the first, everything else will be a lineto
- strcpy(delim," ");
- strcat(out, "M ");
- coord( &points[0], precision, delim, NULL, scaling, out );
- double prev_mag_bulge = sqrt(pow(points[0].ret_bulge(),2)); // Because the bulge value can be positive or negative calculate the magnitude
- if ( prev_mag_bulge > pow(0.1,precision) ){
- to_arc(pline.bulge(0),pline.bulge_r(0), pline.bulge_start_angle(0), pline.bulge_end_angle(0), precision, delim, NULL, scaling, out);
- }
-
- for (int i = 1; i < points.size(); i++){
- if ( prev_mag_bulge < pow(0.1,precision) ){
- // If the previous point was a bulge then don't use a line to
- strcat(out, "L ");
- }
- coord( &points[i], precision, delim, NULL , scaling, out );
- // If bulge > some precsion then add bulge
- double mag_bulge = sqrt(pow(points[i].ret_bulge(),2));
- if ( ( mag_bulge > pow(0.1,precision) ) && (i < (points.size() - 1) )){ // Make sure the final point doesn't add a bulge on accident
- to_arc(pline.bulge(i), pline.bulge_r(i), pline.bulge_start_angle(i), pline.bulge_end_angle(i), precision, delim, units, scaling, out);
- }
- prev_mag_bulge = mag_bulge;
- }
- if ( pline.is_closed() ){
- strcat(out,"z");
- }
- strcat(out,"\" ");
- }
- else{
- strcpy(delim,",");
- for (int i = 0; i < points.size(); i++){
- coord( &points[i], precision, delim, units, scaling, out );
- // If bulge > some precsion then add bulge
- }
- // if the element is a SVG::pline and the DXF::pline is closed then simulate by adding an extra point
- if ( (type == 1) && pline.is_closed() ){
- coord( &points[0], precision, delim, units, scaling, out );
- }
- }
-
-}
-
-char* lwpline2path(lwpolyline pline, char * units, double scaling, tables plot_info){
- // Convert a dxf polyline to a SVG path. This is the closest conversion of the DXF polyline to an SVG element
- char *out_ptr;
- char out[10000] = "<path d=\"";
- entity *ent_ptr = &pline;
- char temp[20];
- int precision = 6;
-
- lwpline2svg(pline, 0, precision, units, scaling, plot_info, out);
- // Add some line information
- strcat(out,"fill=\"none\" stroke=\"black\" stroke-width=\"1\" ");
- pattern2dasharray(plot_info.ret_ltype( ent_ptr->ret_ltype_name(temp),ent_ptr->ret_layer_name(temp) ), precision, scaling, out); // Add the linetype information
-
- strcat(out," />");
- out_ptr = out;
- return out_ptr;
-}
-
-// DXF ARC -> SVG
-char* arc2path(arc a, int precision, char * units, double scaling, tables plot_info, char *out){
- // So far this appears to be the only way to convert arcs into something recognized by SVG
- char *out_ptr;
- char temp[20];
- entity *ent_ptr = &a;
-
- strcpy(out,"<path d=\"M");
- // Calculate the starting point from the center and the start angle. As far as I can tell the rotation is CCW in the dxf notation and it in degrees
- strcat(out,gcvt(scaling*(ent_ptr->ret_x()+a.ret_radius()*cos( a.ret_srt_ang()*3.14159/180 )),precision,temp) );
- strcat(out," ");
- strcat(out,gcvt(-1*scaling*(ent_ptr->ret_y()+a.ret_radius()*sin( a.ret_srt_ang()*3.14159/180 )),precision,temp) );
- strcat(out," A ");
- // For arcs there is only one radius
- strcat(out,gcvt(scaling*a.ret_radius(),precision,temp) );
- strcat(out,",");
- strcat(out,gcvt(scaling*a.ret_radius(),precision,temp) );
-
- strcat(out," 0"); // For arc assume no x-axis rotation. That seems to apply to elipse elements only
- // Determine if it is a large arc
- if ( (a.ret_end_ang() > a.ret_srt_ang()) && ( (a.ret_end_ang() - a.ret_srt_ang()) > 180) ){
- strcat(out," 1,0 "); // Large arc flag...Always use a zero sweep flag
- }
- else{
- strcat(out," 0,0 "); // Small arc flag...Always use a zero sweep flag
- }
-
- //The final point
- strcat(out,gcvt(scaling*(ent_ptr->ret_x()+a.ret_radius()*cos( a.ret_end_ang()*3.14159/180 )),precision,temp) );
- strcat(out,",");
- strcat(out,gcvt(-1*scaling*(ent_ptr->ret_y()+a.ret_radius()*sin( a.ret_end_ang()*3.14159/180 )),precision,temp) );
- strcat(out,"\" fill=\"none\" stroke=\"black\" stroke-width=\"1\" ");
- ltype linfo = plot_info.ret_ltype(ent_ptr->ret_ltype_name(temp), ent_ptr->ret_layer_name(temp));
- pattern2dasharray(linfo, precision, scaling, out); // Add the linetype information
- strcat(out, " />");
-
-
- out_ptr = out;
- return out_ptr;
-
-}
-
-
-// DXF Circle -> SVG
-char* circle2circle(circle circ, int precision, char * units, double scaling, tables plot_info, char *out){
- // Direct conversion of DXF circle to SVG circle
- char *out_ptr;
- char temp[1000]="\" cy=\"";
- entity *ent_ptr = &circ;
- strcpy(out,"<circle cx=\"");
- coord(ent_ptr, precision,temp, units, scaling, out);
- strcat(out,"\" r=\"");
- strcat(out,gcvt(circ.ret_radius(),precision,temp) );
- strcat(out,units);
- strcat(out,"\" fill=\"none\" stroke=\"black\" stroke-width=\"1\" ");
- ltype linfo = plot_info.ret_ltype(ent_ptr->ret_ltype_name(temp), ent_ptr->ret_layer_name(temp));
- //plot_info.ret_ltype(ent_ptr->ret_ltype_name(temp), ent_ptr->ret_layer_name(temp));
- pattern2dasharray(linfo, precision, scaling, out); // Add the linetype information
- //pattern2dasharray(plot_info.ret_ltype(ent_ptr->ret_ltype_name(temp), ent_ptr->ret_layer_name(temp)), precision, scaling, out); // Add the linetype information
- strcat(out, " />");
- out_ptr = out;
- return out_ptr;
-}
-
-char* circle2path(circle circ, int precision, char * units, double scaling, tables plot_info, char *out){
- // Conversion of DXF circle to SVG circle assuming the path will represent the circle
-
- char *out_ptr;
- char temp[20]=",";
- entity *ent_ptr = &circ;
-
- strcpy(out,"<path d=\"M");
- // The starting point is x-r,y so subtract off the radius from the x coord
- strcat(out,gcvt(ent_ptr->ret_x()-circ.ret_radius(),precision,temp) );
- strcat(out," ");
- strcat(out,gcvt(ent_ptr->ret_y(),precision,temp) );
-
- strcat(out," a");
- strcat(out,gcvt(circ.ret_radius(),precision,temp) );
- strcat(out,",");
- strcat(out,gcvt(circ.ret_radius(),precision,temp) );
- strcat(out,"0 0,0 0,0\" fill=\"none\" stroke=\"black\" stroke-width=\"1\"");
-
- out_ptr = out;
- return out_ptr;
-}
-
-
-// DXF Line -> SVG
-char* line2line(line ln, int precision, char * units, double scaling, tables plot_info, char *out){
- // Directly convert DXF to SVG because it works
- char *out_ptr;
- char temp[20];
- entity *ent_ptr = &ln;
-
- strcpy(out,"<line x1=\"");
- strcat(out,gcvt(ent_ptr->ret_x(),precision,temp) );
- strcat(out,units);
- strcat(out,"\" y1=\"");
- strcat(out,gcvt(-1*ent_ptr->ret_y(),precision,temp) ); // Put in an extra minus because of the way SVG has defined the axis
- strcat(out,units);
-
- strcat(out,"\" x2=\"");
- strcat(out,gcvt(ln.ret_xf(),precision,temp) );
- strcat(out,units);
- strcat(out,"\" y2=\"");
- strcat(out,gcvt(-1*ln.ret_yf(),precision,temp) ); // Put in an extra minus because of the way SVG has defined the axis
- strcat(out,units);
- strcat(out,"\" stroke-width=\"1\" stroke=\"black\" ");
- ltype linfo = plot_info.ret_ltype(ent_ptr->ret_ltype_name(temp), ent_ptr->ret_layer_name(temp));
- pattern2dasharray(linfo, precision, scaling, out); // Add the linetype information
- strcat(out, " />");
-
- out_ptr = out;
- return out_ptr;
-}
-
-
-char* line2path(line ln, int precision, char * units, double scaling, tables plot_info, char *out){
- // Convert DXF line to SVG path
-
- char *out_ptr;
- char temp[20];
- entity *ent_ptr = &ln;
-
- strcpy(out,"<path d=\"M");
- strcat(out,gcvt(scaling*ent_ptr->ret_x(),precision,temp) );
- strcat(out," ");
- strcat(out,gcvt(scaling*ent_ptr->ret_y(),precision,temp) );
-
- strcat(out," L");
- strcat(out,gcvt(scaling*ln.ret_xf(),precision,temp) );
- strcat(out," ");
- strcat(out,gcvt(scaling*ln.ret_yf(),precision,temp) );
- strcat(out,"\" fill=\"none\" stroke=\"black\" stroke-width=\"1\" /");
-
- out_ptr = out;
- return out_ptr;
-}
-
-// DXF Text -> SVG
-char* text2text(text txt, int precision, char * units, double scaling, tables plot_info, char *out){
- // Directly convert DXF to SVG because it works
- char *out_ptr;
- char temp[10000];
- entity *ent_ptr = &txt;
-
- // If the text is rotated use the transform matrix
-
- if ( txt.ret_txt_rot() > precision ){
- double ca = cos(0.017453*txt.ret_txt_rot()); // ca = cosine(a)
- double sa = sin(-0.017453*txt.ret_txt_rot()); // sa = sine(a)
- double tx = ent_ptr->ret_x()*scaling;
- double ty = -ent_ptr->ret_y()*scaling;
- // Apply a translation to the orgin, then a rotation, then a translation back to the original position
- double a = ca;
- double b = sa;
- double c = -sa;
- double d = ca;
- double e = -1*(tx*ca-ty*sa-tx);
- double f = -1*(tx*sa+ty*ca-ty);
-
- strcpy(out, "<g transform=\"matrix(");
- strcat(out,gcvt(a,precision,temp) );
- strcat(out," ");
- strcat(out,gcvt(b,precision,temp) );
- strcat(out," ");
- strcat(out,gcvt(c,precision,temp) );
- strcat(out," ");
- strcat(out,gcvt(d,precision,temp) );
- strcat(out," ");
- strcat(out,gcvt(e,precision,temp) );
- strcat(out," ");
- strcat(out,gcvt(f,precision,temp) );
- strcat(out,")\" >\n<text x=\"");
- }
- else{
- strcpy(out,"<text x=\"");
- }
- /*
- strcat(out,gcvt(ent_ptr->ret_x(),precision,temp) );
- strcat(out,units);
- strcat(out,"\" y=\"-"); // Put in an extra minus because of the way SVG has defined the axis
- strcat(out,gcvt(ent_ptr->ret_y(),precision,temp) );
- strcat(out,units);
- */
- strcat(out,gcvt(ent_ptr->ret_x()*scaling,precision,temp) );
- //strcat(out,units);
- strcat(out,"\" y=\"-"); // Put in an extra minus because of the way SVG has defined the axis
- strcat(out,gcvt(ent_ptr->ret_y()*scaling,precision,temp) );
- //strcat(out,units);
- strcat(out,"\" font-family=\"Verdana\" font-size=\"");
- strcat(out,gcvt(scaling*txt.ret_txt_ht(),precision,temp) );
- strcat(out,"\" Fill=\"black\"");
-
- strcat(out," >");
- // Now put in the text
- strcat(out,txt.ret_text(temp));
-
- // Now close the text element
- strcat(out,"</text>");
- // If the text was rotated finish off the tranform group
- if ( txt.ret_txt_rot() > precision ){
- strcat(out,"</g>");
- }
-
- out_ptr = out;
- return out_ptr;
-}
-
-
-
-// DXF Insert -> SVG
-char* insert2group(insert in, int precision, char * units, double scaling, tables plot_info, blocks blks, char *out){
- char *out_ptr;
- char tmp_char[100000];
-
- // get the block using the name from the insert information
- block blk = blks.ret_block(in.name(tmp_char));
-
- entity *ent_ptr = &in;
- entities *ents_ptr = &blk;
- // For now just translations MBS 22 Aug 05
- strcpy(out, "<g transform=\"matrix(1,0,0,1,");
- strcat(out,gcvt(scaling*ent_ptr->ret_x(),precision,tmp_char) );
- strcat(out,",");
- strcat(out,gcvt(-scaling*ent_ptr->ret_y(),precision,tmp_char) );
- strcat(out,")\" >\n");
-
-
- // Now convert the entities in the block
- std::vector< polyline > plines = ents_ptr->ret_plines();
- std::vector< lwpolyline > lwplines = ents_ptr->ret_lwplines();
- std::vector< arc > arcs = ents_ptr->ret_arcs();
- std::vector< circle > circs = ents_ptr->ret_circles();
- std::vector< line > lns = ents_ptr->ret_lines();
- std::vector< text > txts = ents_ptr->ret_texts();
-
-
-
- for(int i = 0; i < plines.size();i++){
- strcat( out,pline2pline(plines[i], units, scaling, plot_info ) );
- strcat( out, "\n" );
- }
- for(int i = 0; i < lwplines.size();i++){
- strcat( out,lwpline2path(lwplines[i], units, scaling, plot_info ) );
- strcat( out, "\n" );
- }
- for(int i = 0; i < arcs.size();i++){
- strcat( out, arc2path(arcs[i], 6,units, scaling, plot_info, tmp_char ) );
- strcat( out, "\n" );
- }
- for(int i = 0; i < circs.size();i++){
- strcat( out, circle2circle(circs[i], 6, units, scaling, plot_info, tmp_char) );
- strcat( out, "\n" );
- }
- for(int i = 0; i < lns.size();i++){
- strcat( out, line2line(lns[i], 6, units, scaling, plot_info, tmp_char) );
- strcat( out, "\n" );
- }
- for(int i = 0; i < txts.size();i++){
- strcat( out, text2text(txts[i], 6, units, scaling, plot_info, tmp_char) );
- strcat( out, "\n" );
- }
- // End the group
- strcat(out,"</g>");
-
- out_ptr = out;
- return out_ptr;
-}
-
-
-
-char* write_by_layer(int output_type, entities &ents, tables &tbls, blocks &blks, double scaling, char * units, char * layer, char * out){
- // output_type = 0 is to std:out
- // output_type = 1 is to the input filename but with .dxf on the end
-
- // For now everything will go to stdout later may directed to other places
-
- // Get the various file informations as dependent on the layer type
- std::vector< polyline > plines = ents.ret_plines(layer);
- std::vector< lwpolyline > lwplines = ents.ret_lwplines(layer);
- std::vector< arc > arcs = ents.ret_arcs(layer);
- std::vector< circle > circs = ents.ret_circles(layer);
- std::vector< line > lns = ents.ret_lines(layer);
- std::vector< text > txts = ents.ret_texts(layer);
- std::vector< insert > ins = ents.ret_inserts(layer);
-
- // It would be better to redirect stdout to different places. That would make the code cleaner but I don't think it will work better
- char tmp_char[100000];
- for(int i = 0; i < plines.size();i++){
- if (output_type == 0){
- std::cout << "\t" << pline2path(plines[i], NULL, scaling, tbls ) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << pline2path(plines[i], NULL, scaling, tbls ) << std::endl;
- }
- }
- for(int i = 0; i < lwplines.size();i++){
- if (output_type == 0){
- std::cout << "\t" << lwpline2path(lwplines[i], units, scaling, tbls ) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << lwpline2path(lwplines[i], units, scaling, tbls ) << std::endl;
- }
- }
- for(int i = 0; i < arcs.size();i++){
- if (output_type == 0){
- std::cout << "\t" << arc2path(arcs[i], 6,units, scaling, tbls, tmp_char ) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << arc2path(arcs[i], 6,units, scaling, tbls, tmp_char ) << std::endl;
- }
- }
- for(int i = 0; i < circs.size();i++){
- if (output_type == 0){
- std::cout << "\t" << circle2circle(circs[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << circle2circle(circs[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- }
- for(int i = 0; i < lns.size();i++){
- if (output_type == 0){
- std::cout << "\t" << line2line(lns[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << line2line(lns[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- }
- for(int i = 0; i < txts.size();i++){
- if (output_type == 0){
- std::cout << "\t" << text2text(txts[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << text2text(txts[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- }
- for(int i = 0; i < ins.size();i++){
- if (output_type == 0){
- std::cout << "\t" << insert2group(ins[i], 6, units, scaling, tbls, blks, tmp_char) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << insert2group(ins[i], 6, units, scaling, tbls, blks, tmp_char) << std::endl;
- }
- }
-}
-
-
-
-char* write_all(int output_type, entities &ents, tables &tbls, blocks &blks, double scaling, char * units, char * out){
- // output_type = 0 is to std:out
- // output_type = 1 is to the input filename but with .dxf on the end
-
- // For now everything will go to stdout later may directed to other places
-
- // Get the various file informations as dependent on the layer type
- std::vector< polyline > plines = ents.ret_plines();
- std::vector< lwpolyline > lwplines = ents.ret_lwplines();
- std::vector< arc > arcs = ents.ret_arcs();
- std::vector< circle > circs = ents.ret_circles();
- std::vector< line > lns = ents.ret_lines();
- std::vector< text > txts = ents.ret_texts();
- std::vector< insert > ins = ents.ret_inserts();
-
- // It would be better to redirect stdout to different places. That would make the code cleaner but I don't think it will work better
- char tmp_char[100000];
- for(int i = 0; i < plines.size();i++){
- if (output_type == 0){
- std::cout << "\t" << pline2path(plines[i], NULL, scaling, tbls ) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << pline2path(plines[i], NULL, scaling, tbls ) << std::endl;
- }
- }
- for(int i = 0; i < lwplines.size();i++){
- if (output_type == 0){
- std::cout << "\t" << lwpline2path(lwplines[i], units, scaling, tbls ) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << lwpline2path(lwplines[i], units, scaling, tbls ) << std::endl;
- }
- }
- for(int i = 0; i < arcs.size();i++){
- if (output_type == 0){
- std::cout << "\t" << arc2path(arcs[i], 6,units, scaling, tbls, tmp_char ) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << arc2path(arcs[i], 6,units, scaling, tbls, tmp_char ) << std::endl;
- }
- }
- for(int i = 0; i < circs.size();i++){
- if (output_type == 0){
- std::cout << "\t" << circle2circle(circs[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << circle2circle(circs[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- }
- for(int i = 0; i < lns.size();i++){
- if (output_type == 0){
- std::cout << "\t" << line2line(lns[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << line2line(lns[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- }
- for(int i = 0; i < txts.size();i++){
- if (output_type == 0){
- std::cout << "\t" << text2text(txts[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << text2text(txts[i], 6, units, scaling, tbls, tmp_char) << std::endl;
- }
- }
- for(int i = 0; i < ins.size();i++){
- if (output_type == 0){
- std::cout << "\t" << insert2group(ins[i], 6, units, scaling, tbls, blks, tmp_char) << std::endl;
- }
- else if (output_type == 1){
- std::cout << "\t" << insert2group(ins[i], 6, units, scaling, tbls, blks, tmp_char) << std::endl;
- }
- }
-}
-
-
-
diff --git a/src/extension/dxf2svg/entities2elements.h b/src/extension/dxf2svg/entities2elements.h
deleted file mode 100644
index cceefcf15..000000000
--- a/src/extension/dxf2svg/entities2elements.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Method for converting dxf entities to SVG elements
-There are multiple ways for converting different items
-
-If possible most DXF enetities will be converted to paths because that is the most flexable object
-
-Matt Squires
-SoC 2005
-
-*/
-
-#include"entities.h"
-#include"tables.h"
-#include"blocks.h"
-
-// The names indicate the DXF entitiy first and the SVG element last
-
-// Common elements
-char* to_arc(double bulge, double r, double start_ang, double end_ang, int precision,char* delim, char * units, double scaling, char *out); // This is used for arcs, polylines, and lwpolylines
-
-// DXF Polyline -> SVG
-
-char* pline2path(polyline pline, char * units, double scaling, tables plot_info); // Convert a dxf polyline to a SVG path. This is the closest conversion of the DXF polyline to an SVG element
-char* pline2pline(polyline pline, char * units, double scaling, tables plot_info); // Convert a dxf polyline to a SVG polyline. The conversion is not 1:1 because the SVG pline doesn't support closed objects or curves
-char* pline2polygon(polyline pline, char * units, double scaling, tables plot_info); // Convert a dxf polyline to a SVG polygon. The conversion is not 1:1 because the SVG polygone assumes a closed path. If the pline is not closed it will be forced closed
-
-// DXF LWPolyline -> SVG
-char* lwpline2path(lwpolyline pline, char * units, double scaling, tables plot_info); // Convert a dxf polyline to a SVG path. This is the closest conversion of the DXF polyline to an SVG element
-
-// DXF ARC -> SVG
-char* arc2path(arc a, int precision, char * units, double scaling, tables plot_info, char *out); // So far this appears to be the only way to convert arcs into something recognized by SVG
-
-
-// DXF Circle -> SVG
-char* circle2circle(circle circ, int precision, char * units, double scaling, tables plot_info, char *out); // Direct conversion of DXF circle to SVG circle
-char* circle2path(circle circ, int precision, char * units, double scaling, tables plot_info, char *out); // Conversion of DXF circle to SVG circle assuming the path will represent the circle
-
-
-// DXF Line -> SVG
-char* line2line(line ln, int precision, char * units, double scaling, tables plot_info, char *out); // Directly convert DXF to SVG because it works
-char* line2path(line ln, int precision, char * units, double scaling, tables plot_info, char *out); // Convert DXF line to SVG path
-
-// DXF Text -> SVG
-char* text2text(text txt, int precision, char * units, double scaling, tables plot_info, char *out); // Directly convert DXF to SVF assuming VERANDA font
-
-// DXF Insert -> SVG
-char* insert2group(insert in, int precision, char * units, double scaling, tables plot_info, blocks blks, char *out);
-
-// Write all of the possible enties with a variety of options
-
-char* write_by_layer(int output_type, entities &ents, tables &tbls, blocks &blks, double scaling, char * units, char * layer, char * out); // Write out the entities by layer designation
-char* write_all(int output_type, entities &ents, tables &tbls, blocks &blks, double scaling, char * units, char * out);
-
-
diff --git a/src/extension/dxf2svg/read_dxf.cpp b/src/extension/dxf2svg/read_dxf.cpp
deleted file mode 100644
index 1a4eefbc9..000000000
--- a/src/extension/dxf2svg/read_dxf.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * For reading and slight parsing of dxf files
- *
- * Author:
- * Matt Squires <squiresm@colorado.edu>
- *
- * Copyright (C) 2005 Matt Squires
- *
- * Released under GNU GPL and LGPL, read the file 'GPL.txt' and 'LGPL.txt' for details
- */
-
-
-
-#include <fstream>
-#include <string>
-#include "read_dxf.h"
-
-#include <iostream>
-#include <string.h>
-#include <stdlib.h>
-using namespace std;
-
-
-int MAX_STR_LN = 10000;
-
-int section(char* value){
- if ( strncmp(value,"HEADER",6) == 0 ) return 0;
- if ( strncmp(value,"CLASSES",7) == 0 ) return 1;
- if ( strncmp(value,"TABLES",6) == 0 ) return 2;
- if ( strncmp(value,"BLOCKS",6) == 0 ) return 3;
- if ( strncmp(value,"ENTITIES",8) == 0 ) return 4;
- if ( strncmp(value,"OBJECTS",7) == 0 ) return 5;
- if ( strncmp(value,"THUMBNAILIMAGE",14) == 0 ) return 6;
-}
-
-
-dxfpair::dxfpair(int gcode, char val[10000]){
- group_code = gcode;
- // Dynamically save the strings, otherwise the memory uses is bad
-
- for (int i = 0; i < strlen(val); i++){
- value.push_back(val[i]);
- }
-}
-
-
-dxfpair::~dxfpair(){
- //delete [] value;
-}
-
-char * dxfpair::value_char(char *string){
- int size = value.size();
- while( ( size > 0 ) && int(value[size-1]) < 33){
- // Strip off any control characters and spaces off the end of the string
- size--;
- }
- for(int i = 0; i < size; i++){
- string[i] = value[i];
- }
- string[size]=0;
-}
-
-std::vector< std::vector< dxfpair > > dxf_get_sections(char* filename){
- // In the dxf format information is paired into group codes that indicate the information that follows on the next line. The information on the next line is called the value
-
- int n =0;
-
- int group_code;
- char value[MAX_STR_LN];
-
- int section_num;
-
-
-
-
- std::vector< std::vector< dxfpair > > out;
-
- std::vector< dxfpair > header;
- std::vector< dxfpair > classes;
- std::vector< dxfpair > tables;
- std::vector< dxfpair > blocks;
- std::vector< dxfpair > entities;
- std::vector< dxfpair > objects;
- std::vector< dxfpair > thumbnailimage;
-
- header.clear();
- classes.clear();
- tables.clear();
- blocks.clear();
- entities.clear();
- objects.clear();
- thumbnailimage.clear();
-
-
- // Open dxf file for reading
- std::ifstream file(filename);
-
- if (!file.is_open()){
- exit (1); // Change this to an exception
- }
-
- // Find the first SECTION header
-
- while ( (!file.eof()) ){
- n++;
-
- // get the first group code and value
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
-
- do{
-
- // TO DO set all the chars to be caps for later comparison
-
- // Find the SECTION codes
- if ( (group_code == 0 ) && ( strncmp(value,"SECTION",7) == 0 ) ){
- // Directly after a section value is the type of section ( e.g. HEADER, TABLES )
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- section_num = section( value );
- if ( group_code == 2 ){
- // Make sure the the group code is 2 for the SECTION name
- // This is a big block of mostly repetitive code, it will result in larger code, but would be faster than putting the switch in another while loop. If I still live in a time when file size mattered alot I would change it
- //std::cout << "section_num = " << section_num << std::endl;
- switch ( section_num ){
- case 0:
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- do{
- header.push_back( dxfpair( group_code, value ) );
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
- break;
- case 1:
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- if ( (group_code != 0) || (strncmp(value,"ENDSEC",6) != 0) ){
- // Some dxf files have blank sections. These are not handled by the do/while loop so break about if needed
- do{
- classes.push_back( dxfpair( group_code, value ) );
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
- }
- break;
- case 2:
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- do{
- tables.push_back( dxfpair( group_code, value ) );
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) );
- break;
- case 3:
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- do{
- blocks.push_back( dxfpair( group_code, value ) );
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
- break;
- case 4:
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- do{
- entities.push_back( dxfpair( group_code, value ) );
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
- break;
- case 5:
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- do{
- objects.push_back( dxfpair( group_code, value ) );
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
- break;
- case 6:
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- do{
- thumbnailimage.push_back( dxfpair( group_code, value ) );
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- }while( ( (group_code != 0) || strncmp(value,"ENDSEC",6) != 0 ) && (!file.eof()) ); // I put in the (group_code != 0) in the hope that it will be a faster bool compare than the string compare. Test this later
- break;
- default:
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
- }
- }
- }
- file.getline(value,MAX_STR_LN);
- group_code = atoi(value);
- file.getline(value,MAX_STR_LN);
-
- n++;
- }while( ( strncmp(value,"EOF",3) != 0 ) && (!file.eof()) );
- }
-
- out.push_back(header);
- out.push_back(classes);
- out.push_back(tables);
- out.push_back(blocks);
- out.push_back(entities);
- out.push_back(objects);
- out.push_back(thumbnailimage);
-
- return out;
-}
-
-
-std::vector< std::vector< dxfpair > > separate_parts( std::vector< dxfpair > section){
- //std::cout << "1" << std::endl;
- //std::cout << "section.size() = " << section.size() << std::endl;
- // Find where the major sections are and break into smaller parts
- // Major section is defined as anything beween group_code 0 to 0
- std::vector< dxfpair > inner;
- std::vector< std::vector< dxfpair > > outer;
- //std::cout << "2" << std::endl;
- for (int i = 0; i < section.size(); i++){
- //std::cout << "i = " << i << std::endl;
- //std::cout << "section[i].value.size() = " << section[i].value.size() << std::endl;
-
- // Make sure no control codes like LF or CR are making it past this section
- if ( (section[i].value.size() > 0) && int(section[i].value.back()) < 32 ){
- section[i].value.pop_back();
- }
- //for(int j = 0;j < section[i].value.size();j++ ) std::cout << section[i].value[j];
- //std::cout << std::endl;
-
- inner.push_back( section[i] );
-
- // If the next group code is 0 then push the previously found info on outer and start looking for data again
- if (section[i+1].group_code == 0){
- //std::cout << "inner.push_back" << std::endl;
- outer.push_back( inner );
- inner.clear();
- }
- }
- // Because putting the data on outer depends on find a GC=0 the last bit of data may be left behind so it inner has data in it put it on outer
- if (!inner.empty()){
- outer.push_back( inner );
- inner.clear();
- }
- //std::cout << "3" << std::endl;
- if (section.back().group_code == 0){
- //outer.push_back( inner ); // Put the last part on if there is information, but I don't think it needs to.
- }
-
- return outer;
-}
-
diff --git a/src/extension/dxf2svg/read_dxf.h b/src/extension/dxf2svg/read_dxf.h
deleted file mode 100644
index 7e008b4e0..000000000
--- a/src/extension/dxf2svg/read_dxf.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Header file for reading dxf information and basic parsing. Interprting information is found in other files
-*/
-
-#ifndef READ_DXF_H
-#define READ_DXF_H
-
-#include<vector>
-
-
-
-class dxfpair{
-public:
- dxfpair(int gcode, char val[10000]);
- virtual ~dxfpair();
-
- char * value_char(char *string);
-
- // Leave this data public
- int group_code;
- std::vector< char > value;
-};
-
-
-
-
-int section(char* value); // Convert the section titles into integers
-
-std::vector< std::vector< dxfpair > > dxf_get_sections(char* filename);
-
-std::vector< std::vector< dxfpair > > separate_parts( std::vector< dxfpair > section ); // Find where the major sections are and break into smaller parts
-
-#endif
diff --git a/src/extension/dxf2svg/tables.cpp b/src/extension/dxf2svg/tables.cpp
deleted file mode 100644
index fcaff33c0..000000000
--- a/src/extension/dxf2svg/tables.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Code for the conversion of DXF information in the TABLES section
- *
- * Author:
- * Matt Squires <squiresm@colorado.edu>
- *
- * Copyright (C) 2005 Matt Squires
- *
- * Released under GNU GPL and LGPL, read the file 'GPL.txt' and 'LGPL.txt' for details
- */
-
-#include"tables.h"
-#include<iostream>
-
-
-
-
-int determine_table(char* value){
- // Common Elements as far as I am concerend
- if ( strncmp(value,"LAYER",5) == 0 ) return 0;
- if ( strncmp(value,"LTYPE",5) == 0 ) return 1;
- if ( strncmp(value,"STYLE",5) == 0 ) return 2;
- if ( strncmp(value,"UCS",3) == 0 ) return 3;
- if ( strncmp(value,"VIEW",4) == 0 ) return 4;
- if ( strncmp(value,"VPORT",4) == 0 ) return 5;
- if ( strncmp(value,"APPID",5) == 0 ) return 6;
- if ( strncmp(value,"BLOCK_RECORD",12) == 0 ) return 7;
- else return -1;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// TABLE
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-int table::ret_maxN(){
- return max_number;
-}
-
-
-
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// LAYER
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-layer::layer( std::vector< dxfpair > info){
- // Get the vertex information
-
- //basic_entity( info );
- //static char string[10000];
- char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 2:
- info[i].value_char(layer_name);
- break;
- case 6:
- info[i].value_char(ltype_name);
- break;
-
- case 62:
- info[i].value_char(string);
- color_number = atoi(string);
- //std::cout << "I found a color and its number = " << color_number << std::endl;
- break;
- case 290:
- info[i].value_char(string);
- plotting_flag = atoi(string);
- break;
- }
- }
-}
-
-void layer::display(){
- std::cout << "LAYER\n";
- //std::cout << "\tx = " << x << "\ty = " << y << "\tz = " << z << "\tbulge = " << bulge << std::flush;
-}
-
-char* layer::name(char* string){
- return( strcpy(string,layer_name) );
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// LTYPE
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-ltype::ltype( std::vector< dxfpair > info){
- // Get the linetype information
-
- //static char string[10000];
- char string[10000];
- for (int i = 0; i < info.size(); i++){
- switch( info[i].group_code ){
- case 2:
- info[i].value_char(ltype_name);
- break;
- case 3:
- info[i].value_char(descriptive_txt);
- break;
- case 73:
- info[i].value_char(string);
- num_elements = atoi(string);
- break;
- case 40:
- info[i].value_char(string);
- pattern_length = atof(string);
- break;
- case 49:
- info[i].value_char(string);
- pattern.push_back( atof(string) );
- break;
- }
- }
-}
-
-
-
-char* ltype::name(char* string){
- return( strcpy(string,ltype_name) );
-}
-
-
-std::vector< double > ltype::ret_pattern(){
- return pattern;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// tables
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-
-tables::tables(std::vector< std::vector< dxfpair > > sections){
- // Read the main information about the entities section and then put it in the enetites class
- int value;
- char string[10000];
-
- for(int i = 0; i < sections.size(); i++){
- //std::cout << "start" << std::endl;
- sections[i][0].value_char(string);
- value = determine_table(string);
- //std::cout << "sections.size() = " << sections.size() << std::endl << "i = " << i << std::endl << "string = " << string << std::endl;
- switch( value ){
- case 0:
- // LAYER
- //std::cout << "tables start layer " << std::endl;
- tables_layer.push_back( layer( sections[i] ) );
- //std::cout << "tables end layer " << std::endl;
- break;
-
- case 1:
- // LTYPE
- //std::cout << "tables start ltype " << std::endl;
- tables_ltype.push_back( ltype( sections[i] ) );
- //std::cout << "tables end ltype " << std::endl;
- break;
-
- //case 3:
- // break;
-
- default:
- break;
- // Nothing here
- }
-
- }
-
-}
-
-
-
-
-ltype tables::ret_ltype(char ltype_name[10000], char layer_name[10000]){
- int string_len = 0;
- char name[10000];
- char temp[10000];
- // The ltype information may be given in the entitity or in the layer information
- // Assume that if there is a name defined in the linetype that it trumps any other layer information
- if ( strlen(ltype_name) > 0 ) strcpy(name,ltype_name);
- else strcpy(name,layer_name);
- for (int i = 0; i < tables_ltype.size();i++){
- string_len = strlen(tables_ltype[i].name(temp));
- if (strncmp(tables_ltype[i].name(temp),name,string_len) == 0 ) return tables_ltype[i];
- }
- return tables_ltype[0];
-}
-
-
-layer tables::ret_layer(char layer_name[10000]){
- int string_len = 0;
- char temp[10000];
-
- for (int i = 0; i < tables_layer.size();i++){
- string_len = strlen(tables_layer[i].name(temp));
- if (strncmp(tables_layer[i].name(temp),layer_name,string_len) == 0 ) return tables_layer[i];
- }
- return tables_layer[0];
-}
-
-
-std::vector< layer > tables::ret_layers(){
- return tables_layer;
-}
diff --git a/src/extension/dxf2svg/tables.h b/src/extension/dxf2svg/tables.h
deleted file mode 100644
index f63122eaf..000000000
--- a/src/extension/dxf2svg/tables.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Code for the conversion of DXF information in the TABLES section
-Matt Squires
-SoC
-2005*/
-
-#ifndef DXF_TABLES_H
-#define DXF_TABLES_H
-
-#include<vector>
-#include"read_dxf.h"
-
-class table{
- public:
- int ret_maxN();
- private:
- int max_number;
-};
-
-
-class layer : public table{
- public:
- layer( std::vector< dxfpair > info);
- void display();
- char* name(char* string);
- private:
- char layer_name[10000];
- char ltype_name[10000]; // The layer may also hold the ltype infomation
- int color_number;
- int plotting_flag;
-
-};
-
-
-class ltype : public table{
- public:
- ltype( std::vector< dxfpair > info);
- char* name(char* string);
- std::vector< double > ret_pattern();
- private:
- char ltype_name[10000];
- char descriptive_txt[10000];
- int num_elements;
- double pattern_length;
- std::vector< double > pattern;
-
-};
-
-
-class tables{
- // Well I said that I would only use STL containers internally, but I would have to use a dynamically linked list, and I haven't done for a long time soo STL is my crutch.
- public:
- tables(std::vector< std::vector< dxfpair > > sections); // Put the various entities into their respective vectors
- void display_all();
-
- ltype ret_ltype(char ltype_name[10000], char layer_name[10000]);
- layer ret_layer(char layer_name[10000]);
-
- std::vector< layer > ret_layers();
-
-
- private:
- //void add_dimstyle(polyline pline);
- void add_layer(layer layr);
- void add_ltype(ltype line_type);
-
- std::vector< layer > tables_layer;
- std::vector< ltype > tables_ltype;
-};
-
-
-#endif
diff --git a/src/extension/dxf2svg/tables2svg_info.cpp b/src/extension/dxf2svg/tables2svg_info.cpp
deleted file mode 100644
index c59060306..000000000
--- a/src/extension/dxf2svg/tables2svg_info.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Convert DXF table information to a format that is recognized by SVG
- *
- * Author:
- * Matt Squires <squiresm@colorado.edu>
- *
- * Copyright (C) 2005 Matt Squires
- *
- * Released under GNU GPL and LGPL, read the file 'GPL.txt' and 'LGPL.txt' for details
- */
-
-
-#include "tables2svg_info.h"
-#include <math.h>
-#include <iostream>
-#include <stdlib.h>
-#include <string.h>
-
-char* pattern2dasharray(ltype info, int precision, double scaling, char* out){
- std::vector< double > pattern = info.ret_pattern();
- char temp[50];
- char *out_ptr;
-
-
- if (!pattern.empty()){
- strcat(out," stroke-dasharray=\"");
- for(int i = 0; i < pattern.size()-1;i++){
- strcat(out,gcvt(scaling*sqrt(pow(pattern[i],2)),precision,temp) );
- strcat(out,",");
- }
- strcat( out,gcvt(scaling*sqrt(pow(pattern[pattern.size()-1],2)),precision,temp) );
- strcat(out,"\" ");
- }
-
- out_ptr = out;
- return out_ptr;
-}
diff --git a/src/extension/dxf2svg/tables2svg_info.h b/src/extension/dxf2svg/tables2svg_info.h
deleted file mode 100644
index 2c99f034e..000000000
--- a/src/extension/dxf2svg/tables2svg_info.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* Convert DXF table information to a format that is recognized by SVG
-Matt Squires
-SOC 2005
-*/
-
-
-#include"tables.h"
-
-char* pattern2dasharray(ltype info, int precision, double scaling, char* temp);
diff --git a/src/extension/dxf2svg/test_dxf.cpp b/src/extension/dxf2svg/test_dxf.cpp
deleted file mode 100644
index c3bbdc141..000000000
--- a/src/extension/dxf2svg/test_dxf.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/* test read_dxf */
-#include"read_dxf.h"
-#include"entities.h"
-#include"blocks.h"
-#include"tables.h"
-#include<iostream>
-#include"entities2elements.h"
-
-using namespace std;
-
-int main(){
- std::vector< std::vector< dxfpair > > output, entities_info, blocks_info, tables_info;
- //output = dxf_get_sections("circ_sqr.dxf");
- //output = dxf_get_sections("Labjack.dxf");
- //output = dxf_get_sections("mini_post.dxf");
- //output = dxf_get_sections("../8599-E0W.dxf");
- //output = dxf_get_sections("../bulged_lwpoly.dxf");
- //output = dxf_get_sections("../aspheric_lens.dxf");
- output = dxf_get_sections("../layers_colors.dxf");
- /*std::vector< dxfpair > header;
- std::vector< dxfpair > classes;
- std::vector< dxfpair > tables;
- std::vector< dxfpair > blocks;
- std::vector< dxfpair > entities;
- std::vector< dxfpair > objects;
- std::vector< dxfpair > thumbnailimage;
- */
-
-
- //dxf_get_sections("circ_sqr.dxf",header,classes,tables,blocks,entities,objects,thumbnailimage);
- //dxf_get_sections("mini_post.dxf",header,classes,tables,blocks,entities,objects,thumbnailimage);
-
- //cout << entities.size() << endl;
- for (int i=0;i<output.size();i++) cout << "output[i].size()" << i << " = " << output[i].size() << endl;
- //cout << endl;
- //for (int i=0;i<output[0].size();i++) cout << output[0][i].group_code << "\t" << output[0][i].value << endl;
- //cout << endl;
- //for (int i=0;i<output[4].size();i++) cout << output[4][i].group_code << "\t" << output[4][i].value << endl;
-
- // Now display the different parts of the entities section
- //cout << endl;
- for (int i=0;i < output[4].size();i++){
- //cout << output[4][i].group_code << " " << output[4][i].value[0] << output[4][i].value[1] << endl;
- }
- cout << endl;
- entities_info = separate_parts(output[4]);
- cout << "entities_info.size() = " << entities_info.size() << endl;
-
- for (int i=0;i < entities_info.size();i++){
- //for (int j=0;j < entities_info[i].size();j++) cout << entities_info[i][j].group_code << " " << entities_info[i][j].value[0] << entities_info[i][j].value[1] << entities_info[i][j].value[2] << entities_info[i][j].value[3] << entities_info[i][j].value[4] << "\n";
- //cout << endl << endl << endl;
- }
-
- cout << "blocks separate parts" << endl;
- blocks_info = separate_parts(output[3]); // Tables is the 4th part of a dxf file.
- cout << "sort separated parts" << endl;
- blocks blks(blocks_info); // Sort the information in the tables
- cout << "blocks_info.size() = " << blocks_info.size() << endl;
-
- for (int i=0;i < blocks_info.size();i++){
- //for (int j=0;j < blocks_info[i].size();j++) cout << blocks_info[i][j].group_code << " " << blocks_info[i][j].value[0] << blocks_info[i][j].value[1] << blocks_info[i][j].value[2] << blocks_info[i][j].value[3] << blocks_info[i][j].value[4] << "\n";
- //cout << endl << endl << endl;
- }
-
-
- tables_info = separate_parts(output[2]); // Tables is the 3rd part of a dxf file.
- cout << "tables_info.size() = " << tables_info.size() << endl;
- for (int i=0;i < tables_info.size();i++){
- //for (int j=0;j < tables_info[i].size();j++) cout << tables_info[i][j].group_code << " " << tables_info[i][j].value[0] << tables_info[i][j].value[1] << tables_info[i][j].value[2] << tables_info[i][j].value[3] << tables_info[i][j].value[4] << "\n";
- //cout << "i = " << i << endl << endl;
- }
- tables tbls(tables_info); // Sort the information in the tables
-
-
-
- cout << "This should change \n";
-
- cout << "\n\nNow display all parsed info \n";
- entities ents(entities_info);
- ents.display_all();
-
- //char units[5] = "in";
- // char units[5] = "";
-
- cout << "\nNow for the begining of the SVG...\n\n";
-
- cout << "Polyline conversion\n";
- //std::vector< polyline > pl_tmp= ents.ret_plines();
- //cout << "pline2pline\n" << pline2pline(pl_tmp[0], units ) << endl;
- //cout << "pline2pline\n" << pline2pline(ents.ret_plines()[0], units ) << endl;
- //cout << "pline2path\n" << pline2path(ents.ret_plines()[0], units );
-
- // char tmp_char[10000];
-
- cout << "\nCircle conversion\n";
- //cout << "circle2circle\n" << circle2circle(ents.ret_circles()[0], 3, units, tmp_char) << endl;
-
- return 0;
-}
diff --git a/src/extension/effect.cpp b/src/extension/effect.cpp
index 1df8002ad..3c8ee5844 100644
--- a/src/extension/effect.cpp
+++ b/src/extension/effect.cpp
@@ -38,7 +38,7 @@ Inkscape::XML::Node * Effect::_filters_list = NULL;
Effect::Effect (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp)
: Extension(in_repr, in_imp),
_id_noprefs(Glib::ustring(get_id()) + ".noprefs"),
- _name_noprefs(Glib::ustring(get_name()) + _(" (No preferences)")),
+ _name_noprefs(Glib::ustring(_(get_name())) + _(" (No preferences)")),
_verb(get_id(), get_name(), NULL, NULL, this, true),
_verb_nopref(_id_noprefs.c_str(), _name_noprefs.c_str(), NULL, NULL, this, false),
_menu_node(NULL), _workingDialog(true),
@@ -89,7 +89,7 @@ Effect::Effect (Inkscape::XML::Node * in_repr, Implementation::Implementation *
} // children of "inkscape-extension"
} // if we have an XML file
- if (INKSCAPE != NULL) {
+ if (INKSCAPE != NULL && inkscape_use_gui()) {
if (_effects_list == NULL)
_effects_list = find_menu(inkscape_get_menus(INKSCAPE), EFFECTS_LIST);
if (_filters_list == NULL)
@@ -359,22 +359,22 @@ Effect::set_pref_dialog (PrefDialog * prefdialog)
}
SPAction *
-Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
+Effect::EffectVerb::make_action (Inkscape::ActionContext const & context)
{
- return make_action_helper(view, &perform, static_cast<void *>(this));
+ return make_action_helper(context, &perform, static_cast<void *>(this));
}
/** \brief Decode the verb code and take appropriate action */
void
Effect::EffectVerb::perform( SPAction *action, void * data )
{
+ g_return_if_fail(ensure_desktop_valid(action));
Inkscape::UI::View::View * current_view = sp_action_get_view(action);
-// SPDocument * current_document = current_view->doc;
+
Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
Effect * effect = ev->_effect;
if (effect == NULL) return;
- if (current_view == NULL) return;
if (ev->_showPrefs) {
effect->prefs(current_view);
diff --git a/src/extension/effect.h b/src/extension/effect.h
index bb36b9238..a14cc6e7d 100644
--- a/src/extension/effect.h
+++ b/src/extension/effect.h
@@ -20,7 +20,7 @@ namespace Gtk {
class VBox;
}
-struct SPDocument;
+class SPDocument;
namespace Inkscape {
@@ -58,7 +58,7 @@ class Effect : public Extension {
/** \brief Name with elipses if that makes sense */
gchar * _elip_name;
protected:
- virtual SPAction * make_action (Inkscape::UI::View::View * view);
+ virtual SPAction * make_action (Inkscape::ActionContext const & context);
public:
/** \brief Use the Verb initializer with the same parameters. */
EffectVerb(gchar const * id,
@@ -67,7 +67,7 @@ class Effect : public Extension {
gchar const * image,
Effect * effect,
bool showPrefs) :
- Verb(id, _(name), _(tip), image),
+ Verb(id, _(name), _(tip), image, _("Extensions")),
_effect(effect),
_showPrefs(showPrefs),
_elip_name(NULL) {
diff --git a/src/extension/error-file.cpp b/src/extension/error-file.cpp
index 2a56f55e8..f60af870f 100644
--- a/src/extension/error-file.cpp
+++ b/src/extension/error-file.cpp
@@ -12,12 +12,11 @@
#include "config.h"
#endif
-#include <glibmm/i18n.h>
-
+#include "ui/dialog/extensions.h"
+#include <glibmm/i18n.h>
#include "inkscape.h"
#include "preferences.h"
-#include "ui/dialog/extensions.h"
#include "extension/extension.h"
#include "error-file.h"
@@ -40,7 +39,7 @@ namespace Extension {
probably good to check anyway).
*/
ErrorFileNotice::ErrorFileNotice (void) :
- Gtk::MessageDialog::MessageDialog(
+ Gtk::MessageDialog(
"", /* message */
false, /* use markup */
Gtk::MESSAGE_WARNING, /* dialog type */
@@ -56,7 +55,11 @@ ErrorFileNotice::ErrorFileNotice (void) :
g_free(ext_error_file);
set_message(dialog_text, true);
+#if WITH_GTKMM_3_0
+ Gtk::Box * vbox = get_content_area();
+#else
Gtk::Box * vbox = get_vbox();
+#endif
/* This is some filler text, needs to change before relase */
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
diff --git a/src/extension/execution-env.cpp b/src/extension/execution-env.cpp
index 4058fd787..d4b5fd187 100644
--- a/src/extension/execution-env.cpp
+++ b/src/extension/execution-env.cpp
@@ -10,6 +10,14 @@
#include <config.h>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include "gtkmm/messagedialog.h"
#include "execution-env.h"
diff --git a/src/extension/execution-env.h b/src/extension/execution-env.h
index 92f496b90..795f5a65a 100644
--- a/src/extension/execution-env.h
+++ b/src/extension/execution-env.h
@@ -17,8 +17,6 @@
#include <gtkmm/dialog.h>
-#include "extension.h"
-
namespace Inkscape {
namespace UI {
diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp
index 4e2c5b9e4..d63ec7485 100644
--- a/src/extension/extension.cpp
+++ b/src/extension/extension.cpp
@@ -19,13 +19,21 @@
# include "config.h"
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
-#include <glibmm/i18n.h>
#include <gtkmm/box.h>
#include <gtkmm/label.h>
#include <gtkmm/frame.h>
-#include <gtkmm/table.h>
+#if WITH_GTKMM_3_0
+# include <gtkmm/grid.h>
+#else
+# include <gtkmm/table.h>
+#endif
+
+#include <glibmm/i18n.h>
#include "inkscape.h"
#include "extension/implementation/implementation.h"
#include "extension.h"
@@ -417,16 +425,31 @@ gchar const *Extension::get_param_string(gchar const *name, SPDocument const *do
}
const gchar *
-Extension::get_param_enum (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node)
+Extension::get_param_enum (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node) const
{
- Parameter* param = get_param(name);
+ Parameter const *param = get_param(name);
return param->get_enum(doc, node);
}
+/**
+ * This is useful to find out, if a given string \c value is selectable in a ComboBox named \cname.
+ *
+ * @param name The name of the enum parameter to get.
+ * @param doc The document to look in for document specific parameters.
+ * @param node The node to look in for a specific parameter.
+ * @return true if value exists, false if not
+ */
+bool
+Extension::get_param_enum_contains(gchar const * name, gchar const * value, SPDocument * doc, Inkscape::XML::Node * node) const
+{
+ Parameter const *param = get_param(name);
+ return param->get_enum_contains(value, doc, node);
+}
+
gchar const *
-Extension::get_param_optiongroup( gchar const * name, SPDocument const * doc, Inkscape::XML::Node const * node)
+Extension::get_param_optiongroup( gchar const * name, SPDocument const * doc, Inkscape::XML::Node const * node) const
{
- Parameter* param = get_param(name);
+ Parameter const*param = get_param(name);
return param->get_optiongroup(doc, node);
}
@@ -500,9 +523,9 @@ Extension::get_param_float (const gchar * name, const SPDocument * doc, const In
found parameter.
*/
guint32
-Extension::get_param_color (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node)
+Extension::get_param_color (const gchar * name, const SPDocument * doc, const Inkscape::XML::Node * node) const
{
- Parameter* param = get_param(name);
+ Parameter const *param = get_param(name);
return param->get_color(doc, node);
}
@@ -593,6 +616,13 @@ Extension::set_param_optiongroup(gchar const * name, gchar const * value, SPDocu
return param->set_optiongroup(value, doc, node);
}
+gchar const *
+Extension::set_param_enum(gchar const * name, gchar const * value, SPDocument * doc, Inkscape::XML::Node * node)
+{
+ Parameter * param = get_param(name);
+ return param->set_enum(value, doc, node);
+}
+
/**
\return The passed in value
@@ -720,7 +750,12 @@ Extension::get_info_widget(void)
Gtk::Frame * info = Gtk::manage(new Gtk::Frame("General Extension Information"));
retval->pack_start(*info, true, true, 5);
+#if WITH_GTKMM_3_0
+ Gtk::Grid * table = Gtk::manage(new Gtk::Grid());
+#else
Gtk::Table * table = Gtk::manage(new Gtk::Table());
+#endif
+
info->add(*table);
int row = 0;
@@ -733,8 +768,11 @@ Extension::get_info_widget(void)
return retval;
}
-void
-Extension::add_val(Glib::ustring labelstr, Glib::ustring valuestr, Gtk::Table * table, int * row)
+#if WITH_GTKMM_3_0
+void Extension::add_val(Glib::ustring labelstr, Glib::ustring valuestr, Gtk::Grid * table, int * row)
+#else
+void Extension::add_val(Glib::ustring labelstr, Glib::ustring valuestr, Gtk::Table * table, int * row)
+#endif
{
Gtk::Label * label;
Gtk::Label * value;
@@ -742,8 +780,14 @@ Extension::add_val(Glib::ustring labelstr, Glib::ustring valuestr, Gtk::Table *
(*row)++;
label = Gtk::manage(new Gtk::Label(labelstr));
value = Gtk::manage(new Gtk::Label(valuestr));
+
+#if WITH_GTKMM_3_0
+ table->attach(*label, 0, (*row) - 1, 1, 1);
+ table->attach(*value, 1, (*row) - 1, 1, 1);
+#else
table->attach(*label, 0, 1, (*row) - 1, *row);
table->attach(*value, 1, 2, (*row) - 1, *row);
+#endif
label->show();
value->show();
diff --git a/src/extension/extension.h b/src/extension/extension.h
index e0b643b6d..1fb8bdfec 100644
--- a/src/extension/extension.h
+++ b/src/extension/extension.h
@@ -19,9 +19,15 @@
#include <vector>
#include <glibmm/ustring.h>
#include "xml/repr.h"
+#include <sigc++/signal.h>
namespace Gtk {
+#if WITH_GTKMM_3_0
+ class Grid;
+#else
class Table;
+#endif
+
class VBox;
class Widget;
}
@@ -65,7 +71,7 @@ namespace Gtk {
#define INKSCAPE_EXTENSION_NS_NC "extension"
#define INKSCAPE_EXTENSION_NS "extension:"
-struct SPDocument;
+class SPDocument;
namespace Inkscape {
namespace Extension {
@@ -138,12 +144,12 @@ private:
extension */
public:
- /** \brief A function to get the the number of parameters that
+ /** \brief A function to get the number of parameters that
the extension has.
\return The number of parameters. */
unsigned int param_count ( ) { return parameters == NULL ? 0 :
g_slist_length(parameters); };
- /** \brief A function to get the the number of parameters that
+ /** \brief A function to get the number of parameters that
are visible to the user that the extension has.
\return The number of visible parameters.
@@ -228,15 +234,20 @@ public:
guint32 get_param_color (const gchar * name,
const SPDocument * doc = NULL,
- const Inkscape::XML::Node * node = NULL);
+ const Inkscape::XML::Node * node = NULL) const;
const gchar * get_param_enum (const gchar * name,
const SPDocument * doc = NULL,
- const Inkscape::XML::Node * node = NULL);
+ const Inkscape::XML::Node * node = NULL) const;
gchar const *get_param_optiongroup( gchar const * name,
SPDocument const * doc = 0,
- Inkscape::XML::Node const * node = 0);
+ Inkscape::XML::Node const * node = 0) const;
+
+ bool get_param_enum_contains(gchar const * name,
+ gchar const * value,
+ SPDocument * doc = 0x0,
+ Inkscape::XML::Node * node = 0x0) const;
bool set_param_bool (const gchar * name,
bool value,
@@ -263,6 +274,11 @@ public:
SPDocument * doc = 0,
Inkscape::XML::Node * node = 0);
+ gchar const * set_param_enum (gchar const * name,
+ gchar const * value,
+ SPDocument * doc = 0x0,
+ Inkscape::XML::Node * node = 0x0);
+
guint32 set_param_color (const gchar * name,
guint32 color,
SPDocument * doc = NULL,
@@ -284,8 +300,11 @@ public:
Gtk::VBox * get_help_widget(void);
Gtk::VBox * get_params_widget(void);
protected:
+#if WITH_GTKMM_3_0
+ inline static void add_val(Glib::ustring labelstr, Glib::ustring valuestr, Gtk::Grid * table, int * row);
+#else
inline static void add_val(Glib::ustring labelstr, Glib::ustring valuestr, Gtk::Table * table, int * row);
-
+#endif
};
diff --git a/src/extension/implementation/implementation.h b/src/extension/implementation/implementation.h
index b0230b7c4..9d679982a 100644
--- a/src/extension/implementation/implementation.h
+++ b/src/extension/implementation/implementation.h
@@ -29,7 +29,7 @@ namespace Gtk {
}
class SPDocument;
-class SPStyle;
+struct SPStyle;
namespace Inkscape {
@@ -104,6 +104,7 @@ public:
virtual bool check(Inkscape::Extension::Extension * /*module*/) { return true; }
virtual bool cancelProcessing () { return true; }
+ virtual bool wasCancelled () { return false; }
virtual void commitDocument () {}
// ----- Input functions -----
diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp
index 432b25bb9..f0fd3711b 100644
--- a/src/extension/implementation/script.cpp
+++ b/src/extension/implementation/script.cpp
@@ -19,10 +19,16 @@
# include <config.h>
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/messagedialog.h>
#include <gtkmm/main.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/textview.h>
+#include <glibmm/miscutils.h>
+#include <glibmm/convert.h>
#include <unistd.h>
#include <errno.h>
@@ -667,8 +673,13 @@ void Script::effect(Inkscape::Extension::Effect *module,
printf("TOO BAD TO LIVE!!!");
exit(1);
}
+ if (doc == NULL)
+ {
+ g_warning("Script::effect: View not defined");
+ return;
+ }
- SPDesktop *desktop = (SPDesktop *)doc;
+ SPDesktop *desktop = reinterpret_cast<SPDesktop *>(doc);
sp_namedview_document_from_window(desktop);
std::list<std::string> params;
@@ -694,16 +705,14 @@ void Script::effect(Inkscape::Extension::Effect *module,
return;
}
- if (desktop != NULL) {
- Inkscape::Util::GSListConstIterator<SPItem *> selected =
- sp_desktop_selection(desktop)->itemList();
- while ( selected != NULL ) {
- Glib::ustring selected_id;
- selected_id += "--id=";
- selected_id += (*selected)->getId();
- params.insert(params.begin(), selected_id);
- ++selected;
- }
+ Inkscape::Util::GSListConstIterator<SPItem *> selected =
+ sp_desktop_selection(desktop)->itemList(); //desktop should not be NULL since doc was checked and desktop is a casted pointer
+ while ( selected != NULL ) {
+ Glib::ustring selected_id;
+ selected_id += "--id=";
+ selected_id += (*selected)->getId();
+ params.insert(params.begin(), selected_id);
+ ++selected;
}
file_listener fileout;
@@ -726,31 +735,37 @@ void Script::effect(Inkscape::Extension::Effect *module,
g_unlink(tempfilename_out.c_str());
- /* Do something with mydoc.... */
if (mydoc) {
- doc->doc()->emitReconstructionStart();
- copy_doc(doc->doc()->rroot, mydoc->rroot);
- doc->doc()->emitReconstructionFinish();
- SPObject *layer = NULL;
- SPObject *obj = mydoc->getObjectById("base");
-
- // Getting the named view from the document generated by the extension
- SPNamedView *nv = (SPNamedView *) obj;
-
- //Check if it has a default layer set up
- if ( nv != NULL){
- if( nv->default_layer_id != 0 ) {
- SPDocument *document = desktop->doc();
- //If so, get that layer
- layer = document->getObjectById(g_quark_to_string(nv->default_layer_id));
+ SPDocument* vd=doc->doc();
+ if (vd != NULL)
+ {
+ vd->emitReconstructionStart();
+ copy_doc(vd->rroot, mydoc->rroot);
+ vd->emitReconstructionFinish();
+ SPObject *layer = NULL;
+
+ // Getting the named view from the document generated by the extension
+ SPNamedView *nv = sp_document_namedview(mydoc, NULL);
+
+ //Check if it has a default layer set up
+ if ( nv != NULL)
+ {
+ if( nv->default_layer_id != 0 ) {
+ SPDocument *document = desktop->doc();
+ //If so, get that layer
+ if (document != NULL)
+ {
+ layer = document->getObjectById(g_quark_to_string(nv->default_layer_id));
+ }
+ }
+ }
+
+ sp_namedview_update_layers_from_document(desktop);
+ //If that layer exists,
+ if (layer) {
+ //set the current layer
+ desktop->setCurrentLayer(layer);
}
- }
-
- sp_namedview_update_layers_from_document(desktop);
- //If that layer exists,
- if (layer) {
- //set the current layer
- desktop->setCurrentLayer(layer);
}
mydoc->release();
}
@@ -777,6 +792,11 @@ void Script::effect(Inkscape::Extension::Effect *module,
*/
void Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot)
{
+ if ((oldroot == NULL) ||(newroot == NULL))
+ {
+ g_warning("Error on copy_doc: NULL pointer input.");
+ return;
+ }
std::vector<Inkscape::XML::Node *> delete_list;
Inkscape::XML::Node * oldroot_namedview = NULL;
@@ -853,7 +873,11 @@ void Script::checkStderr (const Glib::ustring &data,
GtkWidget *dlg = GTK_WIDGET(warning.gobj());
sp_transientize(dlg);
+#if WITH_GTKMM_3_0
+ Gtk::Box * vbox = warning.get_content_area();
+#else
Gtk::Box * vbox = warning.get_vbox();
+#endif
/* Gtk::TextView * textview = new Gtk::TextView(Gtk::TextBuffer::create()); */
Gtk::TextView * textview = new Gtk::TextView();
@@ -861,13 +885,7 @@ void Script::checkStderr (const Glib::ustring &data,
textview->set_wrap_mode(Gtk::WRAP_WORD);
textview->show();
- // Remove the last character
- char *errormsg = (char*) data.c_str();
- while (*errormsg != '\0') errormsg++;
- errormsg -= 1;
- *errormsg = '\0';
-
- textview->get_buffer()->set_text(_(data.c_str()));
+ textview->get_buffer()->set_text(data.c_str());
Gtk::ScrolledWindow * scrollwindow = new Gtk::ScrolledWindow();
scrollwindow->add(*textview);
@@ -963,7 +981,14 @@ int Script::execute (const std::list<std::string> &in_command,
// assemble the rest of argv
std::copy(in_params.begin(), in_params.end(), std::back_inserter(argv));
if (!filein.empty()) {
- argv.push_back(filein);
+ if(Glib::path_is_absolute(filein))
+ argv.push_back(filein);
+ else {
+ std::vector<std::string> buildargs;
+ buildargs.push_back(Glib::get_current_dir());
+ buildargs.push_back(filein);
+ argv.push_back(Glib::build_filename(buildargs));
+ }
}
int stdout_pipe, stderr_pipe;
diff --git a/src/extension/implementation/script.h b/src/extension/implementation/script.h
index f52683623..270c361af 100644
--- a/src/extension/implementation/script.h
+++ b/src/extension/implementation/script.h
@@ -15,6 +15,9 @@
#include "implementation.h"
#include <gtkmm/enums.h>
+#include <glibmm/main.h>
+#include <glibmm/spawn.h>
+#include <glibmm/fileutils.h>
namespace Inkscape {
namespace XML {
diff --git a/src/extension/implementation/xslt.cpp b/src/extension/implementation/xslt.cpp
index 9dd9c83ee..bcea06cb5 100644
--- a/src/extension/implementation/xslt.cpp
+++ b/src/extension/implementation/xslt.cpp
@@ -177,7 +177,7 @@ XSLT::open(Inkscape::Extension::Input */*module*/, gchar const *filename)
}
g_free(s);
- SPDocument * doc = SPDocument::createDoc(rdoc, filename, base, name, true);
+ SPDocument * doc = SPDocument::createDoc(rdoc, filename, base, name, true, NULL);
g_free(base); g_free(name);
diff --git a/src/extension/init.cpp b/src/extension/init.cpp
index b0732568f..0ff4b79c4 100644
--- a/src/extension/init.cpp
+++ b/src/extension/init.cpp
@@ -26,16 +26,18 @@
#include "path-prefix.h"
#include "inkscape.h"
-#include <glibmm/ustring.h>
+
+#include <glibmm/fileutils.h>
#include <glibmm/i18n.h>
+#include <glibmm/ustring.h>
#include "system.h"
#include "db.h"
#include "internal/svgz.h"
-#ifdef WIN32
-# include "internal/emf-win32-inout.h"
-# include "internal/emf-win32-print.h"
-#endif
+# include "internal/emf-inout.h"
+# include "internal/emf-print.h"
+# include "internal/wmf-inout.h"
+# include "internal/wmf-print.h"
#ifdef HAVE_CAIRO_PDF
# include "internal/cairo-renderer-pdf-out.h"
# include "internal/cairo-png-out.h"
@@ -53,6 +55,12 @@
#ifdef WITH_LIBWPG
#include "internal/wpg-input.h"
#endif
+#ifdef WITH_LIBVISIO
+#include "internal/vsd-input.h"
+#endif
+#ifdef WITH_LIBCDR
+#include "internal/cdr-input.h"
+#endif
#include "preferences.h"
#include "io/sys.h"
#ifdef WITH_DBUS
@@ -99,7 +107,7 @@
#include "internal/filter/filter.h"
-extern gboolean inkscape_app_use_gui( Inkscape::Application const *app );
+#include "init.h"
namespace Inkscape {
namespace Extension {
@@ -171,10 +179,10 @@ init()
Internal::PdfInputCairo::init();
}
#endif
-#ifdef WIN32
- Internal::PrintEmfWin32::init();
- Internal::EmfWin32::init();
-#endif
+ Internal::PrintEmf::init();
+ Internal::Emf::init();
+ Internal::PrintWmf::init();
+ Internal::Wmf::init();
Internal::PovOutput::init();
Internal::JavaFXOutput::init();
Internal::OdfOutput::init();
@@ -183,6 +191,12 @@ init()
#ifdef WITH_LIBWPG
Internal::WpgInput::init();
#endif
+#ifdef WITH_LIBVISIO
+ Internal::VsdInput::init();
+#endif
+#ifdef WITH_LIBCDR
+ Internal::CdrInput::init();
+#endif
/* Effects */
Internal::BlurEdge::init();
@@ -279,7 +293,7 @@ static void
build_module_from_dir(gchar const *dirname)
{
if (!dirname) {
- g_warning(_("Null external module directory name. Modules will not be loaded."));
+ g_warning("%s", _("Null external module directory name. Modules will not be loaded."));
return;
}
@@ -308,7 +322,7 @@ build_module_from_dir(gchar const *dirname)
continue;
}
- gchar *pathname = g_build_filename(dirname, filename, NULL);
+ gchar *pathname = g_build_filename(dirname, filename, (char *) NULL);
build_from_file(pathname);
g_free(pathname);
}
diff --git a/src/extension/input.cpp b/src/extension/input.cpp
index 1662ef073..5cef38009 100644
--- a/src/extension/input.cpp
+++ b/src/extension/input.cpp
@@ -152,6 +152,10 @@ Input::open (const gchar *uri)
SPDocument *const doc = imp->open(this, uri);
+ if (imp->wasCancelled()) {
+ throw Input::open_cancelled();
+ }
+
return doc;
}
@@ -227,8 +231,7 @@ Input::prefs (const gchar *uri)
delete dialog;
- if (response == Gtk::RESPONSE_OK) return true;
- return false;
+ return (response == Gtk::RESPONSE_OK);
}
} } /* namespace Inkscape, Extension */
diff --git a/src/extension/input.h b/src/extension/input.h
index 8b198495e..b01ffeb86 100644
--- a/src/extension/input.h
+++ b/src/extension/input.h
@@ -39,6 +39,10 @@ public:
virtual ~no_extension_found() throw() {}
const char *what() const throw() { return "No suitable input extension found"; }
};
+ struct open_cancelled : public std::exception {
+ virtual ~open_cancelled() throw() {}
+ const char *what() const throw() { return "Open was cancelled"; }
+ };
Input (Inkscape::XML::Node * in_repr,
Implementation::Implementation * in_imp);
diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert
index 06fa275cb..a31843114 100644
--- a/src/extension/internal/Makefile_insert
+++ b/src/extension/internal/Makefile_insert
@@ -4,7 +4,18 @@ if WITH_LIBWPG
ink_common_sources += \
extension/internal/wpg-input.cpp \
extension/internal/wpg-input.h
+endif
+
+if WITH_LIBVISIO
+ink_common_sources += \
+ extension/internal/vsd-input.cpp \
+ extension/internal/vsd-input.h
+endif
+if WITH_LIBCDR
+ink_common_sources += \
+ extension/internal/cdr-input.cpp \
+ extension/internal/cdr-input.h
endif
if USE_IMAGE_MAGICK
@@ -127,13 +138,38 @@ ink_common_sources += \
extension/internal/latex-pstricks.h \
extension/internal/latex-pstricks-out.cpp \
extension/internal/latex-pstricks-out.h \
+ extension/internal/filter/bevels.h \
+ extension/internal/filter/blurs.h \
+ extension/internal/filter/bumps.h \
+ extension/internal/filter/color.h \
+ extension/internal/filter/distort.h \
+ extension/internal/filter/filter.h \
+ extension/internal/filter/image.h \
+ extension/internal/filter/morphology.h \
+ extension/internal/filter/overlays.h \
+ extension/internal/filter/paint.h \
+ extension/internal/filter/protrusions.h \
+ extension/internal/filter/shadows.h \
+ extension/internal/filter/textures.h \
+ extension/internal/filter/transparency.h \
extension/internal/filter/filter-all.cpp \
extension/internal/filter/filter-file.cpp \
extension/internal/filter/filter.cpp \
extension/internal/filter/filter.h \
- extension/internal/filter/drop-shadow.h \
- extension/internal/filter/snow.h \
- extension/internal/emf-win32-print.h \
- extension/internal/emf-win32-print.cpp \
- extension/internal/emf-win32-inout.h \
- extension/internal/emf-win32-inout.cpp
+ extension/internal/text_reassemble.c \
+ extension/internal/text_reassemble.h \
+ extension/internal/emf-print.h \
+ extension/internal/emf-print.cpp \
+ extension/internal/emf-inout.h \
+ extension/internal/emf-inout.cpp \
+ extension/internal/metafile-inout.h \
+ extension/internal/metafile-inout.cpp \
+ extension/internal/metafile-print.h \
+ extension/internal/metafile-print.cpp \
+ extension/internal/wmf-print.h \
+ extension/internal/wmf-print.cpp \
+ extension/internal/wmf-inout.h \
+ extension/internal/wmf-inout.cpp \
+ extension/internal/image-resolution.h \
+ extension/internal/image-resolution.cpp
+
diff --git a/src/extension/internal/bitmap/despeckle.cpp b/src/extension/internal/bitmap/despeckle.cpp
index f818ef81a..c40e6e227 100644
--- a/src/extension/internal/bitmap/despeckle.cpp
+++ b/src/extension/internal/bitmap/despeckle.cpp
@@ -23,7 +23,7 @@ Despeckle::applyEffect(Magick::Image *image) {
}
void
-Despeckle::refreshParameters(Inkscape::Extension::Effect *module) {
+Despeckle::refreshParameters(Inkscape::Extension::Effect */*module*/) {
}
#include "../clear-n_.h"
diff --git a/src/extension/internal/bitmap/enhance.cpp b/src/extension/internal/bitmap/enhance.cpp
index 0bd362e8c..5b06a2d27 100644
--- a/src/extension/internal/bitmap/enhance.cpp
+++ b/src/extension/internal/bitmap/enhance.cpp
@@ -23,7 +23,7 @@ Enhance::applyEffect(Magick::Image *image) {
}
void
-Enhance::refreshParameters(Inkscape::Extension::Effect *module) { }
+Enhance::refreshParameters(Inkscape::Extension::Effect */*module*/) { }
#include "../clear-n_.h"
diff --git a/src/extension/internal/bitmap/equalize.cpp b/src/extension/internal/bitmap/equalize.cpp
index b0726b61a..6098f74b1 100644
--- a/src/extension/internal/bitmap/equalize.cpp
+++ b/src/extension/internal/bitmap/equalize.cpp
@@ -23,7 +23,7 @@ Equalize::applyEffect(Magick::Image *image) {
}
void
-Equalize::refreshParameters(Inkscape::Extension::Effect *module) { }
+Equalize::refreshParameters(Inkscape::Extension::Effect */*module*/) { }
#include "../clear-n_.h"
diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp
index 728c38dea..0d47240d4 100644
--- a/src/extension/internal/bitmap/imagemagick.cpp
+++ b/src/extension/internal/bitmap/imagemagick.cpp
@@ -8,6 +8,14 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <libintl.h>
#include <gtkmm/box.h>
diff --git a/src/extension/internal/bitmap/negate.cpp b/src/extension/internal/bitmap/negate.cpp
index 2e564821e..4737e6443 100644
--- a/src/extension/internal/bitmap/negate.cpp
+++ b/src/extension/internal/bitmap/negate.cpp
@@ -23,7 +23,7 @@ Negate::applyEffect(Magick::Image* image) {
}
void
-Negate::refreshParameters(Inkscape::Extension::Effect* module) {
+Negate::refreshParameters(Inkscape::Extension::Effect* /*module*/) {
}
#include "../clear-n_.h"
diff --git a/src/extension/internal/bitmap/normalize.cpp b/src/extension/internal/bitmap/normalize.cpp
index 591fe1fdd..1444aa654 100644
--- a/src/extension/internal/bitmap/normalize.cpp
+++ b/src/extension/internal/bitmap/normalize.cpp
@@ -23,7 +23,7 @@ Normalize::applyEffect(Magick::Image* image) {
}
void
-Normalize::refreshParameters(Inkscape::Extension::Effect* module) {
+Normalize::refreshParameters(Inkscape::Extension::Effect* /*module*/) {
}
#include "../clear-n_.h"
diff --git a/src/extension/internal/bluredge.cpp b/src/extension/internal/bluredge.cpp
index 8f1e07211..3ce537d9f 100644
--- a/src/extension/internal/bluredge.cpp
+++ b/src/extension/internal/bluredge.cpp
@@ -17,6 +17,7 @@
#include "document.h"
#include "selection.h"
#include "helper/action.h"
+#include "helper/action-context.h"
#include "preferences.h"
#include "path-chemistry.h"
#include "sp-item.h"
@@ -93,16 +94,16 @@ BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View
new_group->appendChild(new_items[i]);
selection->add(new_items[i]);
- sp_selected_path_to_curves(static_cast<SPDesktop *>(desktop));
+ sp_selected_path_to_curves(selection, static_cast<SPDesktop *>(desktop));
if (offset < 0.0) {
/* Doing an inset here folks */
offset *= -1.0;
prefs->setDoubleUnit("/options/defaultoffsetwidth/value", offset, "px");
- sp_action_perform(Inkscape::Verb::get(SP_VERB_SELECTION_INSET)->get_action(desktop), NULL);
+ sp_action_perform(Inkscape::Verb::get(SP_VERB_SELECTION_INSET)->get_action(Inkscape::ActionContext(desktop)), NULL);
} else if (offset > 0.0) {
prefs->setDoubleUnit("/options/defaultoffsetwidth/value", offset, "px");
- sp_action_perform(Inkscape::Verb::get(SP_VERB_SELECTION_OFFSET)->get_action(desktop), NULL);
+ sp_action_perform(Inkscape::Verb::get(SP_VERB_SELECTION_OFFSET)->get_action(Inkscape::ActionContext(desktop)), NULL);
}
selection->clear();
diff --git a/src/extension/internal/cairo-png-out.cpp b/src/extension/internal/cairo-png-out.cpp
index 4751a229a..956fcce9a 100644
--- a/src/extension/internal/cairo-png-out.cpp
+++ b/src/extension/internal/cairo-png-out.cpp
@@ -68,7 +68,7 @@ png_render_document_to_file(SPDocument *doc, gchar const *filename)
ctx = renderer->createContext();
/* Render document */
- bool ret = renderer->setupDocument(ctx, doc, TRUE, NULL);
+ bool ret = renderer->setupDocument(ctx, doc, TRUE, 0., NULL);
if (ret) {
renderer->renderItem(ctx, base);
ctx->saveAsPng(filename);
diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp
index 8b1b3fbfd..055a30add 100644
--- a/src/extension/internal/cairo-ps-out.cpp
+++ b/src/extension/internal/cairo-ps-out.cpp
@@ -66,7 +66,7 @@ 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 omittext,
- bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas, bool eps = false)
+ bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px, bool eps = false)
{
doc->ensureUpToDate();
@@ -97,14 +97,14 @@ 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->setOmitText(omittext);
ctx->setFilterToBitmap(filtertobitmap);
ctx->setBitmapResolution(resolution);
bool ret = ctx->setPsTarget(filename);
if(ret) {
/* Render document */
- ret = renderer->setupDocument(ctx, doc, pageBoundingBox, base);
+ ret = renderer->setupDocument(ctx, doc, pageBoundingBox, bleedmargin_px, base);
if (ret) {
renderer->renderItem(ctx, base);
ret = ctx->finish();
@@ -136,12 +136,12 @@ CairoPsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar con
if (ext == NULL)
return;
- const gchar *new_level = NULL;
int level = CAIRO_PS_LEVEL_2;
try {
- new_level = mod->get_param_enum("PSlevel");
- if((new_level != NULL) && (g_ascii_strcasecmp("PS3", new_level) == 0))
+ const gchar *new_level = mod->get_param_enum("PSlevel");
+ if((new_level != NULL) && (g_ascii_strcasecmp("PS3", new_level) == 0)) {
level = CAIRO_PS_LEVEL_3;
+ }
} catch(...) {}
bool new_textToPath = FALSE;
@@ -169,12 +169,14 @@ CairoPsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar con
bool new_areaPage = true;
try {
- new_areaPage = mod->get_param_bool("areaPage");
+ new_areaPage = (strcmp(ext->get_param_optiongroup("area"), "page") == 0);
} catch(...) {}
- bool new_areaDrawing = true;
+ bool new_areaDrawing = !new_areaPage;
+
+ float bleedmargin_px = 0.;
try {
- new_areaDrawing = mod->get_param_bool("areaDrawing");
+ bleedmargin_px = ext->get_param_float("bleed");
} catch(...) {}
const gchar *new_exportId = NULL;
@@ -186,7 +188,11 @@ CairoPsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar con
{
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);
+ ret = ps_print_document_to_file(doc, final_name, level, new_textToPath,
+ new_textToLaTeX, new_blurToBitmap,
+ new_bitmapResolution, new_exportId,
+ new_areaDrawing, new_areaPage,
+ bleedmargin_px);
g_free(final_name);
if (!ret)
@@ -195,7 +201,7 @@ CairoPsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar con
// Create LaTeX file (if requested)
if (new_textToLaTeX) {
- ret = latex_render_document_text_to_file(doc, filename, new_exportId, new_areaDrawing, new_areaPage, false);
+ ret = latex_render_document_text_to_file(doc, filename, new_exportId, new_areaDrawing, new_areaPage, 0., false);
if (!ret)
throw Inkscape::Extension::Output::save_failed();
@@ -219,12 +225,12 @@ CairoEpsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar co
if (ext == NULL)
return;
- const gchar *new_level = NULL;
int level = CAIRO_PS_LEVEL_2;
try {
- new_level = mod->get_param_enum("PSlevel");
- if((new_level != NULL) && (g_ascii_strcasecmp("PS3", new_level) == 0))
+ const gchar *new_level = mod->get_param_enum("PSlevel");
+ if((new_level != NULL) && (g_ascii_strcasecmp("PS3", new_level) == 0)) {
level = CAIRO_PS_LEVEL_3;
+ }
} catch(...) {}
bool new_textToPath = FALSE;
@@ -252,12 +258,14 @@ CairoEpsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar co
bool new_areaPage = true;
try {
- new_areaPage = mod->get_param_bool("areaPage");
+ new_areaPage = (strcmp(ext->get_param_optiongroup("area"), "page") == 0);
} catch(...) {}
- bool new_areaDrawing = true;
+ bool new_areaDrawing = !new_areaPage;
+
+ float bleedmargin_px = 0.;
try {
- new_areaDrawing = mod->get_param_bool("areaDrawing");
+ bleedmargin_px = ext->get_param_float("bleed");
} catch(...) {}
const gchar *new_exportId = NULL;
@@ -269,7 +277,11 @@ CairoEpsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar co
{
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);
+ ret = ps_print_document_to_file(doc, final_name, level, new_textToPath,
+ new_textToLaTeX, new_blurToBitmap,
+ new_bitmapResolution, new_exportId,
+ new_areaDrawing, new_areaPage,
+ bleedmargin_px, true);
g_free(final_name);
if (!ret)
@@ -278,7 +290,7 @@ CairoEpsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar co
// Create LaTeX file (if requested)
if (new_textToLaTeX) {
- ret = latex_render_document_text_to_file(doc, filename, new_exportId, new_areaDrawing, new_areaPage, false);
+ ret = latex_render_document_text_to_file(doc, filename, new_exportId, new_areaDrawing, new_areaPage, 0., false);
if (!ret)
throw Inkscape::Extension::Output::save_failed();
@@ -310,32 +322,33 @@ CairoEpsOutput::textToPath(Inkscape::Extension::Print * ext)
void
CairoPsOutput::init (void)
{
- Inkscape::Extension::build_from_mem(
- "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
- "<name>" N_("PostScript") "</name>\n"
- "<id>" SP_MODULE_KEY_PRINT_CAIRO_PS "</id>\n"
- "<param name=\"PSlevel\" gui-text=\"" N_("Restrict to PS level:") "\" type=\"enum\" >\n"
- "<_item value='PS3'>" N_("PostScript level 3") "</_item>\n"
-#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2))
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("PostScript") "</name>\n"
+ "<id>" SP_MODULE_KEY_PRINT_CAIRO_PS "</id>\n"
+ "<param name=\"PSlevel\" gui-text=\"" N_("Restrict to PS level:") "\" type=\"enum\" >\n"
+ "<_item value='PS3'>" N_("PostScript level 3") "</_item>\n"
"<_item value='PS2'>" N_("PostScript level 2") "</_item>\n"
-#endif
"</param>\n"
- "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
- "<param name=\"textToLaTeX\" gui-text=\"" N_("PS+LaTeX: Omit text in PS, and create LaTeX file") "\" type=\"boolean\">false</param>\n"
- "<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
- "<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi):") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
- "<param name=\"areaDrawing\" gui-text=\"" N_("Export area is drawing") "\" type=\"boolean\">true</param>\n"
- "<param name=\"areaPage\" gui-text=\"" N_("Export area is page") "\" type=\"boolean\">true</param>\n"
- "<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID:") "\" type=\"string\"></param>\n"
- "<output>\n"
- "<extension>.ps</extension>\n"
- "<mimetype>image/x-postscript</mimetype>\n"
- "<filetypename>" N_("PostScript (*.ps)") "</filetypename>\n"
- "<filetypetooltip>" N_("PostScript File") "</filetypetooltip>\n"
- "</output>\n"
- "</inkscape-extension>", new CairoPsOutput());
-
- return;
+ "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"textToLaTeX\" gui-text=\"" N_("PS+LaTeX: Omit text in PS, and create LaTeX file") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi):") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
+ "<param name=\"area\" gui-text=\"" N_("Output page size") "\" type=\"optiongroup\" >\n"
+ "<_option value=\"page\">" N_("Use document's page size") "</_option>"
+ "<_option value=\"drawing\">" N_("Use exported object's size") "</_option>"
+ "</param>"
+ "<param name=\"bleed\" gui-text=\"" N_("Bleed/margin (mm):") "\" type=\"float\" min=\"-10000\" max=\"10000\">0</param>\n"
+ "<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID:") "\" type=\"string\"></param>\n"
+ "<output>\n"
+ "<extension>.ps</extension>\n"
+ "<mimetype>image/x-postscript</mimetype>\n"
+ "<filetypename>" N_("PostScript (*.ps)") "</filetypename>\n"
+ "<filetypetooltip>" N_("PostScript File") "</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>", new CairoPsOutput());
+
+ return;
}
/**
@@ -348,32 +361,33 @@ CairoPsOutput::init (void)
void
CairoEpsOutput::init (void)
{
- Inkscape::Extension::build_from_mem(
- "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
- "<name>" N_("Encapsulated PostScript") "</name>\n"
- "<id>" SP_MODULE_KEY_PRINT_CAIRO_EPS "</id>\n"
- "<param name=\"PSlevel\" gui-text=\"" N_("Restrict to PS level:") "\" type=\"enum\" >\n"
- "<_item value='PS3'>" N_("PostScript level 3") "</_item>\n"
-#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2))
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("Encapsulated PostScript") "</name>\n"
+ "<id>" SP_MODULE_KEY_PRINT_CAIRO_EPS "</id>\n"
+ "<param name=\"PSlevel\" gui-text=\"" N_("Restrict to PS level:") "\" type=\"enum\" >\n"
+ "<_item value='PS3'>" N_("PostScript level 3") "</_item>\n"
"<_item value='PS2'>" N_("PostScript level 2") "</_item>\n"
-#endif
"</param>\n"
- "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
- "<param name=\"textToLaTeX\" gui-text=\"" N_("EPS+LaTeX: Omit text in EPS, and create LaTeX file") "\" type=\"boolean\">false</param>\n"
- "<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
- "<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi):") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
- "<param name=\"areaDrawing\" gui-text=\"" N_("Export area is drawing") "\" type=\"boolean\">true</param>\n"
- "<param name=\"areaPage\" gui-text=\"" N_("Export area is page") "\" type=\"boolean\">true</param>\n"
- "<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID:") "\" type=\"string\"></param>\n"
- "<output>\n"
- "<extension>.eps</extension>\n"
- "<mimetype>image/x-e-postscript</mimetype>\n"
- "<filetypename>" N_("Encapsulated PostScript (*.eps)") "</filetypename>\n"
- "<filetypetooltip>" N_("Encapsulated PostScript File") "</filetypetooltip>\n"
- "</output>\n"
- "</inkscape-extension>", new CairoEpsOutput());
-
- return;
+ "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"textToLaTeX\" gui-text=\"" N_("EPS+LaTeX: Omit text in EPS, and create LaTeX file") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi):") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
+ "<param name=\"area\" gui-text=\"" N_("Output page size") "\" type=\"optiongroup\" >\n"
+ "<_option value=\"page\">" N_("Use document's page size") "</_option>"
+ "<_option value=\"drawing\">" N_("Use exported object's size") "</_option>"
+ "</param>"
+ "<param name=\"bleed\" gui-text=\"" N_("Bleed/margin (mm)") "\" type=\"float\" min=\"-10000\" max=\"10000\">0</param>\n"
+ "<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID:") "\" type=\"string\"></param>\n"
+ "<output>\n"
+ "<extension>.eps</extension>\n"
+ "<mimetype>image/x-e-postscript</mimetype>\n"
+ "<filetypename>" N_("Encapsulated PostScript (*.eps)") "</filetypename>\n"
+ "<filetypetooltip>" N_("Encapsulated PostScript File") "</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>", new CairoEpsOutput());
+
+ return;
}
} } } /* namespace Inkscape, Extension, Implementation */
diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp
index b6a58c526..c09b8e9c8 100644
--- a/src/extension/internal/cairo-render-context.cpp
+++ b/src/extension/internal/cairo-render-context.cpp
@@ -44,12 +44,11 @@
#include "sp-pattern.h"
#include "sp-mask.h"
#include "sp-clippath.h"
+#include "util/units.h"
#ifdef WIN32
#include "libnrtype/FontFactory.h" // USE_PANGO_WIN32
#endif
-#include <unit-constants.h>
-
#include "cairo-render-context.h"
#include "cairo-renderer.h"
#include "extension/system.h"
@@ -73,8 +72,8 @@
#include <cairo-ft.h>
#endif
#ifdef CAIRO_HAS_WIN32_FONT
-#include <cairo-win32.h>
#include <pango/pangowin32.h>
+#include <cairo-win32.h>
#endif
#include <pango/pangofc-fontmap.h>
@@ -112,6 +111,7 @@ CairoRenderContext::CairoRenderContext(CairoRenderer *parent) :
_ps_level(1),
_eps(false),
_is_texttopath(FALSE),
+ _is_omittext(FALSE),
_is_filtertobitmap(FALSE),
_bitmapresolution(72),
_stream(NULL),
@@ -125,7 +125,8 @@ CairoRenderContext::CairoRenderContext(CairoRenderer *parent) :
_state(NULL),
_renderer(parent),
_render_mode(RENDER_MODE_NORMAL),
- _clip_mode(CLIP_MODE_MASK)
+ _clip_mode(CLIP_MODE_MASK),
+ _omittext_state(EMPTY)
{
font_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, font_data_free);
}
@@ -427,6 +428,16 @@ void CairoRenderContext::setTextToPath(bool texttopath)
_is_texttopath = texttopath;
}
+void CairoRenderContext::setOmitText(bool omittext)
+{
+ _is_omittext = omittext;
+}
+
+bool CairoRenderContext::getOmitText(void)
+{
+ return _is_omittext;
+}
+
void CairoRenderContext::setFilterToBitmap(bool filtertobitmap)
{
_is_filtertobitmap = filtertobitmap;
@@ -708,7 +719,7 @@ CairoRenderContext::popLayer(void)
for (int row = 0 ; row < height; row++) {
unsigned char *row_data = pixels + (row * stride);
for (int i = 0 ; i < width; i++) {
- guint32 *pixel = (guint32 *)row_data + i;
+ guint32 *pixel = reinterpret_cast<guint32 *>(row_data) + i;
float lum_alpha = (((*pixel & 0x00ff0000) >> 16) * coeff_r +
((*pixel & 0x0000ff00) >> 8) * coeff_g +
((*pixel & 0x000000ff) ) * coeff_b );
@@ -792,9 +803,7 @@ CairoRenderContext::setupSurface(double width, double height)
#ifdef CAIRO_HAS_PDF_SURFACE
case CAIRO_SURFACE_TYPE_PDF:
surface = cairo_pdf_surface_create_for_stream(Inkscape::Extension::Internal::_write_callback, _stream, width, height);
-#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0))
cairo_pdf_surface_restrict_to_version(surface, (cairo_pdf_version_t)_pdf_level);
-#endif
break;
#endif
#ifdef CAIRO_HAS_PS_SURFACE
@@ -803,10 +812,8 @@ CairoRenderContext::setupSurface(double width, double height)
if(CAIRO_STATUS_SUCCESS != cairo_surface_status(surface)) {
return FALSE;
}
-#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2))
cairo_ps_surface_restrict_to_level(surface, (cairo_ps_level_t)_ps_level);
cairo_ps_surface_set_eps(surface, (cairo_bool_t) _eps);
-#endif
// Cairo calculates the bounding box itself, however we want to override this. See Launchpad bug #380501
#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2))
// cairo_ps_dsc_comment(surface, os_bbox.str().c_str());
@@ -855,7 +862,7 @@ CairoRenderContext::_finishSurfaceSetup(cairo_surface_t *surface, cairo_matrix_t
_surface = surface;
if (_vector_based_target) {
- cairo_scale(_cr, PT_PER_PX, PT_PER_PX);
+ cairo_scale(_cr, Inkscape::Util::Quantity::convert(1, "px", "pt"), Inkscape::Util::Quantity::convert(1, "px", "pt"));
} else if (cairo_surface_get_content(_surface) != CAIRO_CONTENT_ALPHA) {
// set background color on non-alpha surfaces
// TODO: bgcolor should be derived from SPDocument
@@ -1080,11 +1087,11 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver
// show items and render them
for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
- if (pat_i && SP_IS_OBJECT (pat_i) && pattern_hasItemChildren(pat_i)) { // find the first one with item children
+ if (pat_i && SP_IS_OBJECT(pat_i) && pattern_hasItemChildren(pat_i)) { // find the first one with item children
for ( SPObject *child = pat_i->firstChild() ; child; child = child->getNext() ) {
- if (SP_IS_ITEM (child)) {
- SP_ITEM (child)->invoke_show (drawing, dkey, SP_ITEM_REFERENCE_FLAGS);
- _renderer->renderItem(pattern_ctx, SP_ITEM (child));
+ if (SP_IS_ITEM(child)) {
+ SP_ITEM(child)->invoke_show(drawing, dkey, SP_ITEM_REFERENCE_FLAGS);
+ _renderer->renderItem(pattern_ctx, SP_ITEM(child));
}
}
break; // do not go further up the chain if children are found
@@ -1109,10 +1116,10 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver
// hide all items
for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
- if (pat_i && SP_IS_OBJECT (pat_i) && pattern_hasItemChildren(pat_i)) { // find the first one with item children
+ if (pat_i && SP_IS_OBJECT(pat_i) && pattern_hasItemChildren(pat_i)) { // find the first one with item children
for ( SPObject *child = pat_i->firstChild() ; child; child = child->getNext() ) {
- if (SP_IS_ITEM (child)) {
- SP_ITEM (child)->invoke_hide (dkey);
+ if (SP_IS_ITEM(child)) {
+ SP_ITEM(child)->invoke_hide(dkey);
}
}
break; // do not go further up the chain if children are found
@@ -1181,7 +1188,7 @@ CairoRenderContext::_createPatternForPaintServer(SPPaintServer const *const pain
return NULL;
}
- if (pattern && SP_IS_GRADIENT (paintserver)) {
+ if (pattern && SP_IS_GRADIENT(paintserver)) {
SPGradient *g = SP_GRADIENT(paintserver);
// set extend type
@@ -1290,12 +1297,16 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, Geom::OptRect const &p
}
}
- if (style->stroke_dash.n_dash &&
- style->stroke_dash.dash )
+ if (!style->stroke_dasharray.values.empty())
{
- cairo_set_dash(_cr, style->stroke_dash.dash, style->stroke_dash.n_dash, style->stroke_dash.offset);
+ size_t ndashes = style->stroke_dasharray.values.size();
+ double* dashes =(double*)malloc(ndashes*sizeof(double));
+ for( unsigned i = 0; i < ndashes; ++i ) {
+ dashes[i] = style->stroke_dasharray.values[i];
+ }
+ cairo_set_dash(_cr, dashes, ndashes, style->stroke_dashoffset.value);
} else {
- cairo_set_dash(_cr, NULL, 0, 0.0); // disable dashing
+ cairo_set_dash(_cr, NULL, 0, 0.0); // disable dashing
}
cairo_set_line_width(_cr, style->stroke_width.computed);
@@ -1303,40 +1314,65 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, Geom::OptRect const &p
// set line join type
cairo_line_join_t join = CAIRO_LINE_JOIN_MITER;
switch (style->stroke_linejoin.computed) {
- case SP_STROKE_LINEJOIN_MITER:
- join = CAIRO_LINE_JOIN_MITER;
- break;
- case SP_STROKE_LINEJOIN_ROUND:
- join = CAIRO_LINE_JOIN_ROUND;
- break;
- case SP_STROKE_LINEJOIN_BEVEL:
- join = CAIRO_LINE_JOIN_BEVEL;
- break;
+ case SP_STROKE_LINEJOIN_MITER:
+ join = CAIRO_LINE_JOIN_MITER;
+ break;
+ case SP_STROKE_LINEJOIN_ROUND:
+ join = CAIRO_LINE_JOIN_ROUND;
+ break;
+ case SP_STROKE_LINEJOIN_BEVEL:
+ join = CAIRO_LINE_JOIN_BEVEL;
+ break;
}
cairo_set_line_join(_cr, join);
// set line cap type
cairo_line_cap_t cap = CAIRO_LINE_CAP_BUTT;
switch (style->stroke_linecap.computed) {
- case SP_STROKE_LINECAP_BUTT:
- cap = CAIRO_LINE_CAP_BUTT;
- break;
- case SP_STROKE_LINECAP_ROUND:
- cap = CAIRO_LINE_CAP_ROUND;
- break;
- case SP_STROKE_LINECAP_SQUARE:
- cap = CAIRO_LINE_CAP_SQUARE;
- break;
+ case SP_STROKE_LINECAP_BUTT:
+ cap = CAIRO_LINE_CAP_BUTT;
+ break;
+ case SP_STROKE_LINECAP_ROUND:
+ cap = CAIRO_LINE_CAP_ROUND;
+ break;
+ case SP_STROKE_LINECAP_SQUARE:
+ cap = CAIRO_LINE_CAP_SQUARE;
+ break;
}
cairo_set_line_cap(_cr, cap);
cairo_set_miter_limit(_cr, MAX(1, style->stroke_miterlimit.value));
}
+void
+CairoRenderContext::_prepareRenderGraphic()
+{
+ // Only PDFLaTeX supports importing a single page of a graphics file,
+ // so only PDF backend gets interleaved text/graphics
+ if (_is_omittext && _target == CAIRO_SURFACE_TYPE_PDF) {
+ if (_omittext_state == NEW_PAGE_ON_GRAPHIC)
+ cairo_show_page(_cr);
+ _omittext_state = GRAPHIC_ON_TOP;
+ }
+}
+
+void
+CairoRenderContext::_prepareRenderText()
+{
+ // Only PDFLaTeX supports importing a single page of a graphics file,
+ // so only PDF backend gets interleaved text/graphics
+ if (_is_omittext && _target == CAIRO_SURFACE_TYPE_PDF) {
+ if (_omittext_state == GRAPHIC_ON_TOP)
+ _omittext_state = NEW_PAGE_ON_GRAPHIC;
+ }
+}
+
bool
CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle const *style, Geom::OptRect const &pbox)
{
g_assert( _is_valid );
+ _prepareRenderGraphic();
+
if (_render_mode == RENDER_MODE_CLIP) {
if (_clip_mode == CLIP_MODE_PATH) {
addClipPath(pathv, &style->fill_rule);
@@ -1400,8 +1436,8 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con
return true;
}
-bool CairoRenderContext::renderImage(GdkPixbuf *pb,
- Geom::Affine const &image_transform, SPStyle const * /*style*/)
+bool CairoRenderContext::renderImage(Inkscape::Pixbuf *pb,
+ Geom::Affine const &image_transform, SPStyle const *style)
{
g_assert( _is_valid );
@@ -1409,16 +1445,18 @@ bool CairoRenderContext::renderImage(GdkPixbuf *pb,
return true;
}
- int w = gdk_pixbuf_get_width (pb);
- int h = gdk_pixbuf_get_height (pb);
+ _prepareRenderGraphic();
+
+ int w = pb->width();
+ int h = pb->height();
// TODO: reenable merge_opacity if useful
float opacity = _state->opacity;
- cairo_surface_t *image_surface = ink_cairo_surface_create_for_argb32_pixbuf(pb);
+ cairo_surface_t *image_surface = pb->getSurfaceRaw();
if (cairo_surface_status(image_surface)) {
TRACE(("Image surface creation failed:\n%s\n", cairo_status_to_string(cairo_surface_status(image_surface))));
- return false;
+ return false;
}
cairo_save(_cr);
@@ -1434,10 +1472,30 @@ bool CairoRenderContext::renderImage(GdkPixbuf *pb,
cairo_rectangle(_cr, 0, 0, w, h);
cairo_clip(_cr);
}
+
+ // Cairo filter method will be mapped to PS/PDF 'interpolate' true/false).
+ // See cairo-pdf-surface.c
+ if (style) {
+ // See: http://www.w3.org/TR/SVG/painting.html#ImageRenderingProperty
+ // http://www.w3.org/TR/css4-images/#the-image-rendering
+ // style.h/style.cpp
+ switch (style->image_rendering.computed) {
+ case SP_CSS_COLOR_RENDERING_AUTO:
+ // Do nothing
+ break;
+ case SP_CSS_COLOR_RENDERING_OPTIMIZEQUALITY:
+ cairo_pattern_set_filter(cairo_get_source(_cr), CAIRO_FILTER_BEST );
+ break;
+ case SP_CSS_COLOR_RENDERING_OPTIMIZESPEED:
+ default:
+ cairo_pattern_set_filter(cairo_get_source(_cr), CAIRO_FILTER_NEAREST );
+ break;
+ }
+ }
+
cairo_paint_with_alpha(_cr, opacity);
cairo_restore(_cr);
- cairo_surface_destroy(image_surface);
return true;
}
@@ -1490,9 +1548,14 @@ unsigned int CairoRenderContext::_showGlyphs(cairo_t *cr, PangoFont * /*font*/,
bool
CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const &font_matrix,
std::vector<CairoGlyphInfo> const &glyphtext, SPStyle const *style)
-{
+{
+
+ _prepareRenderText();
+ if (_is_omittext)
+ return true;
+
// create a cairo_font_face from PangoFont
- double size = style->font_size.computed;
+ double size = style->font_size.computed; /// \fixme why is this variable never used?
gpointer fonthash = (gpointer)font;
cairo_font_face_t *font_face = (cairo_font_face_t *)g_hash_table_lookup(font_table, fonthash);
@@ -1633,9 +1696,9 @@ _write_callback(void *closure, const unsigned char *data, unsigned int length)
written = fwrite (data, 1, length, file);
if (written == length)
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_STATUS_SUCCESS;
else
- return CAIRO_STATUS_WRITE_ERROR;
+ return CAIRO_STATUS_WRITE_ERROR;
}
#include "clear-n_.h"
diff --git a/src/extension/internal/cairo-render-context.h b/src/extension/internal/cairo-render-context.h
index 94c7bb294..8d3e63775 100644
--- a/src/extension/internal/cairo-render-context.h
+++ b/src/extension/internal/cairo-render-context.h
@@ -6,7 +6,7 @@
*/
/*
* Authors:
- * Miklos Erdelyi <erdelyim@gmail.com>
+ * Miklos Erdelyi <erdelyim@gmail.com>
*
* Copyright (C) 2006 Miklos Erdelyi
*
@@ -32,13 +32,15 @@ class SPClipPath;
class SPMask;
namespace Inkscape {
+class Pixbuf;
+
namespace Extension {
namespace Internal {
class CairoRenderer;
class CairoRenderContext;
-class CairoRenderState;
-class CairoGlyphInfo;
+struct CairoRenderState;
+struct CairoGlyphInfo;
// Holds info for rendering a glyph
struct CairoGlyphInfo {
@@ -94,6 +96,8 @@ public:
void setPDFLevel(unsigned int level);
void setTextToPath(bool texttopath);
bool getTextToPath(void);
+ void setOmitText(bool omittext);
+ bool getOmitText(void);
void setFilterToBitmap(bool filtertobitmap);
bool getFilterToBitmap(void);
void setBitmapResolution(int resolution);
@@ -109,6 +113,9 @@ public:
/** Saves the contents of the context to a PNG file. */
bool saveAsPng(const char *file_name);
+ /** On targets supporting multiple pages, sends subsequent rendering to a new page*/
+ void newPage(void);
+
/* Render/clip mode setting/query */
void setRenderMode(CairoRenderMode mode);
CairoRenderMode getRenderMode(void) const;
@@ -139,7 +146,7 @@ public:
/* Rendering methods */
bool renderPathVector(Geom::PathVector const &pathv, SPStyle const *style, Geom::OptRect const &pbox);
- bool renderImage(GdkPixbuf *pb,
+ bool renderImage(Inkscape::Pixbuf *pb,
Geom::Affine const &image_transform, SPStyle const *style);
bool renderGlyphtext(PangoFont *font, Geom::Affine const &font_matrix,
std::vector<CairoGlyphInfo> const &glyphtext, SPStyle const *style);
@@ -150,6 +157,12 @@ protected:
CairoRenderContext(CairoRenderer *renderer);
virtual ~CairoRenderContext(void);
+ enum CairoOmitTextPageState {
+ EMPTY,
+ GRAPHIC_ON_TOP,
+ NEW_PAGE_ON_GRAPHIC
+ };
+
float _width;
float _height;
unsigned short _dpi;
@@ -157,6 +170,7 @@ protected:
unsigned int _ps_level;
bool _eps;
bool _is_texttopath;
+ bool _is_omittext;
bool _is_filtertobitmap;
int _bitmapresolution;
@@ -182,6 +196,8 @@ protected:
CairoRenderMode _render_mode;
CairoClipMode _clip_mode;
+ CairoOmitTextPageState _omittext_state;
+
cairo_pattern_t *_createPatternForPaintServer(SPPaintServer const *const paintserver,
Geom::OptRect const &pbox, float alpha);
cairo_pattern_t *_createPatternPainter(SPPaintServer const *const paintserver, Geom::OptRect const &pbox);
@@ -196,6 +212,9 @@ protected:
void _concatTransform(cairo_t *cr, double xx, double yx, double xy, double yy, double x0, double y0);
void _concatTransform(cairo_t *cr, Geom::Affine const &transform);
+ void _prepareRenderGraphic(void);
+ void _prepareRenderText(void);
+
GHashTable *font_table;
static void font_data_free(gpointer data);
diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp
index 5d45fcf87..0c314a576 100644
--- a/src/extension/internal/cairo-renderer-pdf-out.cpp
+++ b/src/extension/internal/cairo-renderer-pdf-out.cpp
@@ -39,6 +39,8 @@
#include <2geom/affine.h>
#include "document.h"
+#include "util/units.h"
+
namespace Inkscape {
namespace Extension {
namespace Internal {
@@ -57,7 +59,7 @@ bool CairoRendererPdfOutput::check(Inkscape::Extension::Extension * /*module*/)
static bool
pdf_render_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)
+ const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px)
{
doc->ensureUpToDate();
@@ -92,14 +94,14 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int
CairoRenderContext *ctx = renderer->createContext();
ctx->setPDFLevel(level);
ctx->setTextToPath(texttopath);
- renderer->_omitText = omittext;
+ ctx->setOmitText(omittext);
ctx->setFilterToBitmap(filtertobitmap);
ctx->setBitmapResolution(resolution);
bool ret = ctx->setPdfTarget (filename);
if(ret) {
/* Render document */
- ret = renderer->setupDocument(ctx, doc, pageBoundingBox, base);
+ ret = renderer->setupDocument(ctx, doc, pageBoundingBox, bleedmargin_px, base);
if (ret) {
renderer->renderItem(ctx, base);
ret = ctx->finish();
@@ -134,12 +136,12 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc,
if (ext == NULL)
return;
- const gchar *new_level = NULL;
int level = 0;
try {
- new_level = mod->get_param_enum("PDFversion");
- if((new_level != NULL) && (g_ascii_strcasecmp("PDF-1.5", new_level) == 0))
+ const gchar *new_level = mod->get_param_enum("PDFversion");
+ if((new_level != NULL) && (g_ascii_strcasecmp("PDF-1.5", new_level) == 0)) {
level = 1;
+ }
}
catch(...) {
g_warning("Parameter <PDFversion> might not exist");
@@ -185,20 +187,20 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc,
g_warning("Parameter <exportId> might not exist");
}
- bool new_exportDrawing = FALSE;
+ bool new_exportCanvas = true;
try {
- new_exportDrawing = mod->get_param_bool("areaDrawing");
- }
- catch(...) {
- g_warning("Parameter <areaDrawing> might not exist");
+ new_exportCanvas = (strcmp(ext->get_param_optiongroup("area"), "page") == 0);
+ } catch(...) {
+ g_warning("Parameter <area> might not exist");
}
+ bool new_exportDrawing = !new_exportCanvas;
- bool new_exportCanvas = FALSE;
+ float new_bleedmargin_px = 0.;
try {
- new_exportCanvas = mod->get_param_bool("areaPage");
+ new_bleedmargin_px = Inkscape::Util::Quantity::convert(mod->get_param_float("bleed"), "mm", "px");
}
catch(...) {
- g_warning("Parameter <exportCanvas> might not exist");
+ g_warning("Parameter <bleed> might not exist");
}
// Create PDF file
@@ -207,7 +209,7 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc,
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);
+ new_exportId, new_exportDrawing, new_exportCanvas, new_bleedmargin_px);
g_free(final_name);
if (!ret)
@@ -216,7 +218,7 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc,
// Create LaTeX file (if requested)
if (new_textToLaTeX) {
- ret = latex_render_document_text_to_file(doc, filename, new_exportId, new_exportDrawing, new_exportCanvas, true);
+ ret = latex_render_document_text_to_file(doc, filename, new_exportId, new_exportDrawing, new_exportCanvas, new_bleedmargin_px, true);
if (!ret)
throw Inkscape::Extension::Output::save_failed();
@@ -235,32 +237,35 @@ CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc,
void
CairoRendererPdfOutput::init (void)
{
- Inkscape::Extension::build_from_mem(
- "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
- "<name>Portable Document Format</name>\n"
- "<id>org.inkscape.output.pdf.cairorenderer</id>\n"
- "<param name=\"PDFversion\" gui-text=\"" N_("Restrict to PDF version:") "\" type=\"enum\" >\n"
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>Portable Document Format</name>\n"
+ "<id>org.inkscape.output.pdf.cairorenderer</id>\n"
+ "<param name=\"PDFversion\" gui-text=\"" N_("Restrict to PDF version:") "\" type=\"enum\" >\n"
#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0))
- "<_item value='PDF-1.5'>" N_("PDF 1.5") "</_item>\n"
+ "<_item value='PDF-1.5'>" N_("PDF 1.5") "</_item>\n"
#endif
"<_item value='PDF-1.4'>" N_("PDF 1.4") "</_item>\n"
- "</param>\n"
- "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
- "<param name=\"textToLaTeX\" gui-text=\"" N_("PDF+LaTeX: Omit text in PDF, and create LaTeX file") "\" type=\"boolean\">false</param>\n"
- "<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
- "<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi):") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
- "<param name=\"areaDrawing\" gui-text=\"" N_("Export area is drawing") "\" type=\"boolean\">false</param>\n"
- "<param name=\"areaPage\" gui-text=\"" N_("Export area is page") "\" type=\"boolean\">false</param>\n"
- "<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID:") "\" type=\"string\"></param>\n"
- "<output>\n"
- "<extension>.pdf</extension>\n"
- "<mimetype>application/pdf</mimetype>\n"
- "<filetypename>Portable Document Format (*.pdf)</filetypename>\n"
- "<filetypetooltip>PDF File</filetypetooltip>\n"
- "</output>\n"
- "</inkscape-extension>", new CairoRendererPdfOutput());
-
- return;
+ "</param>\n"
+ "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"textToLaTeX\" gui-text=\"" N_("PDF+LaTeX: Omit text in PDF, and create LaTeX file") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi):") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
+ "<param name=\"area\" gui-text=\"" N_("Output page size:") "\" type=\"optiongroup\" >\n"
+ "<_option value=\"page\">" N_("Use document's page size") "</_option>"
+ "<_option value=\"drawing\">" N_("Use exported object's size") "</_option>"
+ "</param>"
+ "<param name=\"bleed\" gui-text=\"" N_("Bleed/margin (mm):") "\" type=\"float\" min=\"-10000\" max=\"10000\">0</param>\n"
+ "<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID:") "\" type=\"string\"></param>\n"
+ "<output>\n"
+ "<extension>.pdf</extension>\n"
+ "<mimetype>application/pdf</mimetype>\n"
+ "<filetypename>Portable Document Format (*.pdf)</filetypename>\n"
+ "<filetypetooltip>PDF File</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>", new CairoRendererPdfOutput());
+
+ return;
}
} } } /* namespace Inkscape, Extension, Internal */
diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp
index 09d69becb..6fbc85c05 100644
--- a/src/extension/internal/cairo-renderer.cpp
+++ b/src/extension/internal/cairo-renderer.cpp
@@ -27,6 +27,7 @@
#include <signal.h>
#include <errno.h>
+#include <boost/scoped_ptr.hpp>
#include "libnrtype/Layout-TNG.h"
#include <2geom/transforms.h>
@@ -55,7 +56,7 @@
#include "sp-mask.h"
#include "sp-clippath.h"
-#include <unit-constants.h>
+#include "util/units.h"
#include "helper/png-write.h"
#include "helper/pixbuf-ops.h"
@@ -101,7 +102,6 @@ namespace Extension {
namespace Internal {
CairoRenderer::CairoRenderer(void)
- : _omitText(false)
{}
CairoRenderer::~CairoRenderer(void)
@@ -348,8 +348,8 @@ static void sp_image_render(SPItem *item, CairoRenderContext *ctx)
if (!image->pixbuf) return;
if ((image->width.computed <= 0.0) || (image->height.computed <= 0.0)) return;
- w = gdk_pixbuf_get_width (image->pixbuf);
- h = gdk_pixbuf_get_height (image->pixbuf);
+ w = image->pixbuf->width();
+ h = image->pixbuf->height();
double x = image->x.computed;
double y = image->y.computed;
@@ -442,7 +442,7 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx)
*/
res = ctx->getBitmapResolution();
if(res == 0) {
- res = PX_PER_IN;
+ res = Inkscape::Util::Quantity::convert(1, "in", "px");
}
TRACE(("sp_asbitmap_render: resolution: %f\n", res ));
@@ -450,7 +450,7 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx)
Geom::OptRect bbox = item->desktopVisualBounds();
// no bbox, e.g. empty group
- if (!bbox) {
+ if (!bbox) {
return;
}
@@ -463,8 +463,8 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx)
}
// The width and height of the bitmap in pixels
- unsigned width = ceil(bbox->width() * (res / PX_PER_IN));
- unsigned height = ceil(bbox->height() * (res / PX_PER_IN));
+ unsigned width = ceil(bbox->width() * Inkscape::Util::Quantity::convert(res, "px", "in"));
+ unsigned height = ceil(bbox->height() * Inkscape::Util::Quantity::convert(res, "px", "in"));
if (width == 0 || height == 0) return;
@@ -477,7 +477,7 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx)
double shift_y = bbox->max()[Geom::Y];
// For default 90 dpi, snap bitmap to pixel grid
- if (res == PX_PER_IN) {
+ if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) {
shift_x = round (shift_x);
shift_y = -round (-shift_y); // Correct rounding despite coordinate inversion.
// Remove the negations when the inversion is gone.
@@ -498,17 +498,15 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx)
GSList *items = NULL;
items = g_slist_append(items, item);
- GdkPixbuf *pb = sp_generate_internal_bitmap(document, NULL,
- bbox->min()[Geom::X], bbox->min()[Geom::Y], bbox->max()[Geom::X], bbox->max()[Geom::Y],
- width, height, res, res, (guint32) 0xffffff00, items );
+ boost::scoped_ptr<Inkscape::Pixbuf> pb(
+ sp_generate_internal_bitmap(document, NULL,
+ bbox->min()[Geom::X], bbox->min()[Geom::Y], bbox->max()[Geom::X], bbox->max()[Geom::Y],
+ width, height, res, res, (guint32) 0xffffff00, items ));
if (pb) {
- TEST(gdk_pixbuf_save( pb, "bitmap.png", "png", NULL, NULL ));
- // TODO this is stupid - we just converted to pixbuf format when generating the bitmap!
- convert_pixbuf_normal_to_argb32(pb);
- ctx->renderImage(pb, t, item->style);
- g_object_unref(pb);
- pb = 0;
+ //TEST(gdk_pixbuf_save( pb, "bitmap.png", "png", NULL, NULL ));
+
+ ctx->renderImage(pb.get(), t, item->style);
}
g_slist_free (items);
}
@@ -578,18 +576,13 @@ CairoRenderer::setStateForItem(CairoRenderContext *ctx, SPItem const *item)
// TODO change this to accept a const SPItem:
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);
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.
+ // 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();
@@ -598,13 +591,13 @@ void CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item)
sp_item_invoke_render(item, ctx);
if (state->need_layer)
- ctx->popLayer();
+ ctx->popLayer(); // This applies clipping/masking
ctx->popState();
}
bool
-CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool pageBoundingBox, SPItem *base)
+CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool pageBoundingBox, float bleedmargin_px, SPItem *base)
{
// PLEASE note when making changes to the boundingbox and transform calculation, corresponding changes should be made to PDFLaTeXRenderer::setupDocument !!!
@@ -625,10 +618,11 @@ CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool page
}
d = *bbox;
}
+ d.expandBy(bleedmargin_px);
if (ctx->_vector_based_target) {
// convert from px to pt
- d *= Geom::Scale(PT_PER_PX);
+ d *= Geom::Scale(Inkscape::Util::Quantity::convert(1, "px", "pt"));
}
ctx->_width = d.width();
@@ -638,16 +632,21 @@ CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool page
bool ret = ctx->setupSurface(ctx->_width, ctx->_height);
- if (ret && !pageBoundingBox)
- {
- double high = doc->getHeight();
- if (ctx->_vector_based_target)
- high *= PT_PER_PX;
-
- /// @fixme hardcoded dt2doc transform?
- Geom::Affine tp(Geom::Translate(-d.left() * (ctx->_vector_based_target ? PX_PER_PT : 1.0),
- (d.bottom() - high) * (ctx->_vector_based_target ? PX_PER_PT : 1.0)));
- ctx->transform(tp);
+ if (ret) {
+ if (pageBoundingBox) {
+ // translate to set bleed/margin
+ Geom::Affine tp( Geom::Translate( bleedmargin_px, bleedmargin_px ) );
+ ctx->transform(tp);
+ } else {
+ double high = doc->getHeight().value("px");
+ if (ctx->_vector_based_target)
+ high = Inkscape::Util::Quantity::convert(high, "px", "pt");
+
+ // this transform translates the export drawing to a virtual page (0,0)-(width,height)
+ Geom::Affine tp(Geom::Translate(-d.left() * (ctx->_vector_based_target ? Inkscape::Util::Quantity::convert(1, "pt", "px") : 1.0),
+ (d.bottom() - high) * (ctx->_vector_based_target ? Inkscape::Util::Quantity::convert(1, "pt", "px") : 1.0)));
+ ctx->transform(tp);
+ }
}
return ret;
diff --git a/src/extension/internal/cairo-renderer.h b/src/extension/internal/cairo-renderer.h
index 7fa7c7ff5..cfef6bdea 100644
--- a/src/extension/internal/cairo-renderer.h
+++ b/src/extension/internal/cairo-renderer.h
@@ -53,14 +53,10 @@ public:
/** Initializes the CairoRenderContext according to the specified
SPDocument. A set*Target function can only be called on the context
before setupDocument. */
- bool setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool pageBoundingBox, SPItem *base);
+ bool setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool pageBoundingBox, float bleedmargin_px, SPItem *base);
/** 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
diff --git a/src/extension/internal/cdr-input.cpp b/src/extension/internal/cdr-input.cpp
new file mode 100644
index 000000000..0111ed626
--- /dev/null
+++ b/src/extension/internal/cdr-input.cpp
@@ -0,0 +1,339 @@
+/*
+ * This file came from libwpg as a source, their utility wpg2svg
+ * specifically. It has been modified to work as an Inkscape extension.
+ * The Inkscape extension code is covered by this copyright, but the
+ * rest is covered by the one bellow.
+ *
+ * Authors:
+ * Fridrich Strba (fridrich.strba@bluewin.ch)
+ *
+ * Copyright (C) 2012 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ *
+ */
+
+#include <stdio.h>
+#include "config.h"
+
+#include "cdr-input.h"
+
+#ifdef WITH_LIBCDR
+
+#include <string>
+#include <cstring>
+
+#include <libcdr/libcdr.h>
+#include <libwpd-stream/libwpd-stream.h>
+
+#include <gtkmm/alignment.h>
+#include <gtkmm/comboboxtext.h>
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/frame.h>
+#include <gtkmm/scale.h>
+
+#include "extension/system.h"
+#include "extension/input.h"
+#include "document.h"
+
+#include "document-private.h"
+#include "document-undo.h"
+#include "inkscape.h"
+
+#include "dialogs/dialog-events.h"
+#include <gtk/gtk.h>
+#include "ui/widget/spinbutton.h"
+#include "ui/widget/frame.h"
+#include <glibmm/i18n.h>
+
+#include <gdkmm/general.h>
+
+#include "svg-view.h"
+#include "svg-view-widget.h"
+
+#include "util/units.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+
+class CdrImportDialog : public Gtk::Dialog {
+public:
+ CdrImportDialog(const std::vector<WPXString> &vec);
+ virtual ~CdrImportDialog();
+
+ bool showDialog();
+ unsigned getSelectedPage();
+ void getImportSettings(Inkscape::XML::Node *prefs);
+
+private:
+ void _setPreviewPage(unsigned page);
+
+ // Signal handlers
+#if !WITH_GTKMM_3_0
+ bool _onExposePreview(GdkEventExpose *event);
+#endif
+
+ void _onPageNumberChanged();
+
+ class Gtk::Button * cancelbutton;
+ class Gtk::Button * okbutton;
+ class Gtk::Label * _labelSelect;
+ class Inkscape::UI::Widget::SpinButton * _pageNumberSpin;
+ class Gtk::Label * _labelTotalPages;
+ class Gtk::VBox * vbox1;
+ class Gtk::VBox * vbox2;
+ class Gtk::Widget * _previewArea;
+
+ const std::vector<WPXString> &_vec; // Document to be imported
+ unsigned _current_page; // Current selected page
+ int _preview_width, _preview_height; // Size of the preview area
+};
+
+CdrImportDialog::CdrImportDialog(const std::vector<WPXString> &vec)
+ : _vec(vec), _current_page(1)
+{
+ int num_pages = _vec.size();
+ if ( num_pages <= 1 )
+ return;
+ cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel")));
+ okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok")));
+ _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:")));
+
+ // Page number
+#if WITH_GTKMM_3_0
+ Glib::RefPtr<Gtk::Adjustment> _pageNumberSpin_adj = Gtk::Adjustment::create(1, 1, _vec.size(), 1, 10, 0);
+ _pageNumberSpin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(_pageNumberSpin_adj, 1, 1));
+#else
+ Gtk::Adjustment *_pageNumberSpin_adj = Gtk::manage(
+ new class Gtk::Adjustment(1, 1, _vec.size(), 1, 10, 0));
+ _pageNumberSpin = Gtk::manage(new class Inkscape::UI::Widget::SpinButton(*_pageNumberSpin_adj, 1, 1));
+#endif
+ _labelTotalPages = Gtk::manage(new class Gtk::Label());
+ gchar *label_text = g_strdup_printf(_("out of %i"), num_pages);
+ _labelTotalPages->set_label(label_text);
+ g_free(label_text);
+
+ vbox1 = Gtk::manage(new class Gtk::VBox(false, 4));
+ SPDocument *doc = SPDocument::createNewDocFromMem(_vec[0].cstr(), strlen(_vec[0].cstr()), 0);
+ _previewArea = Glib::wrap(sp_svg_view_widget_new(doc));
+
+ vbox2 = Gtk::manage(new class Gtk::VBox(false, 4));
+ cancelbutton->set_can_focus();
+ cancelbutton->set_can_default();
+ cancelbutton->set_relief(Gtk::RELIEF_NORMAL);
+ okbutton->set_can_focus();
+ okbutton->set_can_default();
+ okbutton->set_relief(Gtk::RELIEF_NORMAL);
+ this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END);
+ _labelSelect->set_line_wrap(false);
+ _labelSelect->set_use_markup(false);
+ _labelSelect->set_selectable(false);
+ _pageNumberSpin->set_can_focus();
+ _pageNumberSpin->set_update_policy(Gtk::UPDATE_ALWAYS);
+ _pageNumberSpin->set_numeric(true);
+ _pageNumberSpin->set_digits(0);
+ _pageNumberSpin->set_wrap(false);
+ _labelTotalPages->set_line_wrap(false);
+ _labelTotalPages->set_use_markup(false);
+ _labelTotalPages->set_selectable(false);
+ vbox2->pack_start(*_previewArea, Gtk::PACK_SHRINK, 0);
+ this->get_vbox()->set_homogeneous(false);
+ this->get_vbox()->set_spacing(0);
+ this->get_vbox()->pack_start(*vbox2);
+ this->set_title(_("Page Selector"));
+ this->set_modal(true);
+ sp_transientize(GTK_WIDGET(this->gobj())); //Make transient
+ this->property_window_position().set_value(Gtk::WIN_POS_NONE);
+ this->set_resizable(true);
+ this->property_destroy_with_parent().set_value(false);
+ this->get_action_area()->add(*_labelSelect);
+ this->add_action_widget(*_pageNumberSpin, -7);
+ this->get_action_area()->add(*_labelTotalPages);
+ this->add_action_widget(*cancelbutton, -6);
+ this->add_action_widget(*okbutton, -5);
+ cancelbutton->show();
+ okbutton->show();
+ _labelSelect->show();
+ _pageNumberSpin->show();
+ _labelTotalPages->show();
+ vbox1->show();
+ _previewArea->show();
+ vbox2->show();
+
+ // Connect signals
+ _pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CdrImportDialog::_onPageNumberChanged));
+}
+
+CdrImportDialog::~CdrImportDialog() {}
+
+bool CdrImportDialog::showDialog()
+{
+ show();
+ gint b = run();
+ hide();
+ if ( b == Gtk::RESPONSE_OK ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+unsigned CdrImportDialog::getSelectedPage()
+{
+ return _current_page;
+}
+
+void CdrImportDialog::_onPageNumberChanged()
+{
+ unsigned page = static_cast<unsigned>(_pageNumberSpin->get_value_as_int());
+ _current_page = CLAMP(page, 1U, _vec.size());
+ _setPreviewPage(_current_page);
+}
+
+/**
+ * \brief Renders the given page's thumbnail
+ */
+void CdrImportDialog::_setPreviewPage(unsigned page)
+{
+ SPDocument *doc = SPDocument::createNewDocFromMem(_vec[page-1].cstr(), strlen(_vec[page-1].cstr()), 0);
+ Gtk::Widget * tmpPreviewArea = Glib::wrap(sp_svg_view_widget_new(doc));
+ std::swap(_previewArea, tmpPreviewArea);
+ if (tmpPreviewArea) {
+ _previewArea->set_size_request( tmpPreviewArea->get_width(), tmpPreviewArea->get_height() );
+ delete tmpPreviewArea;
+ }
+ vbox2->pack_start(*_previewArea, Gtk::PACK_SHRINK, 0);
+ _previewArea->show_now();
+}
+
+SPDocument *CdrInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri)
+{
+ WPXFileStream input(uri);
+
+ if (!libcdr::CDRDocument::isSupported(&input)) {
+ return NULL;
+ }
+
+ libcdr::CDRStringVector output;
+ if (!libcdr::CDRDocument::generateSVG(&input, output)) {
+ return NULL;
+ }
+
+ if (output.empty()) {
+ return NULL;
+ }
+
+ std::vector<WPXString> tmpSVGOutput;
+ for (unsigned i=0; i<output.size(); ++i) {
+ WPXString tmpString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+ tmpString.append(output[i]);
+ tmpSVGOutput.push_back(tmpString);
+ }
+
+ unsigned page_num = 1;
+
+ // If only one page is present, import that one without bothering user
+ if (tmpSVGOutput.size() > 1) {
+ CdrImportDialog *dlg = 0;
+ if (inkscape_use_gui()) {
+ dlg = new CdrImportDialog(tmpSVGOutput);
+ if (!dlg->showDialog()) {
+ delete dlg;
+ return NULL;
+ }
+ }
+
+ // Get needed page
+ if (dlg) {
+ page_num = dlg->getSelectedPage();
+ if (page_num < 1)
+ page_num = 1;
+ if (page_num > tmpSVGOutput.size())
+ page_num = tmpSVGOutput.size();
+ }
+ }
+
+ SPDocument * doc = SPDocument::createNewDocFromMem(tmpSVGOutput[page_num-1].cstr(), strlen(tmpSVGOutput[page_num-1].cstr()), TRUE);
+
+ // Set viewBox if it doesn't exist
+ if (doc && !doc->getRoot()->viewBox_set) {
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit())));
+ }
+ return doc;
+}
+
+#include "clear-n_.h"
+
+void CdrInput::init(void)
+{
+ /* CDR */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("Corel DRAW Input") "</name>\n"
+ "<id>org.inkscape.input.cdr</id>\n"
+ "<input>\n"
+ "<extension>.cdr</extension>\n"
+ "<mimetype>image/x-xcdr</mimetype>\n"
+ "<filetypename>" N_("Corel DRAW 7-X4 files (*.cdr)") "</filetypename>\n"
+ "<filetypetooltip>" N_("Open files saved in Corel DRAW 7-X4") "</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>", new CdrInput());
+
+ /* CDT */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("Corel DRAW templates input") "</name>\n"
+ "<id>org.inkscape.input.cdt</id>\n"
+ "<input>\n"
+ "<extension>.cdt</extension>\n"
+ "<mimetype>application/x-xcdt</mimetype>\n"
+ "<filetypename>" N_("Corel DRAW 7-13 template files (*.cdt)") "</filetypename>\n"
+ "<filetypetooltip>" N_("Open files saved in Corel DRAW 7-13") "</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>", new CdrInput());
+
+ /* CCX */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("Corel DRAW Compressed Exchange files input") "</name>\n"
+ "<id>org.inkscape.input.ccx</id>\n"
+ "<input>\n"
+ "<extension>.ccx</extension>\n"
+ "<mimetype>application/x-xccx</mimetype>\n"
+ "<filetypename>" N_("Corel DRAW Compressed Exchange files (*.ccx)") "</filetypename>\n"
+ "<filetypetooltip>" N_("Open compressed exchange files saved in Corel DRAW") "</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>", new CdrInput());
+
+ /* CMX */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("Corel DRAW Presentation Exchange files input") "</name>\n"
+ "<id>org.inkscape.input.cmx</id>\n"
+ "<input>\n"
+ "<extension>.cmx</extension>\n"
+ "<mimetype>application/x-xcmx</mimetype>\n"
+ "<filetypename>" N_("Corel DRAW Presentation Exchange files (*.cmx)") "</filetypename>\n"
+ "<filetypetooltip>" N_("Open presentation exchange files saved in Corel DRAW") "</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>", new CdrInput());
+
+ return;
+
+} // init
+
+} } } /* namespace Inkscape, Extension, Implementation */
+#endif /* WITH_LIBCDR */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/cdr-input.h b/src/extension/internal/cdr-input.h
new file mode 100644
index 000000000..3de6c1ed0
--- /dev/null
+++ b/src/extension/internal/cdr-input.h
@@ -0,0 +1,58 @@
+/*
+ * This code abstracts the libwpg interfaces into the Inkscape
+ * input extension interface.
+ *
+ * Authors:
+ * Fridrich Strba (fridrich.strba@bluewin.ch)
+ *
+ * Copyright (C) 2012 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef __EXTENSION_INTERNAL_CDROUTPUT_H__
+#define __EXTENSION_INTERNAL_CDROUTPUT_H__
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef WITH_LIBCDR
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
+#include <gtkmm/dialog.h>
+
+#include "../implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class CdrInput : public Inkscape::Extension::Implementation::Implementation {
+ CdrInput () { };
+public:
+ SPDocument *open( Inkscape::Extension::Input *mod,
+ const gchar *uri );
+ static void init( void );
+
+};
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+#endif /* WITH_LIBCDR */
+#endif /* __EXTENSION_INTERNAL_CDROUTPUT_H__ */
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp
new file mode 100644
index 000000000..eae3bfb5a
--- /dev/null
+++ b/src/extension/internal/emf-inout.cpp
@@ -0,0 +1,3547 @@
+/** @file
+ * @brief Windows-only Enhanced Metafile input and output.
+ */
+/* Authors:
+ * Ulf Erikson <ulferikson@users.sf.net>
+ * Jon A. Cruz <jon@joncruz.org>
+ * David Mathog
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006-2008 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ *
+ * References:
+ * - How to Create & Play Enhanced Metafiles in Win32
+ * http://support.microsoft.com/kb/q145999/
+ * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
+ * http://support.microsoft.com/kb/q66949/
+ * - Metafile Functions
+ * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
+ * - Metafile Structures
+ * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+//#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <libuemf/symbol_convert.h>
+
+#include "sp-root.h"
+#include "sp-path.h"
+#include "style.h"
+#include "print.h"
+#include "extension/system.h"
+#include "extension/print.h"
+#include "extension/db.h"
+#include "extension/input.h"
+#include "extension/output.h"
+#include "display/drawing.h"
+#include "display/drawing-item.h"
+#include "clear-n_.h"
+#include "document.h"
+#include "util/units.h"
+#include "shape-editor.h"
+#include "sp-namedview.h"
+#include "document-undo.h"
+#include "inkscape.h"
+
+#include "emf-print.h"
+#include "emf-inout.h"
+
+#define PRINT_EMF "org.inkscape.print.emf"
+
+#ifndef U_PS_JOIN_MASK
+#define U_PS_JOIN_MASK (U_PS_JOIN_BEVEL|U_PS_JOIN_MITER|U_PS_JOIN_ROUND)
+#endif
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+static U_RECTL rc_old = rectl_set(pointl_set(-1,-1),pointl_set(-1,-1));
+static bool clipset = false;
+static uint32_t ICMmode = 0; // not used yet, but code to read it from EMF implemented
+static uint32_t BLTmode = 0;
+
+Emf::Emf (void) // The null constructor
+{
+ return;
+}
+
+
+Emf::~Emf (void) //The destructor
+{
+ return;
+}
+
+
+bool
+Emf::check (Inkscape::Extension::Extension * /*module*/)
+{
+ if (NULL == Inkscape::Extension::db.get(PRINT_EMF))
+ return FALSE;
+ return TRUE;
+}
+
+
+void
+Emf::print_document_to_file(SPDocument *doc, const gchar *filename)
+{
+ Inkscape::Extension::Print *mod;
+ SPPrintContext context;
+ const gchar *oldconst;
+ gchar *oldoutput;
+ unsigned int ret;
+
+ doc->ensureUpToDate();
+
+ mod = Inkscape::Extension::get_print(PRINT_EMF);
+ oldconst = mod->get_param_string("destination");
+ oldoutput = g_strdup(oldconst);
+ mod->set_param_string("destination", filename);
+
+/* Start */
+ context.module = mod;
+ /* fixme: This has to go into module constructor somehow */
+ /* Create new arena */
+ mod->base = doc->getRoot();
+ Inkscape::Drawing drawing;
+ mod->dkey = SPItem::display_key_new(1);
+ mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY);
+ drawing.setRoot(mod->root);
+ /* Print document */
+ ret = mod->begin(doc);
+ if (ret) {
+ g_free(oldoutput);
+ throw Inkscape::Extension::Output::save_failed();
+ }
+ mod->base->invoke_print(&context);
+ (void) mod->finish();
+ /* Release arena */
+ mod->base->invoke_hide(mod->dkey);
+ mod->base = NULL;
+ mod->root = NULL; // deleted by invoke_hide
+/* end */
+
+ mod->set_param_string("destination", oldoutput);
+ g_free(oldoutput);
+
+ return;
+}
+
+
+void
+Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
+{
+ Inkscape::Extension::Extension * ext;
+
+ ext = Inkscape::Extension::db.get(PRINT_EMF);
+ if (ext == NULL)
+ return;
+
+ bool new_val = mod->get_param_bool("textToPath");
+ bool new_FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); // character position bug
+ // reserve FixPPT2 for opacity bug. Currently EMF does not export opacity values
+ bool new_FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); // dashed line bug
+ bool new_FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); // gradient bug
+ bool new_FixPPTLinGrad = mod->get_param_bool("FixPPTLinGrad"); // allow native rectangular linear gradient
+ bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard EMF hatch
+ bool new_FixImageRot = mod->get_param_bool("FixImageRot"); // remove rotations on images
+
+ TableGen( //possibly regenerate the unicode-convert tables
+ mod->get_param_bool("TnrToSymbol"),
+ mod->get_param_bool("TnrToWingdings"),
+ mod->get_param_bool("TnrToZapfDingbats"),
+ mod->get_param_bool("UsePUA")
+ );
+
+ ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintEmf::init or a mysterious failure will result!
+ ext->set_param_bool("FixPPTDashLine",new_FixPPTDashLine);
+ ext->set_param_bool("FixPPTGrad2Polys",new_FixPPTGrad2Polys);
+ ext->set_param_bool("FixPPTLinGrad",new_FixPPTLinGrad);
+ ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch);
+ ext->set_param_bool("FixImageRot",new_FixImageRot);
+ ext->set_param_bool("textToPath", new_val);
+
+ print_document_to_file(doc, filename);
+
+ return;
+}
+
+
+/* given the transformation matrix from worldTransform return the scale in the matrix part. Assumes that the
+ matrix is not used to skew, invert, or make another distorting transformation. */
+double Emf::current_scale(PEMF_CALLBACK_DATA d){
+ double scale =
+ d->dc[d->level].worldTransform.eM11 * d->dc[d->level].worldTransform.eM22 -
+ d->dc[d->level].worldTransform.eM12 * d->dc[d->level].worldTransform.eM21;
+ if(scale <= 0.0)scale=1.0; /* something is dreadfully wrong with the matrix, but do not crash over it */
+ scale=sqrt(scale);
+ return(scale);
+}
+
+/* given the transformation matrix from worldTransform and the current x,y position in inkscape coordinates,
+ generate an SVG transform that gives the same amount of rotation, no scaling, and maps x,y back onto x,y. This is used for
+ rotating objects when the location of at least one point in that object is known. Returns:
+ "matrix(a,b,c,d,e,f)" (WITH the double quotes)
+*/
+std::string Emf::current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset){
+ std::stringstream cxform;
+ double scale = current_scale(d);
+ cxform << "\"matrix(";
+ cxform << d->dc[d->level].worldTransform.eM11/scale; cxform << ",";
+ cxform << d->dc[d->level].worldTransform.eM12/scale; cxform << ",";
+ cxform << d->dc[d->level].worldTransform.eM21/scale; cxform << ",";
+ cxform << d->dc[d->level].worldTransform.eM22/scale; cxform << ",";
+ if(useoffset){
+ /* for the "new" coordinates drop the worldtransform translations, not used here */
+ double newx = x * d->dc[d->level].worldTransform.eM11/scale + y * d->dc[d->level].worldTransform.eM21/scale;
+ double newy = x * d->dc[d->level].worldTransform.eM12/scale + y * d->dc[d->level].worldTransform.eM22/scale;
+ cxform << x - newx; cxform << ",";
+ cxform << y - newy;
+ }
+ else {
+ cxform << "0,0";
+ }
+ cxform << ")\"";
+ return(cxform.str());
+}
+
+/* given the transformation matrix from worldTransform return the rotation angle in radians.
+ counter clocwise from the x axis. */
+double Emf::current_rotation(PEMF_CALLBACK_DATA d){
+ return -std::atan2(d->dc[d->level].worldTransform.eM12, d->dc[d->level].worldTransform.eM11);
+}
+
+/* Add another 100 blank slots to the hatches array.
+*/
+void Emf::enlarge_hatches(PEMF_CALLBACK_DATA d){
+ d->hatches.size += 100;
+ d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *));
+}
+
+/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
+*/
+int Emf::in_hatches(PEMF_CALLBACK_DATA d, char *test){
+ int i;
+ for(i=0; i<d->hatches.count; i++){
+ if(strcmp(test,d->hatches.strings[i])==0)return(i+1);
+ }
+ return(0);
+}
+
+/* (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one
+ does not exist it is added to the hatches list and also entered into <defs>.
+ This is also used to add the path part of the hatches, which they reference with a xlink:href
+*/
+uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){
+ char hatchname[64]; // big enough
+ char hpathname[64]; // big enough
+ char hbkname[64]; // big enough
+ char tmpcolor[8];
+ char bkcolor[8];
+ uint32_t idx;
+
+ switch(hatchType){
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor));
+ break;
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
+ break;
+ default:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor));
+ break;
+ }
+
+ /* For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch.
+ This will be used late to compose, or recompose the transparent or opaque final hatch.*/
+
+ std::string refpath; // used to reference later the path pieces which are about to be created
+ sprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor);
+ idx = in_hatches(d,hpathname);
+ if(!idx){ // add path/color if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hpathname);
+
+ *(d->defs) += "\n";
+ switch(hatchType){
+ case U_HS_HORIZONTAL:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_VERTICAL:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_FDIAGONAL:
+ *(d->defs) += " <line id=\"sub";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_BDIAGONAL:
+ *(d->defs) += " <line id=\"sub";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_CROSS:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_DIAGCROSS:
+ *(d->defs) += " <line id=\"subfd";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ *(d->defs) += " <line id=\"subbd";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_SOLIDCLR:
+ case U_HS_DITHEREDCLR:
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ default:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += ";stroke:none";
+ *(d->defs) += "\" />\n";
+ break;
+ }
+ }
+
+ // References to paths possibly just created above. These will be used in the actual patterns.
+ switch(hatchType){
+ case U_HS_HORIZONTAL:
+ case U_HS_VERTICAL:
+ case U_HS_CROSS:
+ case U_HS_SOLIDCLR:
+ case U_HS_DITHEREDCLR:
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ default:
+ refpath += " <use xlink:href=\"#";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ break;
+ case U_HS_FDIAGONAL:
+ case U_HS_BDIAGONAL:
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\" />\n";
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\" />\n";
+ break;
+ case U_HS_DIAGCROSS:
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\"/>\n";
+ break;
+ }
+
+ if(d->dc[d->level].bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR){
+ sprintf(hatchname,"EMFhatch%d_%s",hatchType,tmpcolor);
+ sprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor);
+ idx = in_hatches(d,hatchname);
+ if(!idx){ // add it if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hatchname);
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += hatchname;
+ *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n";
+ *(d->defs) += refpath;
+ *(d->defs) += " </pattern>\n";
+ idx = d->hatches.count;
+ }
+ }
+ else { // bkMode==U_OPAQUE
+ /* Set up an object in the defs for this background, if there is not one already there */
+ sprintf(bkcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
+ sprintf(hbkname,"EMFhbkclr_%s",bkcolor);
+ idx = in_hatches(d,hbkname);
+ if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name.
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hbkname);
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <rect id=\"";
+ *(d->defs) += hbkname;
+ *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
+ *(d->defs) += bkcolor;
+ *(d->defs) += "\" />\n";
+ }
+
+ // this is the pattern, its name will show up in Inkscape's pattern selector
+ sprintf(hatchname,"EMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor);
+ idx = in_hatches(d,hatchname);
+ if(!idx){ // add it if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hatchname);
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += hatchname;
+ *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n";
+ *(d->defs) += " <use xlink:href=\"#";
+ *(d->defs) += hbkname;
+ *(d->defs) += "\" />\n";
+ *(d->defs) += refpath;
+ *(d->defs) += " </pattern>\n";
+ idx = d->hatches.count;
+ }
+ }
+ return(idx-1);
+}
+
+/* Add another 100 blank slots to the images array.
+*/
+void Emf::enlarge_images(PEMF_CALLBACK_DATA d){
+ d->images.size += 100;
+ d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *));
+}
+
+/* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1)
+*/
+int Emf::in_images(PEMF_CALLBACK_DATA d, char *test){
+ int i;
+ for(i=0; i<d->images.count; i++){
+ if(strcmp(test,d->images.strings[i])==0)return(i+1);
+ }
+ return(0);
+}
+
+/* (Conditionally) add an image. If a matching image already exists nothing happens. If one
+ does not exist it is added to the images list and also entered into <defs>.
+
+ U_EMRCREATEMONOBRUSH records only work when the bitmap is monochrome. If we hit one that isn't
+ set idx to 2^32-1 and let the caller handle it.
+*/
+uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi,
+ uint32_t iUsage, uint32_t offBits, uint32_t offBmi){
+
+ uint32_t idx;
+ char imagename[64]; // big enough
+ char imrotname[64]; // big enough
+ char xywh[64]; // big enough
+ int dibparams = U_BI_UNKNOWN; // type of image not yet determined
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // DIB color table
+ U_RGBQUAD ct2[2];
+ uint32_t width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params
+ if(cbBits && cbBmi && (iUsage == U_DIB_RGB_COLORS)){
+ // next call returns pointers and values, but allocates no memory
+ dibparams = get_DIB_params(pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct,
+ &numCt, &width, &height, &colortype, &invert);
+ if(dibparams ==U_BI_RGB){
+ // U_EMRCREATEMONOBRUSH uses text/bk colors instead of what is in the color map.
+ if(((PU_EMR)pEmr)->iType == U_EMR_CREATEMONOBRUSH){
+ if(numCt==2){
+ ct2[0] = U_RGB2BGR(d->dc[d->level].textColor);
+ ct2[1] = U_RGB2BGR(d->dc[d->level].bkColor);
+ ct = &ct2[0];
+ }
+ else { // This record is invalid, nothing more to do here, let caller handle it
+ return(U_EMR_INVALID);
+ }
+ }
+
+ if(!DIB_to_RGBA(
+ px, // DIB pixel array
+ ct, // DIB color table
+ numCt, // DIB color table number of entries
+ &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ width, // Width of pixel array in record
+ height, // Height of pixel array in record
+ colortype, // DIB BitCount Enumeration
+ numCt, // Color table used if not 0
+ invert // If DIB rows are in opposite order from RGBA rows
+ )){
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ width, height, // of the SRC bitmap
+ rgba_px
+ );
+ free(rgba_px);
+ }
+ }
+ }
+
+ gchar *base64String=NULL;
+ if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ // image was binary png or jpg in source file
+ base64String = g_base64_encode((guchar*) px, numCt );
+ }
+ else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine
+ base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ }
+ else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
+ width = 3;
+ height = 4;
+ base64String = bad_image_png();
+ }
+
+ idx = in_images(d, (char *) base64String);
+ if(!idx){ // add it if not already present - we looked at the actual data for comparison
+ if(d->images.count == d->images.size){ enlarge_images(d); }
+ idx = d->images.count;
+ d->images.strings[d->images.count++]=strdup(base64String);
+
+ sprintf(imagename,"EMFimage%d",idx++);
+ sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <image id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n";
+ if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; }
+ else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; }
+ *(d->defs) += base64String;
+ *(d->defs) += "\"\n";
+ *(d->defs) += " preserveAspectRatio=\"none\"\n";
+ *(d->defs) += " />\n";
+
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ref\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
+ *(d->defs) += " >\n";
+ *(d->defs) += " <use id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ign\" ";
+ *(d->defs) += " xlink:href=\"#";
+ *(d->defs) += imagename;
+ *(d->defs) += "\" />\n";
+ *(d->defs) += " ";
+ *(d->defs) += " </pattern>\n";
+ }
+ g_free(base64String);//wait until this point to free because it might be a duplicate image
+
+ /* image allows the inner image to be rotated nicely, load this one second only if needed
+ imagename retained from above
+ Here comes a dreadful hack. How do we determine if this rotation of the base image has already
+ been loaded? The image names contain no identifying information, they are just numbered sequentially.
+ So the rotated name is EMFrotimage###_XXXXXX, where ### is the number of the referred to image, and
+ XXXX is the rotation in radians x 1000000 and truncated. That is then stored in BASE64 as the "image".
+ The corresponding SVG generated though is not for an image, but a reference to an image.
+ The name of the pattern MUST stil be EMFimage###_ref or output_style() will not be able to use it.
+ */
+ if(current_rotation(d) >= 0.00001 || current_rotation(d) <= -0.00001){ /* some rotation, allow a little rounding error around 0 degrees */
+ int tangle = round(current_rotation(d)*1000000.0);
+ sprintf(imrotname,"EMFrotimage%d_%d",idx-1,tangle);
+ base64String = g_base64_encode((guchar*) imrotname, strlen(imrotname) );
+ idx = in_images(d, (char *) base64String); // scan for this "image"
+ if(!idx){
+ if(d->images.count == d->images.size){ enlarge_images(d); }
+ idx = d->images.count;
+ d->images.strings[d->images.count++]=strdup(base64String);
+ sprintf(imrotname,"EMFimage%d",idx++);
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern\n";
+ *(d->defs) += " id=\"";
+ *(d->defs) += imrotname;
+ *(d->defs) += "_ref\"\n";
+ *(d->defs) += " xlink:href=\"#";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ref\"\n";
+ *(d->defs) += " patternTransform=";
+ *(d->defs) += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0
+ *(d->defs) += " />\n";
+ }
+ g_free(base64String);
+ }
+
+ return(idx-1);
+}
+
+/* Add another 100 blank slots to the gradients array.
+*/
+void Emf::enlarge_gradients(PEMF_CALLBACK_DATA d){
+ d->gradients.size += 100;
+ d->gradients.strings = (char **) realloc(d->gradients.strings,d->gradients.size * sizeof(char *));
+}
+
+/* See if the gradient name is already in the list. If it is return its position (1->n, not 1-n-1)
+*/
+int Emf::in_gradients(PEMF_CALLBACK_DATA d, char *test){
+ int i;
+ for(i=0; i<d->gradients.count; i++){
+ if(strcmp(test,d->gradients.strings[i])==0)return(i+1);
+ }
+ return(0);
+}
+
+U_COLORREF trivertex_to_colorref(U_TRIVERTEX tv){
+ U_COLORREF uc;
+ uc.Red = tv.Red >> 8;
+ uc.Green = tv.Green >> 8;
+ uc.Blue = tv.Blue >> 8;
+ uc.Reserved = tv.Alpha >> 8; // Not used
+ return(uc);
+}
+
+/* (Conditionally) add a gradient. If a matching gradient already exists nothing happens. If one
+ does not exist it is added to the gradients list and also entered into <defs>.
+ Only call this with H or V gradient, not a triangle.
+*/
+uint32_t Emf::add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2){
+ char hgradname[64]; // big enough
+ char tmpcolor1[8];
+ char tmpcolor2[8];
+ char gradc;
+ uint32_t idx;
+ std::string x2,y2;
+
+ U_COLORREF gradientColor1 = trivertex_to_colorref(tv1);
+ U_COLORREF gradientColor2 = trivertex_to_colorref(tv2);
+
+
+ sprintf(tmpcolor1,"%6.6X",sethexcolor(gradientColor1));
+ sprintf(tmpcolor2,"%6.6X",sethexcolor(gradientColor2));
+ switch(gradientType){
+ case U_GRADIENT_FILL_RECT_H:
+ gradc='H';
+ x2="100";
+ y2="0";
+ break;
+ case U_GRADIENT_FILL_RECT_V:
+ gradc='V';
+ x2="0";
+ y2="100";
+ break;
+ default: // this should never happen, but fill these in to avoid compiler warnings
+ gradc='!';
+ x2="0";
+ y2="0";
+ break;
+ }
+
+ /* Even though the gradient was defined as Horizontal or Vertical if the rectangle is rotated it needs to
+ be at some other alignment, and that needs gradienttransform. Set the name using the same sort of hack
+ as for add_image.
+ */
+ int tangle = round(current_rotation(d)*1000000.0);
+ sprintf(hgradname,"LinGrd%c_%s_%s_%d",gradc,tmpcolor1,tmpcolor2,tangle);
+
+ idx = in_gradients(d,hgradname);
+ if(!idx){ // gradient does not yet exist
+ if(d->gradients.count == d->gradients.size){ enlarge_gradients(d); }
+ d->gradients.strings[d->gradients.count++]=strdup(hgradname);
+ idx = d->gradients.count;
+ SVGOStringStream stmp;
+ stmp << " <linearGradient id=\"";
+ stmp << hgradname;
+ stmp << "\" x1=\"";
+ stmp << pix_to_x_point(d, tv1.x , tv1.y);
+ stmp << "\" y1=\"";
+ stmp << pix_to_y_point(d, tv1.x , tv1.y);
+ stmp << "\" x2=\"";
+ if(gradc=='H'){ // UR corner
+ stmp << pix_to_x_point(d, tv2.x , tv1.y);
+ stmp << "\" y2=\"";
+ stmp << pix_to_y_point(d, tv2.x , tv1.y);
+ }
+ else { // LL corner
+ stmp << pix_to_x_point(d, tv1.x , tv2.y);
+ stmp << "\" y2=\"";
+ stmp << pix_to_y_point(d, tv1.x , tv2.y);
+ }
+ stmp << "\" gradientTransform=\"(1,0,0,1,0,0)\"";
+ stmp << " gradientUnits=\"userSpaceOnUse\"\n";
+ stmp << ">\n";
+ stmp << " <stop offset=\"0\" style=\"stop-color:#";
+ stmp << tmpcolor1;
+ stmp << ";stop-opacity:1\" />\n";
+ stmp << " <stop offset=\"1\" style=\"stop-color:#";
+ stmp << tmpcolor2;
+ stmp << ";stop-opacity:1\" />\n";
+ stmp << " </linearGradient>\n";
+ *(d->defs) += stmp.str().c_str();
+ }
+
+ return(idx-1);
+}
+
+
+
+void
+Emf::output_style(PEMF_CALLBACK_DATA d, int iType)
+{
+// SVGOStringStream tmp_id;
+ SVGOStringStream tmp_style;
+ char tmp[1024] = {0};
+
+ float fill_rgb[3];
+ sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb );
+ float stroke_rgb[3];
+ sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb);
+
+ // for U_EMR_BITBLT with no image, try to approximate some of these operations/
+ // Assume src color is "white"
+ if(d->dwRop3){
+ switch(d->dwRop3){
+ case U_PATINVERT: // invert pattern
+ fill_rgb[0] = 1.0 - fill_rgb[0];
+ fill_rgb[1] = 1.0 - fill_rgb[1];
+ fill_rgb[2] = 1.0 - fill_rgb[2];
+ break;
+ case U_SRCINVERT: // treat all of these as black
+ case U_DSTINVERT:
+ case U_BLACKNESS:
+ case U_SRCERASE:
+ case U_NOTSRCCOPY:
+ fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0;
+ break;
+ case U_SRCCOPY: // treat all of these as white
+ case U_NOTSRCERASE:
+ case U_WHITENESS:
+ fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0;
+ break;
+ case U_SRCPAINT: // use the existing color
+ case U_SRCAND:
+ case U_MERGECOPY:
+ case U_MERGEPAINT:
+ case U_PATPAINT:
+ case U_PATCOPY:
+ default:
+ break;
+ }
+ d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT
+ }
+
+ // Implement some of these, the ones where the original screen color does not matter.
+ // The options that merge screen and pen colors cannot be done correctly because we
+ // have no way of knowing what color is already on the screen. For those just pass the
+ // pen color through.
+ switch(d->dwRop2){
+ case U_R2_BLACK:
+ fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0;
+ stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0;
+ break;
+ case U_R2_NOTMERGEPEN:
+ case U_R2_MASKNOTPEN:
+ break;
+ case U_R2_NOTCOPYPEN:
+ fill_rgb[0] = 1.0 - fill_rgb[0];
+ fill_rgb[1] = 1.0 - fill_rgb[1];
+ fill_rgb[2] = 1.0 - fill_rgb[2];
+ stroke_rgb[0] = 1.0 - stroke_rgb[0];
+ stroke_rgb[1] = 1.0 - stroke_rgb[1];
+ stroke_rgb[2] = 1.0 - stroke_rgb[2];
+ break;
+ case U_R2_MASKPENNOT:
+ case U_R2_NOT:
+ case U_R2_XORPEN:
+ case U_R2_NOTMASKPEN:
+ case U_R2_NOTXORPEN:
+ case U_R2_NOP:
+ case U_R2_MERGENOTPEN:
+ case U_R2_COPYPEN:
+ case U_R2_MASKPEN:
+ case U_R2_MERGEPENNOT:
+ case U_R2_MERGEPEN:
+ break;
+ case U_R2_WHITE:
+ fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0;
+ stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0;
+ break;
+ default:
+ break;
+ }
+
+
+// tmp_id << "\n\tid=\"" << (d->id++) << "\"";
+// *(d->outsvg) += tmp_id.str().c_str();
+ *(d->outsvg) += "\n\tstyle=\"";
+ if (iType == U_EMR_STROKEPATH || !d->dc[d->level].fill_set) {
+ tmp_style << "fill:none;";
+ } else {
+ switch(d->dc[d->level].fill_mode){
+ // both of these use the url(#) method
+ case DRAW_PATTERN:
+ snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]);
+ tmp_style << tmp;
+ break;
+ case DRAW_IMAGE:
+ snprintf(tmp, 1023, "fill:url(#EMFimage%d_ref); ",d->dc[d->level].fill_idx);
+ tmp_style << tmp;
+ break;
+ case DRAW_LINEAR_GRADIENT:
+ case DRAW_PAINT:
+ default: // <-- this should never happen, but just in case...
+ snprintf(
+ tmp, 1023,
+ "fill:#%02x%02x%02x;",
+ SP_COLOR_F_TO_U(fill_rgb[0]),
+ SP_COLOR_F_TO_U(fill_rgb[1]),
+ SP_COLOR_F_TO_U(fill_rgb[2])
+ );
+ tmp_style << tmp;
+ break;
+ }
+ snprintf(
+ tmp, 1023,
+ "fill-rule:%s;",
+ (d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero")
+ );
+ tmp_style << tmp;
+ tmp_style << "fill-opacity:1;";
+
+ // if the stroke is the same as the fill, and the right size not to change the end size of the object, do not do it separately
+ if(
+ (d->dc[d->level].fill_set ) &&
+ (d->dc[d->level].stroke_set ) &&
+ (d->dc[d->level].style.stroke_width.value == 1 ) &&
+ (d->dc[d->level].fill_mode == d->dc[d->level].stroke_mode) &&
+ (
+ (d->dc[d->level].fill_mode != DRAW_PAINT) ||
+ (
+ (fill_rgb[0]==stroke_rgb[0]) &&
+ (fill_rgb[1]==stroke_rgb[1]) &&
+ (fill_rgb[2]==stroke_rgb[2])
+ )
+ )
+ ){
+ d->dc[d->level].stroke_set = false;
+ }
+ }
+
+ if (iType == U_EMR_FILLPATH || !d->dc[d->level].stroke_set) {
+ tmp_style << "stroke:none;";
+ } else {
+ switch(d->dc[d->level].stroke_mode){
+ // both of these use the url(#) method
+ case DRAW_PATTERN:
+ snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]);
+ tmp_style << tmp;
+ break;
+ case DRAW_IMAGE:
+ snprintf(tmp, 1023, "stroke:url(#EMFimage%d_ref); ",d->dc[d->level].stroke_idx);
+ tmp_style << tmp;
+ break;
+ case DRAW_LINEAR_GRADIENT:
+ case DRAW_PAINT:
+ default: // <-- this should never happen, but just in case...
+ snprintf(
+ tmp, 1023,
+ "stroke:#%02x%02x%02x;",
+ SP_COLOR_F_TO_U(stroke_rgb[0]),
+ SP_COLOR_F_TO_U(stroke_rgb[1]),
+ SP_COLOR_F_TO_U(stroke_rgb[2])
+ );
+ tmp_style << tmp;
+ break;
+ }
+ tmp_style << "stroke-width:" <<
+ MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
+
+ tmp_style << "stroke-linecap:" <<
+ (
+ d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" :
+ d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" :
+ d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" :
+ "unknown"
+ ) << ";";
+
+ tmp_style << "stroke-linejoin:" <<
+ (
+ d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" :
+ d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" :
+ d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" :
+ "unknown"
+ ) << ";";
+
+ // Set miter limit if known, even if it is not needed immediately (not miter)
+ tmp_style << "stroke-miterlimit:" <<
+ MAX( 2.0, d->dc[d->level].style.stroke_miterlimit.value ) << ";";
+
+ if (d->dc[d->level].style.stroke_dasharray.set &&
+ !d->dc[d->level].style.stroke_dasharray.values.empty() )
+ {
+ tmp_style << "stroke-dasharray:";
+ for (unsigned i=0; i<d->dc[d->level].style.stroke_dasharray.values.size(); i++) {
+ if (i)
+ tmp_style << ",";
+ tmp_style << d->dc[d->level].style.stroke_dasharray.values[i];
+ }
+ tmp_style << ";";
+ tmp_style << "stroke-dashoffset:0;";
+ } else {
+ tmp_style << "stroke-dasharray:none;";
+ }
+ tmp_style << "stroke-opacity:1;";
+ }
+ tmp_style << "\" ";
+ if (clipset)
+ tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->id << ")\" ";
+ clipset = false;
+
+ *(d->outsvg) += tmp_style.str().c_str();
+}
+
+
+double
+Emf::_pix_x_to_point(PEMF_CALLBACK_DATA d, double px)
+{
+ double scale = (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0);
+ double tmp;
+ tmp = ((((double) (px - d->dc[d->level].winorg.x))*scale) + d->dc[d->level].vieworg.x) * d->D2PscaleX;
+ tmp -= d->ulCornerOutX; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
+ return(tmp);
+}
+
+double
+Emf::_pix_y_to_point(PEMF_CALLBACK_DATA d, double py)
+{
+ double scale = (d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0);
+ double tmp;
+ tmp = ((((double) (py - d->dc[d->level].winorg.y))*scale) * d->E2IdirY + d->dc[d->level].vieworg.y) * d->D2PscaleY;
+ tmp -= d->ulCornerOutY; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
+ return(tmp);
+}
+
+
+double
+Emf::pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py)
+{
+ double wpx = px * d->dc[d->level].worldTransform.eM11 + py * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx;
+ double x = _pix_x_to_point(d, wpx);
+
+ return x;
+}
+
+double
+Emf::pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py)
+{
+
+ double wpy = px * d->dc[d->level].worldTransform.eM12 + py * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy;
+ double y = _pix_y_to_point(d, wpy);
+
+ return y;
+
+}
+
+double
+Emf::pix_to_abs_size(PEMF_CALLBACK_DATA d, double px)
+{
+ double ppx = fabs(px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0) * d->D2PscaleX * current_scale(d));
+ return ppx;
+}
+
+/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates
+*/
+std::string Emf::pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y){
+ std::stringstream cxform;
+ cxform << pix_to_x_point(d,x,y);
+ cxform << ",";
+ cxform << pix_to_y_point(d,x,y);
+ return(cxform.str());
+}
+
+
+void
+Emf::select_pen(PEMF_CALLBACK_DATA d, int index)
+{
+ PU_EMRCREATEPEN pEmr = NULL;
+
+ if (index >= 0 && index < d->n_obj){
+ pEmr = (PU_EMRCREATEPEN) d->emf_obj[index].lpEMFR;
+ }
+
+ if (!pEmr){ return; }
+
+ switch (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK) {
+ case U_PS_DASH:
+ case U_PS_DOT:
+ case U_PS_DASHDOT:
+ case U_PS_DASHDOTDOT:
+ {
+ int penstyle = (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK);
+ if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values)))
+ d->dc[d->level].style.stroke_dasharray.values.clear();
+ if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 3 );
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ }
+ if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ }
+ if (penstyle==U_PS_DASHDOTDOT) {
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ }
+
+ d->dc[d->level].style.stroke_dasharray.set = 1;
+ break;
+ }
+
+ case U_PS_SOLID:
+ default:
+ {
+ d->dc[d->level].style.stroke_dasharray.set = 0;
+ break;
+ }
+ }
+
+ switch (pEmr->lopn.lopnStyle & U_PS_ENDCAP_MASK) {
+ case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = 1; break; }
+ case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = 2; break; }
+ case U_PS_ENDCAP_FLAT:
+ default: { d->dc[d->level].style.stroke_linecap.computed = 0; break; }
+ }
+
+ switch (pEmr->lopn.lopnStyle & U_PS_JOIN_MASK) {
+ case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = 2; break; }
+ case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = 0; break; }
+ case U_PS_JOIN_ROUND:
+ default: { d->dc[d->level].style.stroke_linejoin.computed = 1; break; }
+ }
+
+ d->dc[d->level].stroke_set = true;
+
+ if (pEmr->lopn.lopnStyle == U_PS_NULL) {
+ d->dc[d->level].style.stroke_width.value = 0;
+ d->dc[d->level].stroke_set = false;
+ } else if (pEmr->lopn.lopnWidth.x) {
+ int cur_level = d->level;
+ d->level = d->emf_obj[index].level;
+ double pen_width = pix_to_abs_size( d, pEmr->lopn.lopnWidth.x );
+ d->level = cur_level;
+ d->dc[d->level].style.stroke_width.value = pen_width;
+ } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
+ //d->dc[d->level].style.stroke_width.value = 1.0;
+ int cur_level = d->level;
+ d->level = d->emf_obj[index].level;
+ double pen_width = pix_to_abs_size( d, 1 );
+ d->level = cur_level;
+ d->dc[d->level].style.stroke_width.value = pen_width;
+ }
+
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lopn.lopnColor) );
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lopn.lopnColor) );
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lopn.lopnColor) );
+ d->dc[d->level].style.stroke.value.color.set( r, g, b );
+}
+
+
+void
+Emf::select_extpen(PEMF_CALLBACK_DATA d, int index)
+{
+ PU_EMREXTCREATEPEN pEmr = NULL;
+
+ if (index >= 0 && index < d->n_obj)
+ pEmr = (PU_EMREXTCREATEPEN) d->emf_obj[index].lpEMFR;
+
+ if (!pEmr)
+ return;
+
+ switch (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK) {
+ case U_PS_USERSTYLE:
+ {
+ if (pEmr->elp.elpNumEntries) {
+ if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values)))
+ d->dc[d->level].style.stroke_dasharray.values.clear();
+ for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
+ int cur_level = d->level;
+ d->level = d->emf_obj[index].level;
+// Doing it this way typically results in a pattern that is tiny, better to assume the array
+// is the same scale as for dot/dash below, that is, no scaling should be applied
+// double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] );
+ double dash_length = pEmr->elp.elpStyleEntry[i];
+ d->level = cur_level;
+ d->dc[d->level].style.stroke_dasharray.values[i] = dash_length;
+ }
+ d->dc[d->level].style.stroke_dasharray.set = 1;
+ } else {
+ d->dc[d->level].style.stroke_dasharray.set = 0;
+ }
+ break;
+ }
+
+ case U_PS_DASH:
+ case U_PS_DOT:
+ case U_PS_DASHDOT:
+ case U_PS_DASHDOTDOT:
+ {
+ int penstyle = (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK);
+ if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values)))
+ d->dc[d->level].style.stroke_dasharray.values.clear();
+ if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 3 );
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 2 );
+ }
+ if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 2 );
+ }
+ if (penstyle==U_PS_DASHDOTDOT) {
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 2 );
+ }
+
+ d->dc[d->level].style.stroke_dasharray.set = 1;
+ break;
+ }
+ case U_PS_SOLID:
+/* includes these for now, some should maybe not be in here
+ case U_PS_NULL:
+ case U_PS_INSIDEFRAME:
+ case U_PS_ALTERNATE:
+ case U_PS_STYLE_MASK:
+*/
+ default:
+ {
+ d->dc[d->level].style.stroke_dasharray.set = 0;
+ break;
+ }
+ }
+
+ switch (pEmr->elp.elpPenStyle & U_PS_ENDCAP_MASK) {
+ case U_PS_ENDCAP_ROUND:
+ {
+ d->dc[d->level].style.stroke_linecap.computed = 1;
+ break;
+ }
+ case U_PS_ENDCAP_SQUARE:
+ {
+ d->dc[d->level].style.stroke_linecap.computed = 2;
+ break;
+ }
+ case U_PS_ENDCAP_FLAT:
+ default:
+ {
+ d->dc[d->level].style.stroke_linecap.computed = 0;
+ break;
+ }
+ }
+
+ switch (pEmr->elp.elpPenStyle & U_PS_JOIN_MASK) {
+ case U_PS_JOIN_BEVEL:
+ {
+ d->dc[d->level].style.stroke_linejoin.computed = 2;
+ break;
+ }
+ case U_PS_JOIN_MITER:
+ {
+ d->dc[d->level].style.stroke_linejoin.computed = 0;
+ break;
+ }
+ case U_PS_JOIN_ROUND:
+ default:
+ {
+ d->dc[d->level].style.stroke_linejoin.computed = 1;
+ break;
+ }
+ }
+
+ d->dc[d->level].stroke_set = true;
+
+ if (pEmr->elp.elpPenStyle == U_PS_NULL) { // draw nothing, but fill out all the values with something
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
+ d->dc[d->level].style.stroke.value.color.set( r, g, b );
+ d->dc[d->level].style.stroke_width.value = 0;
+ d->dc[d->level].stroke_set = false;
+ d->dc[d->level].stroke_mode = DRAW_PAINT;
+ }
+ else {
+ if (pEmr->elp.elpWidth) {
+ int cur_level = d->level;
+ d->level = d->emf_obj[index].level;
+ double pen_width = pix_to_abs_size( d, pEmr->elp.elpWidth );
+ d->level = cur_level;
+ d->dc[d->level].style.stroke_width.value = pen_width;
+ } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
+ //d->dc[d->level].style.stroke_width.value = 1.0;
+ int cur_level = d->level;
+ d->level = d->emf_obj[index].level;
+ double pen_width = pix_to_abs_size( d, 1 );
+ d->level = cur_level;
+ d->dc[d->level].style.stroke_width.value = pen_width;
+ }
+
+ if( pEmr->elp.elpBrushStyle == U_BS_SOLID){
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->elp.elpColor) );
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->elp.elpColor) );
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->elp.elpColor) );
+ d->dc[d->level].style.stroke.value.color.set( r, g, b );
+ d->dc[d->level].stroke_mode = DRAW_PAINT;
+ d->dc[d->level].stroke_set = true;
+ }
+ else if(pEmr->elp.elpBrushStyle == U_BS_HATCHED){
+ d->dc[d->level].stroke_idx = add_hatch(d, pEmr->elp.elpHatch, pEmr->elp.elpColor);
+ d->dc[d->level].stroke_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
+ d->dc[d->level].stroke_mode = DRAW_PATTERN;
+ d->dc[d->level].stroke_set = true;
+ }
+ else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT){
+ d->dc[d->level].stroke_idx = add_image(d, pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi);
+ d->dc[d->level].stroke_mode = DRAW_IMAGE;
+ d->dc[d->level].stroke_set = true;
+ }
+ else { // U_BS_PATTERN and anything strange that falls in, stroke is solid textColor
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
+ d->dc[d->level].style.stroke.value.color.set( r, g, b );
+ d->dc[d->level].stroke_mode = DRAW_PAINT;
+ d->dc[d->level].stroke_set = true;
+ }
+ }
+}
+
+
+void
+Emf::select_brush(PEMF_CALLBACK_DATA d, int index)
+{
+ uint32_t tidx;
+ uint32_t iType;
+
+ if (index >= 0 && index < d->n_obj){
+ iType = ((PU_EMR) (d->emf_obj[index].lpEMFR))->iType;
+ if(iType == U_EMR_CREATEBRUSHINDIRECT){
+ PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;
+ if( pEmr->lb.lbStyle == U_BS_SOLID){
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lb.lbColor) );
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lb.lbColor) );
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lb.lbColor) );
+ d->dc[d->level].style.fill.value.color.set( r, g, b );
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ d->dc[d->level].fill_set = true;
+ }
+ else if(pEmr->lb.lbStyle == U_BS_HATCHED){
+ d->dc[d->level].fill_idx = add_hatch(d, pEmr->lb.lbHatch, pEmr->lb.lbColor);
+ d->dc[d->level].fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
+ d->dc[d->level].fill_mode = DRAW_PATTERN;
+ d->dc[d->level].fill_set = true;
+ }
+ }
+ else if(iType == U_EMR_CREATEDIBPATTERNBRUSHPT || iType == U_EMR_CREATEMONOBRUSH){
+ PU_EMRCREATEDIBPATTERNBRUSHPT pEmr = (PU_EMRCREATEDIBPATTERNBRUSHPT) d->emf_obj[index].lpEMFR;
+ tidx = add_image(d, (void *) pEmr, pEmr->cbBits, pEmr->cbBmi, pEmr->iUsage, pEmr->offBits, pEmr->offBmi);
+ if(tidx == U_EMR_INVALID){ // This happens if createmonobrush has a DIB that isn't monochrome
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
+ d->dc[d->level].style.fill.value.color.set( r, g, b );
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ }
+ else {
+ d->dc[d->level].fill_idx = tidx;
+ d->dc[d->level].fill_mode = DRAW_IMAGE;
+ }
+ d->dc[d->level].fill_set = true;
+ }
+ }
+}
+
+
+void
+Emf::select_font(PEMF_CALLBACK_DATA d, int index)
+{
+ PU_EMREXTCREATEFONTINDIRECTW pEmr = NULL;
+
+ if (index >= 0 && index < d->n_obj)
+ pEmr = (PU_EMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR;
+
+ if (!pEmr)return;
+
+
+ /* The logfont information always starts with a U_LOGFONT structure but the U_EMREXTCREATEFONTINDIRECTW
+ is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont
+ is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored
+ */
+ int cur_level = d->level;
+ d->level = d->emf_obj[index].level;
+ double font_size = pix_to_abs_size( d, pEmr->elfw.elfLogFont.lfHeight );
+ /* snap the font_size to the nearest 1/32nd of a point.
+ (The size is converted from Pixels to points, snapped, and converted back.)
+ See the notes where d->D2Pscale[XY] are set for the reason why.
+ Typically this will set the font to the desired exact size. If some peculiar size
+ was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */
+ font_size = round(20.0 * 0.8 * font_size)/(20.0 * 0.8);
+ d->level = cur_level;
+ d->dc[d->level].style.font_size.computed = font_size;
+ d->dc[d->level].style.font_weight.value =
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER :
+ pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER :
+ U_FW_NORMAL;
+ d->dc[d->level].style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL);
+ d->dc[d->level].style.text_decoration_line.underline = pEmr->elfw.elfLogFont.lfUnderline;
+ d->dc[d->level].style.text_decoration_line.line_through = pEmr->elfw.elfLogFont.lfStrikeOut;
+ d->dc[d->level].style.text_decoration_line.set = true;
+ d->dc[d->level].style.text_decoration_line.inherit = false;
+ // malformed EMF with empty filename may exist, ignore font change if encountered
+ char *ctmp = U_Utf16leToUtf8((uint16_t *) (pEmr->elfw.elfLogFont.lfFaceName), U_LF_FACESIZE, NULL);
+ if(ctmp){
+ if (d->dc[d->level].font_name){ free(d->dc[d->level].font_name); }
+ if(*ctmp){
+ d->dc[d->level].font_name = ctmp;
+ }
+ else { // Malformed EMF might specify an empty font name
+ free(ctmp);
+ d->dc[d->level].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants
+ }
+ }
+ d->dc[d->level].style.baseline_shift.value = round((double)((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600)) / 10.0; // use baseline_shift instead of text_transform to avoid overflow
+}
+
+void
+Emf::delete_object(PEMF_CALLBACK_DATA d, int index)
+{
+ if (index >= 0 && index < d->n_obj) {
+ d->emf_obj[index].type = 0;
+// We are keeping a copy of the EMR rather than just a structure. Currently that is not necessary as the entire
+// EMF is read in at once and is stored in a big malloc. However, in past versions it was handled
+// reord by record, and we might need to do that again at some point in the future if we start running into EMF
+// files too big to fit into memory.
+ if (d->emf_obj[index].lpEMFR)
+ free(d->emf_obj[index].lpEMFR);
+ d->emf_obj[index].lpEMFR = NULL;
+ }
+}
+
+
+void
+Emf::insert_object(PEMF_CALLBACK_DATA d, int index, int type, PU_ENHMETARECORD pObj)
+{
+ if (index >= 0 && index < d->n_obj) {
+ delete_object(d, index);
+ d->emf_obj[index].type = type;
+ d->emf_obj[index].level = d->level;
+ d->emf_obj[index].lpEMFR = emr_dup((char *) pObj);
+ }
+}
+
+/* Identify probable Adobe Illustrator produced EMF files, which do strange things with the scaling.
+ The few so far observed all had this format.
+*/
+int Emf::AI_hack(PU_EMRHEADER pEmr){
+ int ret=0;
+ char *ptr;
+ ptr = (char *)pEmr;
+ PU_EMRSETMAPMODE nEmr = (PU_EMRSETMAPMODE) (ptr + pEmr->emr.nSize);
+ char *string = NULL;
+ if(pEmr->nDescription)string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, NULL);
+ if(string){
+ if((pEmr->nDescription >= 13) &&
+ (0==strcmp("Adobe Systems",string)) &&
+ (nEmr->emr.iType == U_EMR_SETMAPMODE) &&
+ (nEmr->iMode == U_MM_ANISOTROPIC)){ ret=1; }
+ free(string);
+ }
+ return(ret);
+}
+
+/**
+ \fn create a UTF-32LE buffer and fill it with UNICODE unknown character
+ \param count number of copies of the Unicode unknown character to fill with
+*/
+uint32_t *Emf::unknown_chars(size_t count){
+ uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1));
+ if(!res)throw "Inkscape fatal memory allocation error - cannot continue";
+ for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; }
+ res[count]=0;
+ return res;
+}
+
+/**
+ \fn store SVG for an image given the pixmap and various coordinate information
+ \param d
+ \param pEmr
+ \param dx (double) destination x in inkscape pixels
+ \param dy (double) destination y in inkscape pixels
+ \param dw (double) destination width in inkscape pixels
+ \param dh (double) destination height in inkscape pixels
+ \param sx (int) source x in src image pixels
+ \param sy (int) source y in src image pixels
+ \param iUsage
+ \param offBits
+ \param cbBits
+ \param offBmi
+ \param cbBmi
+*/
+void Emf::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr,
+ double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh,
+ uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi){
+
+ SVGOStringStream tmp_image;
+ int dibparams = U_BI_UNKNOWN; // type of image not yet determined
+
+ tmp_image << "\n\t <image\n";
+ tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ char *sub_px = NULL; // RGBA pixels, subarray
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // DIB color table
+ uint32_t width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params
+ if(cbBits && cbBmi && (iUsage == U_DIB_RGB_COLORS)){
+ // next call returns pointers and values, but allocates no memory
+ dibparams = get_DIB_params(pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct,
+ &numCt, &width, &height, &colortype, &invert);
+ if(dibparams ==U_BI_RGB){
+ if(sw == 0 || sh == 0){
+ sw = width;
+ sh = height;
+ }
+
+ if(!DIB_to_RGBA(
+ px, // DIB pixel array
+ ct, // DIB color table
+ numCt, // DIB color table number of entries
+ &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ width, // Width of pixel array
+ height, // Height of pixel array
+ colortype, // DIB BitCount Enumeration
+ numCt, // Color table used if not 0
+ invert // If DIB rows are in opposite order from RGBA rows
+ )){
+ sub_px = RGBA_to_RGBA( // returns either a subset (side effect: frees rgba_px) or NULL (for subset == entire image)
+ rgba_px, // full pixel array from DIB
+ width, // Width of pixel array
+ height, // Height of pixel array
+ sx,sy, // starting point in pixel array
+ &sw,&sh // columns/rows to extract from the pixel array (output array size)
+ );
+
+ if(!sub_px)sub_px=rgba_px;
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ sw, sh, // size of the extracted pixel array
+ sub_px
+ );
+ free(sub_px);
+ }
+ }
+ }
+
+ gchar *base64String=NULL;
+ if(dibparams == U_BI_JPEG){ // image was binary jpg in source file
+ tmp_image << " xlink:href=\"data:image/jpeg;base64,";
+ base64String = g_base64_encode((guchar*) px, numCt );
+ }
+ else if(dibparams==U_BI_PNG){ // image was binary png in source file
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ base64String = g_base64_encode((guchar*) px, numCt );
+ }
+ else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ }
+ else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ base64String = bad_image_png();
+ }
+ tmp_image << base64String;
+ g_free(base64String);
+
+ tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
+
+ tmp_image << " transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset
+ tmp_image << " preserveAspectRatio=\"none\"\n";
+ tmp_image << "/> \n";
+
+ *(d->outsvg) += tmp_image.str().c_str();
+ *(d->path) = "";
+}
+
+/**
+ \fn myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA lpData)
+ \param contents binary contents of an EMF file
+ \param length length in bytes of contents
+ \param d Inkscape data structures returned by this call
+*/
+//THis was a callback, just build it into a normal function
+int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d)
+{
+ uint32_t off=0;
+ uint32_t emr_mask;
+ int OK =1;
+ PU_ENHMETARECORD lpEMFR;
+ TCHUNK_SPECS tsp;
+ uint32_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written
+ U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
+
+ /* initialize the tsp for text reassembly */
+ tsp.string = NULL;
+ tsp.ori = 0.0; /* degrees */
+ tsp.fs = 12.0; /* font size */
+ tsp.x = 0.0;
+ tsp.y = 0.0;
+ tsp.boff = 0.0; /* offset to baseline from LL corner of bounding rectangle, changes with fs and taln*/
+ tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */
+ tsp.taln = ALILEFT + ALIBASE;
+ tsp.ldir = LDIR_LR;
+ tsp.spaces = 0; // this field is only used for debugging
+ tsp.color.Red = 0; /* RGB Black */
+ tsp.color.Green = 0; /* RGB Black */
+ tsp.color.Blue = 0; /* RGB Black */
+ tsp.color.Reserved = 0; /* not used */
+ tsp.italics = 0;
+ tsp.weight = 80;
+ tsp.decoration = TXTDECOR_NONE;
+ tsp.condensed = 100;
+ tsp.co = 0;
+ tsp.fi_idx = -1; /* set to an invalid */
+
+ while(OK){
+ if(off>=length)return(0); //normally should exit from while after EMREOF sets OK to false.
+
+ lpEMFR = (PU_ENHMETARECORD)(contents + off);
+// Uncomment the following to track down toxic records
+//std::cout << "record type: " << lpEMFR->iType << " length: " << lpEMFR->nSize << " offset: " << off <<std::endl;
+ off += lpEMFR->nSize;
+
+ SVGOStringStream tmp_outsvg;
+ SVGOStringStream tmp_path;
+ SVGOStringStream tmp_str;
+ SVGOStringStream dbg_str;
+
+ emr_mask = emr_properties(lpEMFR->iType);
+ if(emr_mask == U_EMR_INVALID){ throw "Inkscape fatal memory allocation error - cannot continue"; }
+
+/* Uncomment the following to track down text problems */
+//std::cout << "tri->dirty:"<< d->tri->dirty << " emr_mask: " << std::hex << emr_mask << std::dec << std::endl;
+
+ // incompatible change to text drawing detected (color or background change) forces out existing text
+ // OR
+ // next record is valid type and forces pending text to be drawn immediately
+ if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((emr_mask != U_EMR_INVALID) && (emr_mask & U_DRAW_TEXT) && d->tri->dirty)){
+ TR_layout_analyze(d->tri);
+ TR_layout_2_svg(d->tri);
+ SVGOStringStream ts;
+ ts << d->tri->out;
+ *(d->outsvg) += ts.str().c_str();
+ d->tri = trinfo_clear(d->tri);
+ }
+ if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag
+ d->dc[d->level].bkMode = tbkMode;
+ memcpy(&(d->dc[d->level].bkColor),&tbkColor, sizeof(U_COLORREF));
+
+ if(d->dc[d->level].dirty & DIRTY_TEXT){
+ // U_COLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing...
+ if(tbkMode == U_TRANSPARENT){ (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); }
+ else { (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); } // Opaque
+ }
+
+ /* It is possible to have a series of EMF records that would result in
+ the following creating hash patterns which are never used. For instance, if
+ there were a series of records that changed the background color but did nothing
+ else.
+ */
+ if((d->dc[d->level].stroke_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_STROKE)){
+ select_extpen(d, d->dc[d->level].stroke_recidx);
+ }
+
+ if((d->dc[d->level].fill_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_FILL)){
+ select_brush(d, d->dc[d->level].fill_recidx);
+ }
+
+ d->dc[d->level].dirty = 0;
+ }
+
+//std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl;
+/*
+std::cout << "BEFORE DRAW"
+ << " test0 " << ( d->mask & U_DRAW_VISIBLE)
+ << " test1 " << ( d->mask & U_DRAW_FORCE)
+ << " test2 " << (emr_mask & U_DRAW_ALTERS)
+ << " test3 " << (emr_mask & U_DRAW_VISIBLE)
+ << " test4 " << !(d->mask & U_DRAW_ONLYTO)
+ << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) )
+ << std::endl;
+*/
+
+ if(
+ (emr_mask != U_EMR_INVALID) && // next record is valid type
+ (d->mask & U_DRAW_VISIBLE) && // Current set of objects are drawable
+ (
+ (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH
+ (emr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way
+ (
+ (emr_mask & U_DRAW_VISIBLE) && // Next record is visible...
+ (
+ ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible
+ ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) )// *TO records can only be followed by other *TO records
+ )
+ )
+ )
+ ){
+// std::cout << "PATH DRAW at TOP" << std::endl;
+ *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!! One exception, gradientfill.
+ if(d->drawtype){ // explicit draw type EMR record
+ output_style(d, d->drawtype);
+ }
+ else if(d->mask & U_DRAW_CLOSED){ // implicit draw type
+ output_style(d, U_EMR_STROKEANDFILLPATH);
+ }
+ else {
+ output_style(d, U_EMR_STROKEPATH);
+ }
+ *(d->outsvg) += "\n\t";
+ *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!! One exception, gradientfill.
+ *(d->outsvg) += *(d->path);
+ *(d->outsvg) += " \" /> \n";
+ *(d->path) = "";
+ // reset the flags
+ d->mask = 0;
+ d->drawtype = 0;
+ }
+// std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl;
+
+ switch (lpEMFR->iType)
+ {
+ case U_EMR_HEADER:
+ {
+ dbg_str << "<!-- U_EMR_HEADER -->\n";
+
+ *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
+
+ if (d->pDesc) {
+ *(d->outdef) += "<!-- ";
+ *(d->outdef) += d->pDesc;
+ *(d->outdef) += " -->\n";
+ }
+
+ PU_EMRHEADER pEmr = (PU_EMRHEADER) lpEMFR;
+ SVGOStringStream tmp_outdef;
+ tmp_outdef << "<svg\n";
+ tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
+ tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n";
+ tmp_outdef << " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n";
+ tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role
+ tmp_outdef << " version=\"1.0\"\n";
+
+
+ /* inclusive-inclusive, so the size is 1 more than the difference */
+ d->MM100InX = pEmr->rclFrame.right - pEmr->rclFrame.left + 1;
+ d->MM100InY = pEmr->rclFrame.bottom - pEmr->rclFrame.top + 1;
+ d->PixelsInX = pEmr->rclBounds.right - pEmr->rclBounds.left + 1;
+ d->PixelsInY = pEmr->rclBounds.bottom - pEmr->rclBounds.top + 1;
+
+ /*
+ calculate ratio of Inkscape dpi/EMF device dpi
+ This can cause problems later due to accuracy limits in the EMF. A high resolution
+ EMF might have a final D2Pscale[XY] of 0.074998, and adjusting the (integer) device size
+ by 1 will still not get it exactly to 0.075. Later when the font size is calculated it
+ can end up as 29.9992 or 22.4994 instead of the intended 30 or 22.5. This is handled by
+ snapping font sizes to the nearest .01. The best estimate is made by using both values.
+ */
+ if ((pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy) && ( pEmr->szlDevice.cx + pEmr->szlDevice.cy)){
+ d->E2IdirY = 1.0; // assume MM_TEXT, if not, this will be changed later
+ d->D2PscaleX = d->D2PscaleY = Inkscape::Util::Quantity::convert(1, "mm", "px") *
+ (double)(pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy)/
+ (double)( pEmr->szlDevice.cx + pEmr->szlDevice.cy);
+ }
+ trinfo_load_qe(d->tri, d->D2PscaleX); /* quantization error that will affect text positions */
+
+ /* Adobe Illustrator files set mapmode to MM_ANISOTROPIC and somehow or other this
+ converts the rclFrame values from MM_HIMETRIC to MM_HIENGLISH, with another factor of 3 thrown
+ in for good measure. Ours not to question why...
+ */
+ if(AI_hack(pEmr)){
+ d->MM100InX *= 25.4/(10.0*3.0);
+ d->MM100InY *= 25.4/(10.0*3.0);
+ d->D2PscaleX *= 25.4/(10.0*3.0);
+ d->D2PscaleY *= 25.4/(10.0*3.0);
+ }
+
+ d->MMX = d->MM100InX / 100.0;
+ d->MMY = d->MM100InY / 100.0;
+
+ d->PixelsOutX = Inkscape::Util::Quantity::convert(d->MMX, "mm", "px");
+ d->PixelsOutY = Inkscape::Util::Quantity::convert(d->MMY, "mm", "px");
+
+ // Upper left corner, from header rclBounds, in device units, usually both 0, but not always
+ d->ulCornerInX = pEmr->rclBounds.left;
+ d->ulCornerInY = pEmr->rclBounds.top;
+ d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX;
+ d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY;
+
+ tmp_outdef <<
+ " width=\"" << d->MMX << "mm\"\n" <<
+ " height=\"" << d->MMY << "mm\">\n";
+ *(d->outdef) += tmp_outdef.str().c_str();
+ *(d->outdef) += "<defs>"; // temporary end of header
+
+ // d->defs holds any defines which are read in.
+
+ tmp_outsvg << "\n</defs>\n\n"; // start of main body
+
+ if (pEmr->nHandles) {
+ d->n_obj = pEmr->nHandles;
+ d->emf_obj = new EMF_OBJECT[d->n_obj];
+
+ // Init the new emf_obj list elements to null, provided the
+ // dynamic allocation succeeded.
+ if ( d->emf_obj != NULL )
+ {
+ for( int i=0; i < d->n_obj; ++i )
+ d->emf_obj[i].lpEMFR = NULL;
+ } //if
+
+ } else {
+ d->emf_obj = NULL;
+ }
+
+ break;
+ }
+ case U_EMR_POLYBEZIER:
+ {
+ dbg_str << "<!-- U_EMR_POLYBEZIER -->\n";
+
+ PU_EMRPOLYBEZIER pEmr = (PU_EMRPOLYBEZIER) lpEMFR;
+ uint32_t i,j;
+
+ if (pEmr->cptl<4)
+ break;
+
+ d->mask |= emr_mask;
+
+ tmp_str <<
+ "\n\tM " <<
+ pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " ";
+
+ for (i=1; i<pEmr->cptl; ) {
+ tmp_str << "\n\tC ";
+ for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
+ tmp_str << pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y) << " ";
+ }
+ }
+
+ tmp_path << tmp_str.str().c_str();
+
+ break;
+ }
+ case U_EMR_POLYGON:
+ {
+ dbg_str << "<!-- U_EMR_POLYGON -->\n";
+
+ PU_EMRPOLYGON pEmr = (PU_EMRPOLYGON) lpEMFR;
+ uint32_t i;
+
+ if (pEmr->cptl < 2)
+ break;
+
+ d->mask |= emr_mask;
+
+ tmp_str <<
+ "\n\tM " <<
+ pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
+
+ for (i=1; i<pEmr->cptl; i++) {
+ tmp_str <<
+ "\n\tL " <<
+ pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
+ }
+
+ tmp_path << tmp_str.str().c_str();
+ tmp_path << " z";
+
+ break;
+ }
+ case U_EMR_POLYLINE:
+ {
+ dbg_str << "<!-- U_EMR_POLYLINE -->\n";
+
+ PU_EMRPOLYLINE pEmr = (PU_EMRPOLYLINE) lpEMFR;
+ uint32_t i;
+
+ if (pEmr->cptl<2)
+ break;
+
+ d->mask |= emr_mask;
+
+ tmp_str <<
+ "\n\tM " <<
+ pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
+
+ for (i=1; i<pEmr->cptl; i++) {
+ tmp_str <<
+ "\n\tL " <<
+ pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
+ }
+
+ tmp_path << tmp_str.str().c_str();
+
+ break;
+ }
+ case U_EMR_POLYBEZIERTO:
+ {
+ dbg_str << "<!-- U_EMR_POLYBEZIERTO -->\n";
+
+ PU_EMRPOLYBEZIERTO pEmr = (PU_EMRPOLYBEZIERTO) lpEMFR;
+ uint32_t i,j;
+
+ d->mask |= emr_mask;
+
+ for (i=0; i<pEmr->cptl;) {
+ tmp_path << "\n\tC ";
+ for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
+ tmp_path <<
+ pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
+ }
+ }
+
+ break;
+ }
+ case U_EMR_POLYLINETO:
+ {
+ dbg_str << "<!-- U_EMR_POLYLINETO -->\n";
+
+ PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) lpEMFR;
+ uint32_t i;
+
+ d->mask |= emr_mask;
+
+ for (i=0; i<pEmr->cptl;i++) {
+ tmp_path <<
+ "\n\tL " <<
+ pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
+ }
+
+ break;
+ }
+ case U_EMR_POLYPOLYLINE:
+ case U_EMR_POLYPOLYGON:
+ {
+ if (lpEMFR->iType == U_EMR_POLYPOLYLINE)
+ dbg_str << "<!-- U_EMR_POLYPOLYLINE -->\n";
+ if (lpEMFR->iType == U_EMR_POLYPOLYGON)
+ dbg_str << "<!-- U_EMR_POLYPOLYGON -->\n";
+
+ PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) lpEMFR;
+ unsigned int n, i, j;
+
+ d->mask |= emr_mask;
+
+ U_POINTL *aptl = (PU_POINTL) &pEmr->aPolyCounts[pEmr->nPolys];
+
+ i = 0;
+ for (n=0; n<pEmr->nPolys && i<pEmr->cptl; n++) {
+ SVGOStringStream poly_path;
+
+ poly_path << "\n\tM " << pix_to_xy( d, aptl[i].x, aptl[i].y) << " ";
+ i++;
+
+ for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cptl; j++) {
+ poly_path << "\n\tL " << pix_to_xy( d, aptl[i].x, aptl[i].y) << " ";
+ i++;
+ }
+
+ tmp_str << poly_path.str().c_str();
+ if (lpEMFR->iType == U_EMR_POLYPOLYGON)
+ tmp_str << " z";
+ tmp_str << " \n";
+ }
+
+ tmp_path << tmp_str.str().c_str();
+
+ break;
+ }
+ case U_EMR_SETWINDOWEXTEX:
+ {
+ dbg_str << "<!-- U_EMR_SETWINDOWEXTEX -->\n";
+
+ PU_EMRSETWINDOWEXTEX pEmr = (PU_EMRSETWINDOWEXTEX) lpEMFR;
+
+ d->dc[d->level].sizeWnd = pEmr->szlExtent;
+
+ if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
+ d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
+ if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
+ d->dc[d->level].sizeWnd.cx = d->PixelsOutX;
+ d->dc[d->level].sizeWnd.cy = d->PixelsOutY;
+ }
+ }
+
+ if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
+ d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
+ }
+
+ /* scales logical to EMF pixels, transfer a negative sign on Y, if any */
+ if (d->dc[d->level].sizeWnd.cx && d->dc[d->level].sizeWnd.cy) {
+ d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx;
+ d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy;
+ if(d->dc[d->level].ScaleInY < 0){
+ d->dc[d->level].ScaleInY *= -1.0;
+ d->E2IdirY = -1.0;
+ }
+ }
+ else {
+ d->dc[d->level].ScaleInX = 1;
+ d->dc[d->level].ScaleInY = 1;
+ }
+ break;
+ }
+ case U_EMR_SETWINDOWORGEX:
+ {
+ dbg_str << "<!-- U_EMR_SETWINDOWORGEX -->\n";
+
+ PU_EMRSETWINDOWORGEX pEmr = (PU_EMRSETWINDOWORGEX) lpEMFR;
+ d->dc[d->level].winorg = pEmr->ptlOrigin;
+ break;
+ }
+ case U_EMR_SETVIEWPORTEXTEX:
+ {
+ dbg_str << "<!-- U_EMR_SETVIEWPORTEXTEX -->\n";
+
+ PU_EMRSETVIEWPORTEXTEX pEmr = (PU_EMRSETVIEWPORTEXTEX) lpEMFR;
+
+ d->dc[d->level].sizeView = pEmr->szlExtent;
+
+ if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
+ d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
+ if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
+ d->dc[d->level].sizeView.cx = d->PixelsOutX;
+ d->dc[d->level].sizeView.cy = d->PixelsOutY;
+ }
+ }
+
+ if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
+ d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
+ }
+
+ /* scales logical to EMF pixels, transfer a negative sign on Y, if any */
+ if (d->dc[d->level].sizeWnd.cx && d->dc[d->level].sizeWnd.cy) {
+ d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx;
+ d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy;
+ if( d->dc[d->level].ScaleInY < 0){
+ d->dc[d->level].ScaleInY *= -1.0;
+ d->E2IdirY = -1.0;
+ }
+ }
+ else {
+ d->dc[d->level].ScaleInX = 1;
+ d->dc[d->level].ScaleInY = 1;
+ }
+ break;
+ }
+ case U_EMR_SETVIEWPORTORGEX:
+ {
+ dbg_str << "<!-- U_EMR_SETVIEWPORTORGEX -->\n";
+
+ PU_EMRSETVIEWPORTORGEX pEmr = (PU_EMRSETVIEWPORTORGEX) lpEMFR;
+ d->dc[d->level].vieworg = pEmr->ptlOrigin;
+ break;
+ }
+ case U_EMR_SETBRUSHORGEX: dbg_str << "<!-- U_EMR_SETBRUSHORGEX -->\n"; break;
+ case U_EMR_EOF:
+ {
+ dbg_str << "<!-- U_EMR_EOF -->\n";
+
+ tmp_outsvg << "</svg>\n";
+ *(d->outsvg) = *(d->outdef) + *(d->defs) + *(d->outsvg);
+ OK=0;
+ break;
+ }
+ case U_EMR_SETPIXELV: dbg_str << "<!-- U_EMR_SETPIXELV -->\n"; break;
+ case U_EMR_SETMAPPERFLAGS: dbg_str << "<!-- U_EMR_SETMAPPERFLAGS -->\n"; break;
+ case U_EMR_SETMAPMODE:
+ {
+ dbg_str << "<!-- U_EMR_SETMAPMODE -->\n";
+ PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE) lpEMFR;
+ switch (pEmr->iMode){
+ case U_MM_TEXT:
+ default:
+ // Use all values from the header.
+ break;
+ /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex
+ and show up in ScaleIn[XY]
+ */
+ case U_MM_LOMETRIC: // 1 LU = 0.1 mm,
+ case U_MM_HIMETRIC: // 1 LU = 0.01 mm
+ case U_MM_LOENGLISH: // 1 LU = 0.1 in
+ case U_MM_HIENGLISH: // 1 LU = 0.01 in
+ case U_MM_TWIPS: // 1 LU = 1/1440 in
+ d->E2IdirY = -1.0;
+ // Use d->D2Pscale[XY] values from the header.
+ break;
+ case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX
+ case U_MM_ANISOTROPIC:
+ break;
+ }
+ break;
+ }
+ case U_EMR_SETBKMODE:
+ {
+ dbg_str << "<!-- U_EMR_SETBKMODE -->\n";
+ PU_EMRSETBKMODE pEmr = (PU_EMRSETBKMODE) lpEMFR;
+ tbkMode = pEmr->iMode;
+ if(tbkMode != d->dc[d->level].bkMode){
+ d->dc[d->level].dirty |= DIRTY_TEXT;
+ if(tbkMode != d->dc[d->level].bkMode){
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; }
+ }
+ memcpy(&tbkColor,&(d->dc[d->level].bkColor),sizeof(U_COLORREF));
+ }
+ break;
+ }
+ case U_EMR_SETPOLYFILLMODE:
+ {
+ dbg_str << "<!-- U_EMR_SETPOLYFILLMODE -->\n";
+
+ PU_EMRSETPOLYFILLMODE pEmr = (PU_EMRSETPOLYFILLMODE) lpEMFR;
+ d->dc[d->level].style.fill_rule.value =
+ (pEmr->iMode == U_ALTERNATE ? 0 : (pEmr->iMode == U_WINDING ? 1 : 0));
+ break;
+ }
+ case U_EMR_SETROP2:
+ {
+ dbg_str << "<!-- U_EMR_SETROP2 -->\n";
+ PU_EMRSETROP2 pEmr = (PU_EMRSETROP2) lpEMFR;
+ d->dwRop2 = pEmr->iMode;
+ break;
+ }
+ case U_EMR_SETSTRETCHBLTMODE:
+ {
+ PU_EMRSETSTRETCHBLTMODE pEmr = (PU_EMRSETSTRETCHBLTMODE) lpEMFR; // from wingdi.h
+ BLTmode = pEmr->iMode;
+ dbg_str << "<!-- U_EMR_SETSTRETCHBLTMODE -->\n";
+ break;
+ }
+ case U_EMR_SETTEXTALIGN:
+ {
+ dbg_str << "<!-- U_EMR_SETTEXTALIGN -->\n";
+
+ PU_EMRSETTEXTALIGN pEmr = (PU_EMRSETTEXTALIGN) lpEMFR;
+ d->dc[d->level].textAlign = pEmr->iMode;
+ break;
+ }
+ case U_EMR_SETCOLORADJUSTMENT:
+ dbg_str << "<!-- U_EMR_SETCOLORADJUSTMENT -->\n";
+ break;
+ case U_EMR_SETTEXTCOLOR:
+ {
+ dbg_str << "<!-- U_EMR_SETTEXTCOLOR -->\n";
+
+ PU_EMRSETTEXTCOLOR pEmr = (PU_EMRSETTEXTCOLOR) lpEMFR;
+ d->dc[d->level].textColor = pEmr->crColor;
+ if(tbkMode != d->dc[d->level].bkMode){
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; }
+ }
+ // not text_dirty, because multicolored complex text is supported in libTERE
+ break;
+ }
+ case U_EMR_SETBKCOLOR:
+ {
+ dbg_str << "<!-- U_EMR_SETBKCOLOR -->\n";
+
+ PU_EMRSETBKCOLOR pEmr = (PU_EMRSETBKCOLOR) lpEMFR;
+ tbkColor = pEmr->crColor;
+ if(memcmp(&tbkColor, &(d->dc[d->level].bkColor), sizeof(U_COLORREF))){
+ d->dc[d->level].dirty |= DIRTY_TEXT;
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; }
+ tbkMode = d->dc[d->level].bkMode;
+ }
+ break;
+ }
+ case U_EMR_OFFSETCLIPRGN: dbg_str << "<!-- U_EMR_OFFSETCLIPRGN -->\n"; break;
+ case U_EMR_MOVETOEX:
+ {
+ dbg_str << "<!-- U_EMR_MOVETOEX -->\n";
+
+ PU_EMRMOVETOEX pEmr = (PU_EMRMOVETOEX) lpEMFR;
+
+ d->mask |= emr_mask;
+
+ d->dc[d->level].cur = pEmr->ptl;
+
+ tmp_path <<
+ "\n\tM " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
+ break;
+ }
+ case U_EMR_SETMETARGN: dbg_str << "<!-- U_EMR_SETMETARGN -->\n"; break;
+ case U_EMR_EXCLUDECLIPRECT: dbg_str << "<!-- U_EMR_EXCLUDECLIPRECT -->\n"; break;
+ case U_EMR_INTERSECTCLIPRECT:
+ {
+ dbg_str << "<!-- U_EMR_INTERSECTCLIPRECT -->\n";
+
+ PU_EMRINTERSECTCLIPRECT pEmr = (PU_EMRINTERSECTCLIPRECT) lpEMFR;
+ U_RECTL rc = pEmr->rclClip;
+ clipset = true;
+ if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom))
+ break;
+ rc_old = rc;
+
+ double dx = pix_to_x_point( d, rc.left, rc.top );
+ double dy = pix_to_y_point( d, rc.left, rc.top );
+ double dw = pix_to_abs_size( d, rc.right - rc.left + 1);
+ double dh = pix_to_abs_size( d, rc.bottom - rc.top + 1);
+
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n<clipPath\n\tclipPathUnits=\"userSpaceOnUse\" ";
+ tmp_rectangle << "\nid=\"clipEmfPath" << ++(d->id) << "\" >";
+ tmp_rectangle << "\n<rect ";
+ tmp_rectangle << "\n x=\"" << dx << "\" ";
+ tmp_rectangle << "\n y=\"" << dy << "\" ";
+ tmp_rectangle << "\n width=\"" << dw << "\" ";
+ tmp_rectangle << "\n height=\"" << dh << "\" ";
+ tmp_rectangle << "\n transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset
+ tmp_rectangle << "/>\n</clipPath>";
+
+ *(d->outdef) += tmp_rectangle.str().c_str();
+ *(d->path) = "";
+ break;
+ }
+ case U_EMR_SCALEVIEWPORTEXTEX: dbg_str << "<!-- U_EMR_SCALEVIEWPORTEXTEX -->\n"; break;
+ case U_EMR_SCALEWINDOWEXTEX: dbg_str << "<!-- U_EMR_SCALEWINDOWEXTEX -->\n"; break;
+ case U_EMR_SAVEDC:
+ dbg_str << "<!-- U_EMR_SAVEDC -->\n";
+
+ if (d->level < EMF_MAX_DC) {
+ d->dc[d->level + 1] = d->dc[d->level];
+ if(d->dc[d->level].font_name){
+ d->dc[d->level + 1].font_name = strdup(d->dc[d->level].font_name); // or memory access problems because font name pointer duplicated
+ }
+ d->level = d->level + 1;
+ }
+ break;
+ case U_EMR_RESTOREDC:
+ {
+ dbg_str << "<!-- U_EMR_RESTOREDC -->\n";
+
+ PU_EMRRESTOREDC pEmr = (PU_EMRRESTOREDC) lpEMFR;
+ int old_level = d->level;
+ if (pEmr->iRelative >= 0) {
+ if (pEmr->iRelative < d->level)
+ d->level = pEmr->iRelative;
+ }
+ else {
+ if (d->level + pEmr->iRelative >= 0)
+ d->level = d->level + pEmr->iRelative;
+ }
+ while (old_level > d->level) {
+ if (!d->dc[old_level].style.stroke_dasharray.values.empty() && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dasharray.values!=d->dc[old_level-1].style.stroke_dasharray.values))){
+ d->dc[old_level].style.stroke_dasharray.values.clear();
+ }
+ if(d->dc[old_level].font_name){
+ free(d->dc[old_level].font_name); // else memory leak
+ d->dc[old_level].font_name = NULL;
+ }
+ old_level--;
+ }
+ break;
+ }
+ case U_EMR_SETWORLDTRANSFORM:
+ {
+ dbg_str << "<!-- U_EMR_SETWORLDTRANSFORM -->\n";
+
+ PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM) lpEMFR;
+ d->dc[d->level].worldTransform = pEmr->xform;
+ break;
+ }
+ case U_EMR_MODIFYWORLDTRANSFORM:
+ {
+ dbg_str << "<!-- U_EMR_MODIFYWORLDTRANSFORM -->\n";
+
+ PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM) lpEMFR;
+ switch (pEmr->iMode)
+ {
+ case U_MWT_IDENTITY:
+ d->dc[d->level].worldTransform.eM11 = 1.0;
+ d->dc[d->level].worldTransform.eM12 = 0.0;
+ d->dc[d->level].worldTransform.eM21 = 0.0;
+ d->dc[d->level].worldTransform.eM22 = 1.0;
+ d->dc[d->level].worldTransform.eDx = 0.0;
+ d->dc[d->level].worldTransform.eDy = 0.0;
+ break;
+ case U_MWT_LEFTMULTIPLY:
+ {
+// d->dc[d->level].worldTransform = pEmr->xform * worldTransform;
+
+ float a11 = pEmr->xform.eM11;
+ float a12 = pEmr->xform.eM12;
+ float a13 = 0.0;
+ float a21 = pEmr->xform.eM21;
+ float a22 = pEmr->xform.eM22;
+ float a23 = 0.0;
+ float a31 = pEmr->xform.eDx;
+ float a32 = pEmr->xform.eDy;
+ float a33 = 1.0;
+
+ float b11 = d->dc[d->level].worldTransform.eM11;
+ float b12 = d->dc[d->level].worldTransform.eM12;
+ //float b13 = 0.0;
+ float b21 = d->dc[d->level].worldTransform.eM21;
+ float b22 = d->dc[d->level].worldTransform.eM22;
+ //float b23 = 0.0;
+ float b31 = d->dc[d->level].worldTransform.eDx;
+ float b32 = d->dc[d->level].worldTransform.eDy;
+ //float b33 = 1.0;
+
+ float c11 = a11*b11 + a12*b21 + a13*b31;;
+ float c12 = a11*b12 + a12*b22 + a13*b32;;
+ //float c13 = a11*b13 + a12*b23 + a13*b33;;
+ float c21 = a21*b11 + a22*b21 + a23*b31;;
+ float c22 = a21*b12 + a22*b22 + a23*b32;;
+ //float c23 = a21*b13 + a22*b23 + a23*b33;;
+ float c31 = a31*b11 + a32*b21 + a33*b31;;
+ float c32 = a31*b12 + a32*b22 + a33*b32;;
+ //float c33 = a31*b13 + a32*b23 + a33*b33;;
+
+ d->dc[d->level].worldTransform.eM11 = c11;;
+ d->dc[d->level].worldTransform.eM12 = c12;;
+ d->dc[d->level].worldTransform.eM21 = c21;;
+ d->dc[d->level].worldTransform.eM22 = c22;;
+ d->dc[d->level].worldTransform.eDx = c31;
+ d->dc[d->level].worldTransform.eDy = c32;
+
+ break;
+ }
+ case U_MWT_RIGHTMULTIPLY:
+ {
+// d->dc[d->level].worldTransform = worldTransform * pEmr->xform;
+
+ float a11 = d->dc[d->level].worldTransform.eM11;
+ float a12 = d->dc[d->level].worldTransform.eM12;
+ float a13 = 0.0;
+ float a21 = d->dc[d->level].worldTransform.eM21;
+ float a22 = d->dc[d->level].worldTransform.eM22;
+ float a23 = 0.0;
+ float a31 = d->dc[d->level].worldTransform.eDx;
+ float a32 = d->dc[d->level].worldTransform.eDy;
+ float a33 = 1.0;
+
+ float b11 = pEmr->xform.eM11;
+ float b12 = pEmr->xform.eM12;
+ //float b13 = 0.0;
+ float b21 = pEmr->xform.eM21;
+ float b22 = pEmr->xform.eM22;
+ //float b23 = 0.0;
+ float b31 = pEmr->xform.eDx;
+ float b32 = pEmr->xform.eDy;
+ //float b33 = 1.0;
+
+ float c11 = a11*b11 + a12*b21 + a13*b31;;
+ float c12 = a11*b12 + a12*b22 + a13*b32;;
+ //float c13 = a11*b13 + a12*b23 + a13*b33;;
+ float c21 = a21*b11 + a22*b21 + a23*b31;;
+ float c22 = a21*b12 + a22*b22 + a23*b32;;
+ //float c23 = a21*b13 + a22*b23 + a23*b33;;
+ float c31 = a31*b11 + a32*b21 + a33*b31;;
+ float c32 = a31*b12 + a32*b22 + a33*b32;;
+ //float c33 = a31*b13 + a32*b23 + a33*b33;;
+
+ d->dc[d->level].worldTransform.eM11 = c11;;
+ d->dc[d->level].worldTransform.eM12 = c12;;
+ d->dc[d->level].worldTransform.eM21 = c21;;
+ d->dc[d->level].worldTransform.eM22 = c22;;
+ d->dc[d->level].worldTransform.eDx = c31;
+ d->dc[d->level].worldTransform.eDy = c32;
+
+ break;
+ }
+// case MWT_SET:
+ default:
+ d->dc[d->level].worldTransform = pEmr->xform;
+ break;
+ }
+ break;
+ }
+ case U_EMR_SELECTOBJECT:
+ {
+ dbg_str << "<!-- U_EMR_SELECTOBJECT -->\n";
+
+ PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT) lpEMFR;
+ unsigned int index = pEmr->ihObject;
+
+ if (index & U_STOCK_OBJECT) {
+ switch (index) {
+ case U_NULL_BRUSH:
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ d->dc[d->level].fill_set = false;
+ break;
+ case U_BLACK_BRUSH:
+ case U_DKGRAY_BRUSH:
+ case U_GRAY_BRUSH:
+ case U_LTGRAY_BRUSH:
+ case U_WHITE_BRUSH:
+ {
+ float val = 0;
+ switch (index) {
+ case U_BLACK_BRUSH:
+ val = 0.0 / 255.0;
+ break;
+ case U_DKGRAY_BRUSH:
+ val = 64.0 / 255.0;
+ break;
+ case U_GRAY_BRUSH:
+ val = 128.0 / 255.0;
+ break;
+ case U_LTGRAY_BRUSH:
+ val = 192.0 / 255.0;
+ break;
+ case U_WHITE_BRUSH:
+ val = 255.0 / 255.0;
+ break;
+ }
+ d->dc[d->level].style.fill.value.color.set( val, val, val );
+
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ d->dc[d->level].fill_set = true;
+ break;
+ }
+ case U_NULL_PEN:
+ d->dc[d->level].stroke_mode = DRAW_PAINT;
+ d->dc[d->level].stroke_set = false;
+ break;
+ case U_BLACK_PEN:
+ case U_WHITE_PEN:
+ {
+ float val = index == U_BLACK_PEN ? 0 : 1;
+ d->dc[d->level].style.stroke_dasharray.set = 0;
+ d->dc[d->level].style.stroke_width.value = 1.0;
+ d->dc[d->level].style.stroke.value.color.set( val, val, val );
+
+ d->dc[d->level].stroke_mode = DRAW_PAINT;
+ d->dc[d->level].stroke_set = true;
+
+ break;
+ }
+ }
+ } else {
+ if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) {
+ switch (d->emf_obj[index].type)
+ {
+ case U_EMR_CREATEPEN:
+ select_pen(d, index);
+ break;
+ case U_EMR_CREATEBRUSHINDIRECT:
+ case U_EMR_CREATEDIBPATTERNBRUSHPT:
+ case U_EMR_CREATEMONOBRUSH:
+ select_brush(d, index);
+ break;
+ case U_EMR_EXTCREATEPEN:
+ select_extpen(d, index);
+ break;
+ case U_EMR_EXTCREATEFONTINDIRECTW:
+ select_font(d, index);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case U_EMR_CREATEPEN:
+ {
+ dbg_str << "<!-- U_EMR_CREATEPEN -->\n";
+
+ PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN) lpEMFR;
+ insert_object(d, pEmr->ihPen, U_EMR_CREATEPEN, lpEMFR);
+ break;
+ }
+ case U_EMR_CREATEBRUSHINDIRECT:
+ {
+ dbg_str << "<!-- U_EMR_CREATEBRUSHINDIRECT -->\n";
+
+ PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) lpEMFR;
+ insert_object(d, pEmr->ihBrush, U_EMR_CREATEBRUSHINDIRECT, lpEMFR);
+ break;
+ }
+ case U_EMR_DELETEOBJECT:
+ dbg_str << "<!-- U_EMR_DELETEOBJECT -->\n";
+ // Objects here are not deleted until the draw completes, new ones may write over an existing one.
+ break;
+ case U_EMR_ANGLEARC:
+ dbg_str << "<!-- U_EMR_ANGLEARC -->\n";
+ break;
+ case U_EMR_ELLIPSE:
+ {
+ dbg_str << "<!-- U_EMR_ELLIPSE -->\n";
+
+ PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE) lpEMFR;
+ U_RECTL rclBox = pEmr->rclBox;
+
+ double cx = pix_to_x_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 );
+ double cy = pix_to_y_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 );
+ double rx = pix_to_abs_size( d, fabs(rclBox.right - rclBox.left )/2.0 );
+ double ry = pix_to_abs_size( d, fabs(rclBox.top - rclBox.bottom)/2.0 );
+
+ SVGOStringStream tmp_ellipse;
+ tmp_ellipse << "cx=\"" << cx << "\" ";
+ tmp_ellipse << "cy=\"" << cy << "\" ";
+ tmp_ellipse << "rx=\"" << rx << "\" ";
+ tmp_ellipse << "ry=\"" << ry << "\" ";
+
+ d->mask |= emr_mask;
+
+ *(d->outsvg) += " <ellipse ";
+ output_style(d, lpEMFR->iType); //
+ *(d->outsvg) += "\n\t";
+ *(d->outsvg) += tmp_ellipse.str().c_str();
+ *(d->outsvg) += "/> \n";
+ *(d->path) = "";
+ break;
+ }
+ case U_EMR_RECTANGLE:
+ {
+ dbg_str << "<!-- U_EMR_RECTANGLE -->\n";
+
+ PU_EMRRECTANGLE pEmr = (PU_EMRRECTANGLE) lpEMFR;
+ U_RECTL rc = pEmr->rclBox;
+
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n\tM " << pix_to_xy( d, rc.left , rc.top ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.top ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.bottom ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.left, rc.bottom ) << " ";
+ tmp_rectangle << "\n\tz";
+
+ d->mask |= emr_mask;
+
+ tmp_path << tmp_rectangle.str().c_str();
+ break;
+ }
+ case U_EMR_ROUNDRECT:
+ {
+ dbg_str << "<!-- U_EMR_ROUNDRECT -->\n";
+
+ PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT) lpEMFR;
+ U_RECTL rc = pEmr->rclBox;
+ U_SIZEL corner = pEmr->szlCorner;
+ double f = 4.*(sqrt(2) - 1)/3;
+ double f1 = 1.0 - f;
+ double cnx = corner.cx/2;
+ double cny = corner.cy/2;
+
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n"
+ << " M "
+ << pix_to_xy(d, rc.left , rc.top + cny )
+ << "\n";
+ tmp_rectangle << " C "
+ << pix_to_xy(d, rc.left , rc.top + cny*f1 )
+ << " "
+ << pix_to_xy(d, rc.left + cnx*f1 , rc.top )
+ << " "
+ << pix_to_xy(d, rc.left + cnx , rc.top )
+ << "\n";
+ tmp_rectangle << " L "
+ << pix_to_xy(d, rc.right - cnx , rc.top )
+ << "\n";
+ tmp_rectangle << " C "
+ << pix_to_xy(d, rc.right - cnx*f1 , rc.top )
+ << " "
+ << pix_to_xy(d, rc.right , rc.top + cny*f1 )
+ << " "
+ << pix_to_xy(d, rc.right , rc.top + cny )
+ << "\n";
+ tmp_rectangle << " L "
+ << pix_to_xy(d, rc.right , rc.bottom - cny )
+ << "\n";
+ tmp_rectangle << " C "
+ << pix_to_xy(d, rc.right , rc.bottom - cny*f1 )
+ << " "
+ << pix_to_xy(d, rc.right - cnx*f1 , rc.bottom )
+ << " "
+ << pix_to_xy(d, rc.right - cnx , rc.bottom )
+ << "\n";
+ tmp_rectangle << " L "
+ << pix_to_xy(d, rc.left + cnx , rc.bottom )
+ << "\n";
+ tmp_rectangle << " C "
+ << pix_to_xy(d, rc.left + cnx*f1 , rc.bottom )
+ << " "
+ << pix_to_xy(d, rc.left , rc.bottom - cny*f1 )
+ << " "
+ << pix_to_xy(d, rc.left , rc.bottom - cny )
+ << "\n";
+ tmp_rectangle << " z\n";
+
+
+ d->mask |= emr_mask;
+
+ tmp_path << tmp_rectangle.str().c_str();
+ break;
+ }
+ case U_EMR_ARC:
+ {
+ dbg_str << "<!-- U_EMR_ARC -->\n";
+ U_PAIRF center,start,end,size;
+ int f1;
+ int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
+ int stat = emr_arc_points( lpEMFR, &f1, f2, &center, &start, &end, &size);
+ if(!stat){
+ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ d->mask |= emr_mask;
+ }
+ else {
+ dbg_str << "<!-- ARC record is invalid -->\n";
+ }
+ break;
+ }
+ case U_EMR_CHORD:
+ {
+ dbg_str << "<!-- U_EMR_CHORD -->\n";
+ U_PAIRF center,start,end,size;
+ int f1;
+ int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
+ if(!emr_arc_points( lpEMFR, &f1, f2, &center, &start, &end, &size)){
+ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ tmp_path << " z ";
+ d->mask |= emr_mask;
+ }
+ else {
+ dbg_str << "<!-- CHORD record is invalid -->\n";
+ }
+ break;
+ }
+ case U_EMR_PIE:
+ {
+ dbg_str << "<!-- U_EMR_PIE -->\n";
+ U_PAIRF center,start,end,size;
+ int f1;
+ int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
+ if(!emr_arc_points( lpEMFR, &f1, f2, &center, &start, &end, &size)){
+ tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y);
+ tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ tmp_path << " z ";
+ d->mask |= emr_mask;
+ }
+ else {
+ dbg_str << "<!-- PIE record is invalid -->\n";
+ }
+ break;
+ }
+ case U_EMR_SELECTPALETTE: dbg_str << "<!-- U_EMR_SELECTPALETTE -->\n"; break;
+ case U_EMR_CREATEPALETTE: dbg_str << "<!-- U_EMR_CREATEPALETTE -->\n"; break;
+ case U_EMR_SETPALETTEENTRIES: dbg_str << "<!-- U_EMR_SETPALETTEENTRIES -->\n"; break;
+ case U_EMR_RESIZEPALETTE: dbg_str << "<!-- U_EMR_RESIZEPALETTE -->\n"; break;
+ case U_EMR_REALIZEPALETTE: dbg_str << "<!-- U_EMR_REALIZEPALETTE -->\n"; break;
+ case U_EMR_EXTFLOODFILL: dbg_str << "<!-- U_EMR_EXTFLOODFILL -->\n"; break;
+ case U_EMR_LINETO:
+ {
+ dbg_str << "<!-- U_EMR_LINETO -->\n";
+
+ PU_EMRLINETO pEmr = (PU_EMRLINETO) lpEMFR;
+
+ d->mask |= emr_mask;
+
+ tmp_path <<
+ "\n\tL " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y) << " ";
+ break;
+ }
+ case U_EMR_ARCTO:
+ {
+ dbg_str << "<!-- U_EMR_ARCTO -->\n";
+ U_PAIRF center,start,end,size;
+ int f1;
+ int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
+ if(!emr_arc_points( lpEMFR, &f1, f2, &center, &start, &end, &size)){
+ // draw a line from current position to start, arc from there
+ tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y)<< " ";
+
+ d->mask |= emr_mask;
+ }
+ else {
+ dbg_str << "<!-- ARCTO record is invalid -->\n";
+ }
+ break;
+ }
+ case U_EMR_POLYDRAW: dbg_str << "<!-- U_EMR_POLYDRAW -->\n"; break;
+ case U_EMR_SETARCDIRECTION:
+ {
+ dbg_str << "<!-- U_EMR_SETARCDIRECTION -->\n";
+ PU_EMRSETARCDIRECTION pEmr = (PU_EMRSETARCDIRECTION) lpEMFR;
+ if(d->arcdir == U_AD_CLOCKWISE || d->arcdir == U_AD_COUNTERCLOCKWISE){ // EMF file could be corrupt
+ d->arcdir = pEmr->iArcDirection;
+ }
+ break;
+ }
+ case U_EMR_SETMITERLIMIT:
+ {
+ dbg_str << "<!-- U_EMR_SETMITERLIMIT -->\n";
+
+ PU_EMRSETMITERLIMIT pEmr = (PU_EMRSETMITERLIMIT) lpEMFR;
+
+ //The function takes a float but saves a 32 bit int in the U_EMR_SETMITERLIMIT record.
+ float miterlimit = *((int32_t *) &(pEmr->eMiterLimit));
+ d->dc[d->level].style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size
+ if (d->dc[d->level].style.stroke_miterlimit.value < 2)
+ d->dc[d->level].style.stroke_miterlimit.value = 2.0;
+ break;
+ }
+ case U_EMR_BEGINPATH:
+ {
+ dbg_str << "<!-- U_EMR_BEGINPATH -->\n";
+ // The next line should never be needed, should have been handled before main switch
+ // qualifier added because EMF's encountered where moveto preceded beginpath followed by lineto
+ if(d->mask & U_DRAW_VISIBLE){
+ *(d->path) = "";
+ }
+ d->mask |= emr_mask;
+ break;
+ }
+ case U_EMR_ENDPATH:
+ {
+ dbg_str << "<!-- U_EMR_ENDPATH -->\n";
+ d->mask &= (0xFFFFFFFF - U_DRAW_ONLYTO); // clear the OnlyTo bit (it might not have been set), prevents any further path extension
+ break;
+ }
+ case U_EMR_CLOSEFIGURE:
+ {
+ dbg_str << "<!-- U_EMR_CLOSEFIGURE -->\n";
+ // EMF may contain multiple closefigures on one path
+ tmp_path << "\n\tz";
+ d->mask |= U_DRAW_CLOSED;
+ break;
+ }
+ case U_EMR_FILLPATH:
+ {
+ dbg_str << "<!-- U_EMR_FILLPATH -->\n";
+ if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths
+ if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense
+ tmp_path << "\n\tz";
+ d->mask |= U_DRAW_CLOSED;
+ }
+ d->mask |= emr_mask;
+ d->drawtype = U_EMR_FILLPATH;
+ }
+ break;
+ }
+ case U_EMR_STROKEANDFILLPATH:
+ {
+ dbg_str << "<!-- U_EMR_STROKEANDFILLPATH -->\n";
+ if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths
+ if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense
+ tmp_path << "\n\tz";
+ d->mask |= U_DRAW_CLOSED;
+ }
+ d->mask |= emr_mask;
+ d->drawtype = U_EMR_STROKEANDFILLPATH;
+ }
+ break;
+ }
+ case U_EMR_STROKEPATH:
+ {
+ dbg_str << "<!-- U_EMR_STROKEPATH -->\n";
+ if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths
+ d->mask |= emr_mask;
+ d->drawtype = U_EMR_STROKEPATH;
+ }
+ break;
+ }
+ case U_EMR_FLATTENPATH: dbg_str << "<!-- U_EMR_FLATTENPATH -->\n"; break;
+ case U_EMR_WIDENPATH: dbg_str << "<!-- U_EMR_WIDENPATH -->\n"; break;
+ case U_EMR_SELECTCLIPPATH: dbg_str << "<!-- U_EMR_SELECTCLIPPATH -->\n"; break;
+ case U_EMR_ABORTPATH:
+ {
+ dbg_str << "<!-- U_EMR_ABORTPATH -->\n";
+ *(d->path) = "";
+ d->drawtype = 0;
+ break;
+ }
+ case U_EMR_UNDEF69: dbg_str << "<!-- U_EMR_UNDEF69 -->\n"; break;
+ case U_EMR_COMMENT:
+ {
+ dbg_str << "<!-- U_EMR_COMMENT -->\n";
+
+ PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT) lpEMFR;
+
+ char *szTxt = (char *) pEmr->Data;
+
+ for (uint32_t i = 0; i < pEmr->cbData; i++) {
+ if ( *szTxt) {
+ if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) {
+ tmp_str << *szTxt;
+ }
+ szTxt++;
+ }
+ }
+
+ if (0 && strlen(tmp_str.str().c_str())) {
+ tmp_outsvg << " <!-- \"";
+ tmp_outsvg << tmp_str.str().c_str();
+ tmp_outsvg << "\" -->\n";
+ }
+
+ break;
+ }
+ case U_EMR_FILLRGN: dbg_str << "<!-- U_EMR_FILLRGN -->\n"; break;
+ case U_EMR_FRAMERGN: dbg_str << "<!-- U_EMR_FRAMERGN -->\n"; break;
+ case U_EMR_INVERTRGN: dbg_str << "<!-- U_EMR_INVERTRGN -->\n"; break;
+ case U_EMR_PAINTRGN: dbg_str << "<!-- U_EMR_PAINTRGN -->\n"; break;
+ case U_EMR_EXTSELECTCLIPRGN:
+ {
+ dbg_str << "<!-- U_EMR_EXTSELECTCLIPRGN -->\n";
+
+ PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) lpEMFR;
+ if (pEmr->iMode == U_RGN_COPY)
+ clipset = false;
+ break;
+ }
+ case U_EMR_BITBLT:
+ {
+ dbg_str << "<!-- U_EMR_BITBLT -->\n";
+
+ PU_EMRBITBLT pEmr = (PU_EMRBITBLT) lpEMFR;
+ // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at
+ // least it leaves objects where the operations should have been.
+ if (!pEmr->cbBmiSrc) {
+ // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead
+
+ if(pEmr->dwRop == U_NOOP)break; /* GDI applications apparently often end with this as a sort of flush(), nothing should be drawn */
+ int32_t dx = pEmr->Dest.x;
+ int32_t dy = pEmr->Dest.y;
+ int32_t dw = pEmr->cDest.x;
+ int32_t dh = pEmr->cDest.y;
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " ";
+ tmp_rectangle << "\n\tz";
+
+ d->mask |= emr_mask;
+ d->dwRop3 = pEmr->dwRop; // we will try to approximate SOME of these
+ d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that
+
+ tmp_path << tmp_rectangle.str().c_str();
+ }
+ else {
+ double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y);
+ double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y);
+ double dw = pix_to_abs_size( d, pEmr->cDest.x);
+ double dh = pix_to_abs_size( d, pEmr->cDest.y);
+ //source position within the bitmap, in pixels
+ int sx = pEmr->Src.x + pEmr->xformSrc.eDx;
+ int sy = pEmr->Src.y + pEmr->xformSrc.eDy;
+ int sw = 0; // extract all of the image
+ int sh = 0;
+ if(sx<0)sx=0;
+ if(sy<0)sy=0;
+ common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
+ pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
+ }
+ break;
+ }
+ case U_EMR_STRETCHBLT:
+ {
+ dbg_str << "<!-- U_EMR_STRETCHBLT -->\n";
+ PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) lpEMFR;
+ // Always grab image, ignore modes.
+ if (pEmr->cbBmiSrc) {
+ double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y);
+ double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y);
+ double dw = pix_to_abs_size( d, pEmr->cDest.x);
+ double dh = pix_to_abs_size( d, pEmr->cDest.y);
+ //source position within the bitmap, in pixels
+ int sx = pEmr->Src.x + pEmr->xformSrc.eDx;
+ int sy = pEmr->Src.y + pEmr->xformSrc.eDy;
+ int sw = pEmr->cSrc.x; // extract the specified amount of the image
+ int sh = pEmr->cSrc.y;
+ common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
+ pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
+ }
+ break;
+ }
+ case U_EMR_MASKBLT:
+ {
+ dbg_str << "<!-- U_EMR_MASKBLT -->\n";
+ PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) lpEMFR;
+ // Always grab image, ignore masks and modes.
+ if (pEmr->cbBmiSrc) {
+ double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y);
+ double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y);
+ double dw = pix_to_abs_size( d, pEmr->cDest.x);
+ double dh = pix_to_abs_size( d, pEmr->cDest.y);
+ int sx = pEmr->Src.x + pEmr->xformSrc.eDx; //source position within the bitmap, in pixels
+ int sy = pEmr->Src.y + pEmr->xformSrc.eDy;
+ int sw = 0; // extract all of the image
+ int sh = 0;
+ common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
+ pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
+ }
+ break;
+ }
+ case U_EMR_PLGBLT: dbg_str << "<!-- U_EMR_PLGBLT -->\n"; break;
+ case U_EMR_SETDIBITSTODEVICE: dbg_str << "<!-- U_EMR_SETDIBITSTODEVICE -->\n"; break;
+ case U_EMR_STRETCHDIBITS:
+ {
+ // Some applications use multiple EMF operations, including multiple STRETCHDIBITS to create
+ // images with transparent regions. PowerPoint does this with rotated images, for instance.
+ // Parsing all of that to derive a single resultant image object is left for a later version
+ // of this code. In the meantime, every STRETCHDIBITS goes directly to an image. The Inkscape
+ // user can sort out transparency later using Gimp, if need be.
+
+ PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) lpEMFR;
+ double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y );
+ double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y );
+ double dw = pix_to_abs_size( d, pEmr->cDest.x);
+ double dh = pix_to_abs_size( d, pEmr->cDest.y);
+ int sx = pEmr->Src.x; //source position within the bitmap, in pixels
+ int sy = pEmr->Src.y;
+ int sw = pEmr->cSrc.x; // extract the specified amount of the image
+ int sh = pEmr->cSrc.y;
+ common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
+ pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
+
+ dbg_str << "<!-- U_EMR_STRETCHDIBITS -->\n";
+ break;
+ }
+ case U_EMR_EXTCREATEFONTINDIRECTW:
+ {
+ dbg_str << "<!-- U_EMR_EXTCREATEFONTINDIRECTW -->\n";
+
+ PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) lpEMFR;
+ insert_object(d, pEmr->ihFont, U_EMR_EXTCREATEFONTINDIRECTW, lpEMFR);
+ break;
+ }
+ case U_EMR_EXTTEXTOUTA:
+ case U_EMR_EXTTEXTOUTW:
+ case U_EMR_SMALLTEXTOUT:
+ {
+ dbg_str << "<!-- U_EMR_EXTTEXTOUTA/W -->\n";
+
+ PU_EMREXTTEXTOUTW pEmr = (PU_EMREXTTEXTOUTW) lpEMFR;
+ PU_EMRSMALLTEXTOUT pEmrS = (PU_EMRSMALLTEXTOUT) lpEMFR;
+
+ double x1,y1;
+ int roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields, only used with U_EMR_SMALLTEXTOUT
+ int cChars;
+ if(lpEMFR->iType==U_EMR_SMALLTEXTOUT){
+ x1 = pEmrS->Dest.x;
+ y1 = pEmrS->Dest.y;
+ cChars = pEmrS->cChars;
+ if(!(pEmrS->fuOptions & U_ETO_NO_RECT)){ roff += sizeof(U_RECTL); }
+ }
+ else {
+ x1 = pEmr->emrtext.ptlReference.x;
+ y1 = pEmr->emrtext.ptlReference.y;
+ cChars = 0;
+ }
+ uint32_t fOptions = pEmr->emrtext.fOptions;
+
+ if (d->dc[d->level].textAlign & U_TA_UPDATECP) {
+ x1 = d->dc[d->level].cur.x;
+ y1 = d->dc[d->level].cur.y;
+ }
+
+ double x = pix_to_x_point(d, x1, y1);
+ double y = pix_to_y_point(d, x1, y1);
+
+ /* Rotation issues are handled entirely in libTERE now */
+
+ uint32_t *dup_wt = NULL;
+
+ if( lpEMFR->iType==U_EMR_EXTTEXTOUTA){
+ /* These should be JUST ASCII, but they might not be...
+ If it holds Utf-8 or plain ASCII the first call will succeed.
+ If not, assume that it holds Latin1.
+ If that fails then someting is really screwed up!
+ */
+ dup_wt = U_Utf8ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL);
+ if(!dup_wt)dup_wt = U_Latin1ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL);
+ if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars);
+ }
+ else if( lpEMFR->iType==U_EMR_EXTTEXTOUTW){
+ dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmr + pEmr->emrtext.offString), pEmr->emrtext.nChars, NULL);
+ if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars);
+ }
+ else { // U_EMR_SMALLTEXTOUT
+ if(pEmrS->fuOptions & U_ETO_SMALL_CHARS){
+ dup_wt = U_Utf8ToUtf32le((char *) pEmrS + roff, cChars, NULL);
+ }
+ else {
+ dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmrS + roff), cChars, NULL);
+ }
+ if(!dup_wt)dup_wt = unknown_chars(cChars);
+ }
+
+ msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats
+
+ if(NonToUnicode(dup_wt, d->dc[d->level].font_name)){
+ free(d->dc[d->level].font_name);
+ d->dc[d->level].font_name = strdup("Times New Roman");
+ }
+
+ char *ansi_text;
+ ansi_text = (char *) U_Utf32leToUtf8((uint32_t *)dup_wt, 0, NULL);
+ free(dup_wt);
+ // Empty string or starts with an invalid escape/control sequence, which is bogus text. Throw it out before g_markup_escape_text can make things worse
+ if(*((uint8_t *)ansi_text) <= 0x1F){
+ free(ansi_text);
+ ansi_text=NULL;
+ }
+
+ if (ansi_text) {
+
+ SVGOStringStream ts;
+
+ gchar *escaped_text = g_markup_escape_text(ansi_text, -1);
+
+ tsp.x = x*0.8; // TERE expects sizes in points.
+ tsp.y = y*0.8;
+ tsp.color.Red = d->dc[d->level].textColor.Red;
+ tsp.color.Green = d->dc[d->level].textColor.Green;
+ tsp.color.Blue = d->dc[d->level].textColor.Blue;
+ tsp.color.Reserved = 0;
+ switch(d->dc[d->level].style.font_style.value){
+ case SP_CSS_FONT_STYLE_OBLIQUE:
+ tsp.italics = FC_SLANT_OBLIQUE; break;
+ case SP_CSS_FONT_STYLE_ITALIC:
+ tsp.italics = FC_SLANT_ITALIC; break;
+ default:
+ case SP_CSS_FONT_STYLE_NORMAL:
+ tsp.italics = FC_SLANT_ROMAN; break;
+ }
+ switch(d->dc[d->level].style.font_weight.value){
+ case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break;
+ case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break;
+ case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break;
+ case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break;
+ case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
+ case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break;
+ case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break;
+ case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
+ default: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ }
+ // EMF only supports two types of text decoration
+ tsp.decoration = TXTDECOR_NONE;
+ if(d->dc[d->level].style.text_decoration_line.underline){ tsp.decoration |= TXTDECOR_UNDER; }
+ if(d->dc[d->level].style.text_decoration_line.line_through){ tsp.decoration |= TXTDECOR_STRIKE;}
+
+ // EMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left
+ tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER :
+ (((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT :
+ ALIRIGHT);
+ tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE :
+ ((d->dc[d->level].textAlign & U_TA_BOTTOM) ? ALIBOT :
+ ALITOP));
+
+ // language direction can be encoded two ways, U_TA_RTLREADING is preferred
+ if( (fOptions & U_ETO_RTLREADING) || (d->dc[d->level].textAlign & U_TA_RTLREADING) ){ tsp.ldir = LDIR_RL; }
+ else{ tsp.ldir = LDIR_LR; }
+
+ tsp.condensed = FC_WIDTH_NORMAL; // Not implemented well in libTERE (yet)
+ tsp.ori = d->dc[d->level].style.baseline_shift.value; // For now orientation is always the same as escapement
+ tsp.ori += 180.0 * current_rotation(d)/ M_PI; // radians to degrees
+ tsp.string = (uint8_t *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear().
+ tsp.fs = d->dc[d->level].style.font_size.computed * 0.8; // Font size in points
+ char *fontspec = TR_construct_fontspec(&tsp, d->dc[d->level].font_name);
+ tsp.fi_idx = ftinfo_load_fontname(d->tri->fti,fontspec);
+ free(fontspec);
+ // when font name includes narrow it may not be set to "condensed". Narrow fonts do not work well anyway though
+ // as the metrics from fontconfig may not match, or the font may not be present.
+ if(0<= TR_findcasesub(d->dc[d->level].font_name, (char *) "Narrow")){ tsp.co=1; }
+ else { tsp.co=0; }
+
+ int status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement
+ if(status==-1){ // change of escapement, emit what we have and reset
+ TR_layout_analyze(d->tri);
+ TR_layout_2_svg(d->tri);
+ ts << d->tri->out;
+ *(d->outsvg) += ts.str().c_str();
+ d->tri = trinfo_clear(d->tri);
+ (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
+ }
+
+ g_free(escaped_text);
+ free(ansi_text);
+ }
+
+ break;
+ }
+ case U_EMR_POLYBEZIER16:
+ {
+ dbg_str << "<!-- U_EMR_POLYBEZIER16 -->\n";
+
+ PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) lpEMFR;
+ PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
+ uint32_t i,j;
+
+ if (pEmr->cpts<4)
+ break;
+
+ d->mask |= emr_mask;
+
+ tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " ";
+
+ for (i=1; i<pEmr->cpts; ) {
+ tmp_str << "\n\tC ";
+ for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
+ tmp_str << pix_to_xy( d, apts[i].x, apts[i].y ) << " ";
+ }
+ }
+
+ tmp_path << tmp_str.str().c_str();
+
+ break;
+ }
+ case U_EMR_POLYGON16:
+ {
+ dbg_str << "<!-- U_EMR_POLYGON16 -->\n";
+
+ PU_EMRPOLYGON16 pEmr = (PU_EMRPOLYGON16) lpEMFR;
+ PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
+ SVGOStringStream tmp_poly;
+ unsigned int i;
+ unsigned int first = 0;
+
+ d->mask |= emr_mask;
+
+ // skip the first point?
+ tmp_poly << "\n\tM " << pix_to_xy( d, apts[first].x, apts[first].y ) << " ";
+
+ for (i=first+1; i<pEmr->cpts; i++) {
+ tmp_poly << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " ";
+ }
+
+ tmp_path << tmp_poly.str().c_str();
+ tmp_path << "\n\tz";
+ d->mask |= U_DRAW_CLOSED;
+
+ break;
+ }
+ case U_EMR_POLYLINE16:
+ {
+ dbg_str << "<!-- U_EMR_POLYLINE16 -->\n";
+
+ PU_EMRPOLYLINE16 pEmr = (PU_EMRPOLYLINE16) lpEMFR;
+ PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
+ uint32_t i;
+
+ if (pEmr->cpts<2)
+ break;
+
+ d->mask |= emr_mask;
+
+ tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " ";
+
+ for (i=1; i<pEmr->cpts; i++) {
+ tmp_str << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " ";
+ }
+
+ tmp_path << tmp_str.str().c_str();
+
+ break;
+ }
+ case U_EMR_POLYBEZIERTO16:
+ {
+ dbg_str << "<!-- U_EMR_POLYBEZIERTO16 -->\n";
+
+ PU_EMRPOLYBEZIERTO16 pEmr = (PU_EMRPOLYBEZIERTO16) lpEMFR;
+ PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
+ uint32_t i,j;
+
+ d->mask |= emr_mask;
+
+ for (i=0; i<pEmr->cpts;) {
+ tmp_path << "\n\tC ";
+ for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
+ tmp_path << pix_to_xy( d, apts[i].x, apts[i].y) << " ";
+ }
+ }
+
+ break;
+ }
+ case U_EMR_POLYLINETO16:
+ {
+ dbg_str << "<!-- U_EMR_POLYLINETO16 -->\n";
+
+ PU_EMRPOLYLINETO16 pEmr = (PU_EMRPOLYLINETO16) lpEMFR;
+ PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
+ uint32_t i;
+
+ d->mask |= emr_mask;
+
+ for (i=0; i<pEmr->cpts;i++) {
+ tmp_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " ";
+ }
+
+ break;
+ }
+ case U_EMR_POLYPOLYLINE16:
+ case U_EMR_POLYPOLYGON16:
+ {
+ if (lpEMFR->iType == U_EMR_POLYPOLYLINE16)
+ dbg_str << "<!-- U_EMR_POLYPOLYLINE16 -->\n";
+ if (lpEMFR->iType == U_EMR_POLYPOLYGON16)
+ dbg_str << "<!-- U_EMR_POLYPOLYGON16 -->\n";
+
+ PU_EMRPOLYPOLYGON16 pEmr = (PU_EMRPOLYPOLYGON16) lpEMFR;
+ unsigned int n, i, j;
+
+ d->mask |= emr_mask;
+
+ PU_POINT16 apts = (PU_POINT16) &pEmr->aPolyCounts[pEmr->nPolys];
+
+ i = 0;
+ for (n=0; n<pEmr->nPolys && i<pEmr->cpts; n++) {
+ SVGOStringStream poly_path;
+
+ poly_path << "\n\tM " << pix_to_xy( d, apts[i].x, apts[i].y) << " ";
+ i++;
+
+ for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cpts; j++) {
+ poly_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " ";
+ i++;
+ }
+
+ tmp_str << poly_path.str().c_str();
+ if (lpEMFR->iType == U_EMR_POLYPOLYGON16)
+ tmp_str << " z";
+ tmp_str << " \n";
+ }
+
+ tmp_path << tmp_str.str().c_str();
+
+ break;
+ }
+ case U_EMR_POLYDRAW16: dbg_str << "<!-- U_EMR_POLYDRAW16 -->\n"; break;
+ case U_EMR_CREATEMONOBRUSH:
+ {
+ dbg_str << "<!-- U_EMR_CREATEDIBPATTERNBRUSHPT -->\n";
+
+ PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) lpEMFR;
+ insert_object(d, pEmr->ihBrush, U_EMR_CREATEMONOBRUSH, lpEMFR);
+ break;
+ }
+ case U_EMR_CREATEDIBPATTERNBRUSHPT:
+ {
+ dbg_str << "<!-- U_EMR_CREATEDIBPATTERNBRUSHPT -->\n";
+
+ PU_EMRCREATEDIBPATTERNBRUSHPT pEmr = (PU_EMRCREATEDIBPATTERNBRUSHPT) lpEMFR;
+ insert_object(d, pEmr->ihBrush, U_EMR_CREATEDIBPATTERNBRUSHPT, lpEMFR);
+ break;
+ }
+ case U_EMR_EXTCREATEPEN:
+ {
+ dbg_str << "<!-- U_EMR_EXTCREATEPEN -->\n";
+
+ PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN) lpEMFR;
+ insert_object(d, pEmr->ihPen, U_EMR_EXTCREATEPEN, lpEMFR);
+ break;
+ }
+ case U_EMR_POLYTEXTOUTA: dbg_str << "<!-- U_EMR_POLYTEXTOUTA -->\n"; break;
+ case U_EMR_POLYTEXTOUTW: dbg_str << "<!-- U_EMR_POLYTEXTOUTW -->\n"; break;
+ case U_EMR_SETICMMODE:
+ {
+ dbg_str << "<!-- U_EMR_SETICMMODE -->\n";
+ PU_EMRSETICMMODE pEmr = (PU_EMRSETICMMODE) lpEMFR;
+ ICMmode= pEmr->iMode;
+ break;
+ }
+ case U_EMR_CREATECOLORSPACE: dbg_str << "<!-- U_EMR_CREATECOLORSPACE -->\n"; break;
+ case U_EMR_SETCOLORSPACE: dbg_str << "<!-- U_EMR_SETCOLORSPACE -->\n"; break;
+ case U_EMR_DELETECOLORSPACE: dbg_str << "<!-- U_EMR_DELETECOLORSPACE -->\n"; break;
+ case U_EMR_GLSRECORD: dbg_str << "<!-- U_EMR_GLSRECORD -->\n"; break;
+ case U_EMR_GLSBOUNDEDRECORD: dbg_str << "<!-- U_EMR_GLSBOUNDEDRECORD -->\n"; break;
+ case U_EMR_PIXELFORMAT: dbg_str << "<!-- U_EMR_PIXELFORMAT -->\n"; break;
+ case U_EMR_DRAWESCAPE: dbg_str << "<!-- U_EMR_DRAWESCAPE -->\n"; break;
+ case U_EMR_EXTESCAPE: dbg_str << "<!-- U_EMR_EXTESCAPE -->\n"; break;
+ case U_EMR_UNDEF107: dbg_str << "<!-- U_EMR_UNDEF107 -->\n"; break;
+ // U_EMR_SMALLTEXTOUT is handled with U_EMR_EXTTEXTOUTA/W above
+ case U_EMR_FORCEUFIMAPPING: dbg_str << "<!-- U_EMR_FORCEUFIMAPPING -->\n"; break;
+ case U_EMR_NAMEDESCAPE: dbg_str << "<!-- U_EMR_NAMEDESCAPE -->\n"; break;
+ case U_EMR_COLORCORRECTPALETTE: dbg_str << "<!-- U_EMR_COLORCORRECTPALETTE -->\n"; break;
+ case U_EMR_SETICMPROFILEA: dbg_str << "<!-- U_EMR_SETICMPROFILEA -->\n"; break;
+ case U_EMR_SETICMPROFILEW: dbg_str << "<!-- U_EMR_SETICMPROFILEW -->\n"; break;
+ case U_EMR_ALPHABLEND: dbg_str << "<!-- U_EMR_ALPHABLEND -->\n"; break;
+ case U_EMR_SETLAYOUT: dbg_str << "<!-- U_EMR_SETLAYOUT -->\n"; break;
+ case U_EMR_TRANSPARENTBLT: dbg_str << "<!-- U_EMR_TRANSPARENTBLT -->\n"; break;
+ case U_EMR_UNDEF117: dbg_str << "<!-- U_EMR_UNDEF117 -->\n"; break;
+ case U_EMR_GRADIENTFILL:
+ {
+ /* Gradient fill is doable for rectangles because those correspond to linear gradients. However,
+ the general case for the triangle fill, with a different color in each corner of the triangle,
+ has no SVG equivalent and cannot be easily emulated with SVG gradients. So the linear gradient
+ is implemented, and the triangle fill just paints with the color of the first corner.
+
+ This record can hold a series of gradients so we are forced to add path elements directly here,
+ it cannot wait for the top of the main loop. Any existing path is erased.
+
+ */
+ dbg_str << "<!-- U_EMR_GRADIENTFILL -->\n";
+ PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL) lpEMFR;
+ int nV = pEmr->nTriVert; // Number of TriVertex objects
+ int nG = pEmr->nGradObj; // Number of gradient triangle/rectangle objects
+ U_TRIVERTEX *tv = (U_TRIVERTEX *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL));
+ if( pEmr->ulMode == U_GRADIENT_FILL_RECT_H ||
+ pEmr->ulMode == U_GRADIENT_FILL_RECT_V
+ ){
+ SVGOStringStream tmp_rectangle;
+ int i,fill_idx;
+ U_GRADIENT4 *rcs = (U_GRADIENT4 *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL) + sizeof(U_TRIVERTEX)*nV);
+ for(i=0;i<nG;i++){
+ tmp_rectangle << "\n<path d=\"";
+ fill_idx = add_gradient(d, pEmr->ulMode, tv[rcs[i].UpperLeft], tv[rcs[i].LowerRight]);
+ tmp_rectangle << "\n\tM " << pix_to_xy( d, tv[rcs[i].UpperLeft ].x , tv[rcs[i].UpperLeft ].y ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].LowerRight].x , tv[rcs[i].UpperLeft ].y ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].LowerRight].x , tv[rcs[i].LowerRight].y ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].UpperLeft ].x , tv[rcs[i].LowerRight].y ) << " ";
+ tmp_rectangle << "\n\tz\"";
+ tmp_rectangle << "\n\tstyle=\"stroke:none;fill:url(#";
+ tmp_rectangle << d->gradients.strings[fill_idx];
+ tmp_rectangle << ");\"\n/>\n";
+ }
+ *(d->outsvg) += tmp_rectangle.str().c_str();
+ }
+ else if(pEmr->ulMode == U_GRADIENT_FILL_TRIANGLE){
+ SVGOStringStream tmp_triangle;
+ char tmpcolor[8];
+ int i;
+ U_GRADIENT3 *tris = (U_GRADIENT3 *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL) + sizeof(U_TRIVERTEX)*nV);
+ for(i=0;i<nG;i++){
+ tmp_triangle << "\n<path d=\"";
+ sprintf(tmpcolor,"%6.6X",sethexcolor(trivertex_to_colorref(tv[tris[i].Vertex1])));
+ tmp_triangle << "\n\tM " << pix_to_xy( d, tv[tris[i].Vertex1].x , tv[tris[i].Vertex1].y ) << " ";
+ tmp_triangle << "\n\tL " << pix_to_xy( d, tv[tris[i].Vertex2].x , tv[tris[i].Vertex2].y ) << " ";
+ tmp_triangle << "\n\tL " << pix_to_xy( d, tv[tris[i].Vertex3].x , tv[tris[i].Vertex3].y ) << " ";
+ tmp_triangle << "\n\tz\"";
+ tmp_triangle << "\n\tstyle=\"stroke:none;fill:#";
+ tmp_triangle << tmpcolor;
+ tmp_triangle << ";\"\n/>\n";
+ }
+ *(d->outsvg) += tmp_triangle.str().c_str();
+ }
+ *(d->path) = "";
+ // if it is anything else the record is bogus, so ignore it
+ break;
+ }
+ case U_EMR_SETLINKEDUFIS: dbg_str << "<!-- U_EMR_SETLINKEDUFIS -->\n"; break;
+ case U_EMR_SETTEXTJUSTIFICATION: dbg_str << "<!-- U_EMR_SETTEXTJUSTIFICATION -->\n"; break;
+ case U_EMR_COLORMATCHTOTARGETW: dbg_str << "<!-- U_EMR_COLORMATCHTOTARGETW -->\n"; break;
+ case U_EMR_CREATECOLORSPACEW: dbg_str << "<!-- U_EMR_CREATECOLORSPACEW -->\n"; break;
+ default:
+ dbg_str << "<!-- U_EMR_??? -->\n";
+ break;
+ } //end of switch
+// When testing, uncomment the following to place a comment for each processed EMR record in the SVG
+// *(d->outsvg) += dbg_str.str().c_str();
+ *(d->outsvg) += tmp_outsvg.str().c_str();
+ *(d->path) += tmp_path.str().c_str();
+
+ } //end of while
+// When testing, uncomment the following to show the final SVG derived from the EMF
+// std::cout << *(d->outsvg) << std::endl;
+ (void) emr_properties(U_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
+
+ return 1;
+}
+
+void Emf::free_emf_strings(EMF_STRINGS name){
+ if(name.count){
+ for(int i=0; i< name.count; i++){ free(name.strings[i]); }
+ free(name.strings);
+ }
+}
+
+SPDocument *
+Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
+{
+ EMF_CALLBACK_DATA d;
+
+// memset(&d, 0, sizeof(d));
+ memset(&d, 0, sizeof(EMF_CALLBACK_DATA));
+
+ for(int i = 0; i < EMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with
+ memset(&(d.dc[i]),0,sizeof(EMF_DEVICE_CONTEXT));
+ }
+
+ d.dc[0].worldTransform.eM11 = 1.0;
+ d.dc[0].worldTransform.eM12 = 0.0;
+ d.dc[0].worldTransform.eM21 = 0.0;
+ d.dc[0].worldTransform.eM22 = 1.0;
+ d.dc[0].worldTransform.eDx = 0.0;
+ d.dc[0].worldTransform.eDy = 0.0;
+ d.dc[0].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants
+ d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black)
+ d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white)
+ d.dc[0].bkMode = U_TRANSPARENT;
+ d.dc[0].dirty = 0;
+
+ if (uri == NULL) {
+ return NULL;
+ }
+
+ d.outsvg = new Glib::ustring("");
+ d.path = new Glib::ustring("");
+ d.outdef = new Glib::ustring("");
+ d.defs = new Glib::ustring("");
+ d.mask = 0;
+ d.drawtype = 0;
+ d.arcdir = U_AD_COUNTERCLOCKWISE;
+ d.dwRop2 = U_R2_COPYPEN;
+ d.dwRop3 = 0;
+ d.E2IdirY = 1.0;
+ d.D2PscaleX = 1.0;
+ d.D2PscaleY = 1.0;
+ d.hatches.size = 0;
+ d.hatches.count = 0;
+ d.hatches.strings = NULL;
+ d.images.size = 0;
+ d.images.count = 0;
+ d.images.strings = NULL;
+ d.gradients.size = 0;
+ d.gradients.count = 0;
+ d.gradients.strings = NULL;
+
+ // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
+
+ *(d.defs) += "\n";
+ *(d.defs) += " <pattern id=\"EMFhbasepattern\" \n";
+ *(d.defs) += " patternUnits=\"userSpaceOnUse\"\n";
+ *(d.defs) += " width=\"6\" \n";
+ *(d.defs) += " height=\"6\" \n";
+ *(d.defs) += " x=\"0\" \n";
+ *(d.defs) += " y=\"0\"> \n";
+ *(d.defs) += " </pattern> \n";
+
+
+ size_t length;
+ char *contents;
+ if(emf_readdata(uri, &contents, &length))return(NULL);
+
+ d.pDesc = NULL;
+
+ // set up the text reassembly system
+ if(!(d.tri = trinfo_init(NULL)))return(NULL);
+ (void) trinfo_load_ft_opts(d.tri, 1,
+ FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP,
+ FT_KERNING_UNSCALED);
+
+ (void) myEnhMetaFileProc(contents,length, &d);
+ free(contents);
+
+ if (d.pDesc){ free( d.pDesc ); }
+
+// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
+
+ SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE);
+
+ delete d.outsvg;
+ delete d.path;
+ delete d.outdef;
+ delete d.defs;
+ free_emf_strings(d.hatches);
+ free_emf_strings(d.images);
+ free_emf_strings(d.gradients);
+
+ if (d.emf_obj) {
+ int i;
+ for (i=0; i<d.n_obj; i++)
+ delete_object(&d, i);
+ delete[] d.emf_obj;
+ }
+
+ d.dc[0].style.stroke_dasharray.values.clear();
+
+ for(int i=0; i<=d.level;i++){
+ if(d.dc[i].font_name)free(d.dc[i].font_name);
+ }
+
+ d.tri = trinfo_release_except_FC(d.tri);
+
+ // Set viewBox if it doesn't exist
+ if (doc && !doc->getRoot()->viewBox_set) {
+ bool saved = Inkscape::DocumentUndo::getUndoSensitive(doc);
+ Inkscape::DocumentUndo::setUndoSensitive(doc, false);
+
+ doc->ensureUpToDate();
+
+ // Set document unit
+ Inkscape::XML::Node *repr = sp_document_namedview(doc, 0)->getRepr();
+ Inkscape::SVGOStringStream os;
+ Inkscape::Util::Unit const* doc_unit = doc->getWidth().unit;
+ os << doc_unit->abbr;
+ repr->setAttribute("inkscape:document-units", os.str().c_str());
+
+ // Set viewBox
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc_unit), doc->getHeight().value(doc_unit)));
+ doc->ensureUpToDate();
+
+ // Scale and translate objects
+ double scale = Inkscape::Util::Quantity::convert(1, "px", doc_unit);
+ ShapeEditor::blockSetItem(true);
+ double dh;
+ if(SP_ACTIVE_DOCUMENT){ // for file menu open or import, or paste from clipboard
+ dh = SP_ACTIVE_DOCUMENT->getHeight().value("px");
+ }
+ else { // for open via --file on command line
+ dh = doc->getHeight().value("px");
+ }
+ doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh));
+ ShapeEditor::blockSetItem(false);
+
+ Inkscape::DocumentUndo::setUndoSensitive(doc, saved);
+ }
+
+ return doc;
+}
+
+
+void
+Emf::init (void)
+{
+ /* EMF in */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("EMF Input") "</name>\n"
+ "<id>org.inkscape.input.emf</id>\n"
+ "<input>\n"
+ "<extension>.emf</extension>\n"
+ "<mimetype>image/x-emf</mimetype>\n"
+ "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"
+ "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"
+ "<output_extension>org.inkscape.output.emf</output_extension>\n"
+ "</input>\n"
+ "</inkscape-extension>", new Emf());
+
+ /* EMF out */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("EMF Output") "</name>\n"
+ "<id>org.inkscape.output.emf</id>\n"
+ "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"TnrToSymbol\" gui-text=\"" N_("Map Unicode to Symbol font") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"TnrToWingdings\" gui-text=\"" N_("Map Unicode to Wingdings") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"TnrToZapfDingbats\" gui-text=\"" N_("Map Unicode to Zapf Dingbats") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"UsePUA\" gui-text=\"" N_("Use MS Unicode PUA (0xF020-0xF0FF) for converted characters") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTCharPos\" gui-text=\"" N_("Compensate for PPT font bug") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTDashLine\" gui-text=\"" N_("Convert dashed/dotted lines to single lines") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTGrad2Polys\" gui-text=\"" N_("Convert gradients to colored polygon series") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTLinGrad\" gui-text=\"" N_("Use native rectangular linear gradients") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTPatternAsHatch\" gui-text=\"" N_("Map all fill patterns to standard EMF hatches") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixImageRot\" gui-text=\"" N_("Ignore image rotations") "\" type=\"boolean\">false</param>\n"
+ "<output>\n"
+ "<extension>.emf</extension>\n"
+ "<mimetype>image/x-emf</mimetype>\n"
+ "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"
+ "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>", new Emf());
+
+ return;
+}
+
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h
new file mode 100644
index 000000000..a97cb0a54
--- /dev/null
+++ b/src/extension/internal/emf-inout.h
@@ -0,0 +1,183 @@
+/** @file
+ * @brief Enhanced Metafile Input/Output
+ */
+/* Authors:
+ * Ulf Erikson <ulferikson@users.sf.net>
+ * David Mathog
+ *
+ * Copyright (C) 2006-2008 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+#ifndef SEEN_EXTENSION_INTERNAL_EMF_H
+#define SEEN_EXTENSION_INTERNAL_EMF_H
+
+#include <libuemf/uemf.h>
+#include "extension/internal/metafile-inout.h" // picks up PNG
+#include "extension/implementation/implementation.h"
+#include "style.h"
+#include "text_reassemble.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+#define DIRTY_NONE 0x00
+#define DIRTY_TEXT 0x01
+#define DIRTY_FILL 0x02
+#define DIRTY_STROKE 0x04
+
+typedef struct {
+ int type;
+ int level;
+ char *lpEMFR;
+} EMF_OBJECT, *PEMF_OBJECT;
+
+typedef struct {
+ int size; // number of slots allocated in strings
+ int count; // number of slots used in strings
+ char **strings; // place to store strings
+} EMF_STRINGS, *PEMF_STRINGS;
+
+typedef struct emf_device_context {
+ struct SPStyle style;
+ char *font_name;
+ bool stroke_set;
+ int stroke_mode; // enumeration from drawmode, not used if fill_set is not True
+ int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
+ int stroke_recidx;// record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change
+ bool fill_set;
+ int fill_mode; // enumeration from drawmode, not used if fill_set is not True
+ int fill_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
+ int fill_recidx; // record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change
+ int dirty; // holds the dirty bits for text, stroke, fill
+ U_SIZEL sizeWnd;
+ U_SIZEL sizeView;
+ U_POINTL winorg;
+ U_POINTL vieworg;
+ double ScaleInX, ScaleInY;
+ double ScaleOutX, ScaleOutY;
+ uint16_t bkMode;
+ U_COLORREF bkColor;
+ U_COLORREF textColor;
+ uint32_t textAlign;
+ U_XFORM worldTransform;
+ U_POINTL cur;
+} EMF_DEVICE_CONTEXT, *PEMF_DEVICE_CONTEXT;
+
+#define EMF_MAX_DC 128
+
+typedef struct {
+ Glib::ustring *outsvg;
+ Glib::ustring *path;
+ Glib::ustring *outdef;
+ Glib::ustring *defs;
+
+ EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic..
+ int level;
+
+ double E2IdirY; // EMF Y direction relative to Inkscape Y direction. Will be negative for MM_LOMETRIC etc.
+ double D2PscaleX,D2PscaleY; // EMF device to Inkscape Page scale.
+ float MM100InX, MM100InY; // size of the drawing in hundredths of a millimeter
+ float PixelsInX, PixelsInY; // size of the drawing, in EMF device pixels
+ float PixelsOutX, PixelsOutY; // size of the drawing, in Inkscape pixels
+ double ulCornerInX,ulCornerInY; // Upper left corner, from header rclBounds, in logical units
+ double ulCornerOutX,ulCornerOutY; // Upper left corner, in Inkscape pixels
+ uint32_t mask; // Draw properties
+ int arcdir; //U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2
+
+ uint32_t dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested)
+ uint32_t dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested)
+
+ float MMX;
+ float MMY;
+
+ unsigned int id;
+ unsigned int drawtype; // one of 0 or U_EMR_FILLPATH, U_EMR_STROKEPATH, U_EMR_STROKEANDFILLPATH
+ char *pDesc;
+ // both of these end up in <defs> under the names shown here. These structures allow duplicates to be avoided.
+ EMF_STRINGS hatches; // hold pattern names, all like EMFhatch#_$$$$$$ where # is the EMF hatch code and $$$$$$ is the color
+ EMF_STRINGS images; // hold images, all like Image#, where # is the slot the image lives.
+ EMF_STRINGS gradients; // hold gradient names, all like EMF[HV]_$$$$$$_$$$$$$ where $$$$$$ are the colors
+ TR_INFO *tri; // Text Reassembly data structure
+
+
+ int n_obj;
+ PEMF_OBJECT emf_obj;
+} EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA;
+
+class Emf : public Metafile
+{
+
+public:
+
+ Emf(); // Empty constructor
+
+ virtual ~Emf();//Destructor
+
+ bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now)
+
+ void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename
+ SPDocument *doc,
+ gchar const *filename);
+
+ virtual SPDocument *open( Inkscape::Extension::Input *mod,
+ const gchar *uri );
+
+ static void init(void);//Initialize the class
+
+private:
+
+protected:
+ static void print_document_to_file(SPDocument *doc, const gchar *filename);
+ static double current_scale(PEMF_CALLBACK_DATA d);
+ static std::string current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset);
+ static double current_rotation(PEMF_CALLBACK_DATA d);
+ static void enlarge_hatches(PEMF_CALLBACK_DATA d);
+ static int in_hatches(PEMF_CALLBACK_DATA d, char *test);
+ static uint32_t add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor);
+ static void enlarge_images(PEMF_CALLBACK_DATA d);
+ static int in_images(PEMF_CALLBACK_DATA d, char *test);
+ static uint32_t add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi,
+ uint32_t iUsage, uint32_t offBits, uint32_t offBmi);
+ static void enlarge_gradients(PEMF_CALLBACK_DATA d);
+ static int in_gradients(PEMF_CALLBACK_DATA d, char *test);
+ static uint32_t add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2);
+ static void output_style(PEMF_CALLBACK_DATA d, int iType);
+ static double _pix_x_to_point(PEMF_CALLBACK_DATA d, double px);
+ static double _pix_y_to_point(PEMF_CALLBACK_DATA d, double py);
+ static double pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py);
+ static double pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py);
+ static double pix_to_abs_size(PEMF_CALLBACK_DATA d, double px);
+ static std::string pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y);
+ static void select_pen(PEMF_CALLBACK_DATA d, int index);
+ static void select_extpen(PEMF_CALLBACK_DATA d, int index);
+ static void select_brush(PEMF_CALLBACK_DATA d, int index);
+ static void select_font(PEMF_CALLBACK_DATA d, int index);
+ static void delete_object(PEMF_CALLBACK_DATA d, int index);
+ static void insert_object(PEMF_CALLBACK_DATA d, int index, int type, PU_ENHMETARECORD pObj);
+ static int AI_hack(PU_EMRHEADER pEmr);
+ static uint32_t *unknown_chars(size_t count);
+ static void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr,
+ double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh,
+ uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi);
+ static int myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d);
+ static void free_emf_strings(EMF_STRINGS name);
+
+};
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+
+#endif /* EXTENSION_INTERNAL_EMF_H */
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp
new file mode 100644
index 000000000..f4f7f08cb
--- /dev/null
+++ b/src/extension/internal/emf-print.cpp
@@ -0,0 +1,2061 @@
+/** @file
+ * @brief Enhanced Metafile printing
+ *//*
+ * Authors:
+ * Ulf Erikson <ulferikson@users.sf.net>
+ * Jon A. Cruz <jon@joncruz.org>
+ * Abhishek Sharma
+ * David Mathog
+ *
+ * Copyright (C) 2006-2009 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ *
+ * References:
+ * - How to Create & Play Enhanced Metafiles in Win32
+ * http://support.microsoft.com/kb/q145999/
+ * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
+ * http://support.microsoft.com/kb/q66949/
+ * - Metafile Functions
+ * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
+ * - Metafile Structures
+ * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <glibmm/miscutils.h>
+#include <libuemf/symbol_convert.h>
+#include <2geom/sbasis-to-bezier.h>
+#include <2geom/path.h>
+#include <2geom/pathvector.h>
+#include <2geom/rect.h>
+#include <2geom/curves.h>
+
+#include "helper/geom.h"
+#include "helper/geom-curves.h"
+#include "sp-item.h"
+#include "util/units.h"
+
+#include "style.h"
+#include "inkscape-version.h"
+#include "sp-root.h"
+
+#include "extension/system.h"
+#include "extension/print.h"
+#include "document.h"
+#include "path-prefix.h"
+#include "sp-pattern.h"
+#include "sp-image.h"
+#include "sp-gradient.h"
+#include "sp-radial-gradient.h"
+#include "sp-linear-gradient.h"
+#include "display/cairo-utils.h"
+
+#include "splivarot.h" // pieces for union on shapes
+#include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path
+#include "display/canvas-bpath.h" // for SPWindRule
+
+#include "emf-print.h"
+
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+#define PXPERMETER 2835
+
+
+/* globals */
+static double PX2WORLD;
+static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTLinGrad, FixPPTPatternAsHatch, FixImageRot;
+static EMFTRACK *et = NULL;
+static EMFHANDLES *eht = NULL;
+
+void PrintEmf::smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale)
+{
+ float fdx;
+ int i;
+ uint32_t *ladx;
+ const char *cptr = &string[strlen(string) + 1]; // this works because of the first fake terminator
+
+ *adx = NULL;
+ *ky = 0.0; // set a default value
+ sscanf(cptr, "%7d", ndx);
+ if (!*ndx) {
+ return; // this could happen with an empty string
+ }
+ cptr += 7;
+ ladx = (uint32_t *) malloc(*ndx * sizeof(uint32_t));
+ if (!ladx) {
+ g_message("Out of memory");
+ }
+ *adx = ladx;
+ for (i = 0; i < *ndx; i++, cptr += 7, ladx++) {
+ sscanf(cptr, "%7f", &fdx);
+ *ladx = (uint32_t) round(fdx * scale);
+ }
+ cptr++; // skip 2nd fake terminator
+ sscanf(cptr, "%7f", &fdx);
+ *ky = fdx;
+ cptr += 7; // advance over ky and its space
+ sscanf(cptr, "%07d", rtl);
+}
+
+PrintEmf::PrintEmf()
+{
+ // all of the class variables are initialized elsewhere, many in PrintEmf::Begin,
+}
+
+
+unsigned int PrintEmf::setup(Inkscape::Extension::Print * /*mod*/)
+{
+ return TRUE;
+}
+
+
+unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
+{
+ U_SIZEL szlDev, szlMm;
+ U_RECTL rclBounds, rclFrame;
+ char *rec;
+ gchar const *utf8_fn = mod->get_param_string("destination");
+
+ // Typically PX2WORLD is 1200/90, using inkscape's default dpi
+ PX2WORLD = 1200.0 / Inkscape::Util::Quantity::convert(1.0, "in", "px");
+ FixPPTCharPos = mod->get_param_bool("FixPPTCharPos");
+ FixPPTDashLine = mod->get_param_bool("FixPPTDashLine");
+ FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys");
+ FixPPTLinGrad = mod->get_param_bool("FixPPTLinGrad");
+ FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch");
+ FixImageRot = mod->get_param_bool("FixImageRot");
+
+ (void) emf_start(utf8_fn, 1000000, 250000, &et); // Initialize the et structure
+ (void) htable_create(128, 128, &eht); // Initialize the eht structure
+
+ char *ansi_uri = (char *) utf8_fn;
+
+
+ // width and height in px
+ _width = doc->getWidth().value("px");
+ _height = doc->getHeight().value("px");
+
+ // initialize a few global variables
+ hbrush = hbrushOld = hpen = 0;
+ htextalignment = U_TA_BASELINE | U_TA_LEFT;
+ use_stroke = use_fill = simple_shape = usebk = false;
+
+ Inkscape::XML::Node *nv = sp_repr_lookup_name(doc->rroot, "sodipodi:namedview");
+ if (nv) {
+ const char *p1 = nv->attribute("pagecolor");
+ char *p2;
+ uint32_t lc = strtoul(&p1[1], &p2, 16); // it looks like "#ABC123"
+ if (*p2) {
+ lc = 0;
+ }
+ gv.bgc = _gethexcolor(lc);
+ gv.rgb[0] = (float) U_RGBAGetR(gv.bgc) / 255.0;
+ gv.rgb[1] = (float) U_RGBAGetG(gv.bgc) / 255.0;
+ gv.rgb[2] = (float) U_RGBAGetB(gv.bgc) / 255.0;
+ }
+
+ bool pageBoundingBox;
+ pageBoundingBox = mod->get_param_bool("pageBoundingBox");
+
+ Geom::Rect d;
+ if (pageBoundingBox) {
+ d = Geom::Rect::from_xywh(0, 0, _width, _height);
+ } else {
+ SPItem *doc_item = doc->getRoot();
+ Geom::OptRect bbox = doc_item->desktopVisualBounds();
+ if (bbox) {
+ d = *bbox;
+ }
+ }
+
+ d *= Geom::Scale(Inkscape::Util::Quantity::convert(1, "px", "in"));
+
+ float dwInchesX = d.width();
+ float dwInchesY = d.height();
+
+ // dwInchesX x dwInchesY in micrometer units, 1200 dpi/25.4 -> dpmm
+ (void) drawing_size((int) ceil(dwInchesX * 25.4), (int) ceil(dwInchesY * 25.4),1200.0/25.4, &rclBounds, &rclFrame);
+
+ // set up the reference device as 100 X A4 horizontal, (1200 dpi/25.4 -> dpmm). Extra digits maintain dpi better in EMF
+ int MMX = 216;
+ int MMY = 279;
+ (void) device_size(MMX, MMY, 1200.0 / 25.4, &szlDev, &szlMm);
+ int PixelsX = szlDev.cx;
+ int PixelsY = szlDev.cy;
+
+ // set up the description: (version string)0(file)00
+ char buff[1024];
+ memset(buff, 0, sizeof(buff));
+ char *p1 = strrchr(ansi_uri, '\\');
+ char *p2 = strrchr(ansi_uri, '/');
+ char *p = MAX(p1, p2);
+ if (p) {
+ p++;
+ } else {
+ p = ansi_uri;
+ }
+ snprintf(buff, sizeof(buff) - 1, "Inkscape %s (%s)\1%s\1", Inkscape::version_string, __DATE__, p);
+ uint16_t *Description = U_Utf8ToUtf16le(buff, 0, NULL);
+ int cbDesc = 2 + wchar16len(Description); // also count the final terminator
+ (void) U_Utf16leEdit(Description, '\1', '\0'); // swap the temporary \1 characters for nulls
+
+ // construct the EMRHEADER record and append it to the EMF in memory
+ rec = U_EMRHEADER_set(rclBounds, rclFrame, NULL, cbDesc, Description, szlDev, szlMm, 0);
+ free(Description);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at EMRHEADER");
+ }
+
+
+ // Simplest mapping mode, supply all coordinates in pixels
+ rec = U_EMRSETMAPMODE_set(U_MM_TEXT);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at EMRSETMAPMODE");
+ }
+
+
+ // In earlier versions this was used to scale from inkscape's dpi of 90 to
+ // the files 1200 dpi, taking into account PX2WORLD which was 20. Now PX2WORLD
+ // is set so that this matrix is unitary. The usual value of PX2WORLD is 1200/90,
+ // but might be different if the internal dpi is changed.
+
+ U_XFORM worldTransform;
+ worldTransform.eM11 = 1.0;
+ worldTransform.eM12 = 0.0;
+ worldTransform.eM21 = 0.0;
+ worldTransform.eM22 = 1.0;
+ worldTransform.eDx = 0;
+ worldTransform.eDy = 0;
+
+ rec = U_EMRMODIFYWORLDTRANSFORM_set(worldTransform, U_MWT_LEFTMULTIPLY);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at EMRMODIFYWORLDTRANSFORM");
+ }
+
+
+ if (1) {
+ snprintf(buff, sizeof(buff) - 1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY);
+ rec = textcomment_set(buff);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1");
+ }
+
+ snprintf(buff, sizeof(buff) - 1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, Inkscape::Util::Quantity::convert(dwInchesX, "in", "mm"), Inkscape::Util::Quantity::convert(dwInchesY, "in", "mm"));
+ rec = textcomment_set(buff);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1");
+ }
+ }
+
+ /* set some parameters, else the program that reads the EMF may default to other values */
+
+ rec = U_EMRSETBKMODE_set(U_TRANSPARENT);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at U_EMRSETBKMODE_set");
+ }
+
+ hpolyfillmode = U_WINDING;
+ rec = U_EMRSETPOLYFILLMODE_set(U_WINDING);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at U_EMRSETPOLYFILLMODE_set");
+ }
+
+ // Text alignment: (only changed if RTL text is encountered )
+ // - (x,y) coordinates received by this filter are those of the point where the text
+ // actually starts, and already takes into account the text object's alignment;
+ // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT.
+ htextalignment = U_TA_BASELINE | U_TA_LEFT;
+ rec = U_EMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at U_EMRSETTEXTALIGN_set");
+ }
+
+ htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0;
+ rec = U_EMRSETTEXTCOLOR_set(U_RGB(0, 0, 0));
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at U_EMRSETTEXTCOLOR_set");
+ }
+
+ rec = U_EMRSETROP2_set(U_R2_COPYPEN);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::begin at U_EMRSETROP2_set");
+ }
+
+ /* miterlimit is set with eah pen, so no need to check for it changes as in WMF */
+
+ return 0;
+}
+
+
+unsigned int PrintEmf::finish(Inkscape::Extension::Print * /*mod*/)
+{
+ char *rec;
+ if (!et) {
+ return 0;
+ }
+
+
+ // earlier versions had flush of fill here, but it never executed and was removed
+
+ rec = U_EMREOF_set(0, NULL, et); // generate the EOF record
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::finish");
+ }
+ (void) emf_finish(et, eht); // Finalize and write out the EMF
+ emf_free(&et); // clean up
+ htable_free(&eht); // clean up
+
+ return 0;
+}
+
+
+unsigned int PrintEmf::comment(
+ Inkscape::Extension::Print * /*module*/,
+ const char * /*comment*/)
+{
+ if (!et) {
+ return 0;
+ }
+
+ // earlier versions had flush of fill here, but it never executed and was removed
+
+ return 0;
+}
+
+
+// fcolor is defined when gradients are being expanded, it is the color of one stripe or ring.
+int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
+{
+ float rgb[3];
+ char *rec;
+ U_LOGBRUSH lb;
+ uint32_t brush, fmode;
+ MFDrawMode fill_mode;
+ Inkscape::Pixbuf *pixbuf;
+ uint32_t brushStyle;
+ int hatchType;
+ U_COLORREF hatchColor;
+ U_COLORREF bkColor;
+ uint32_t width = 0; // quiets a harmless compiler warning, initialization not otherwise required.
+ uint32_t height = 0;
+
+ if (!et) {
+ return 0;
+ }
+
+ // set a default fill in case we can't figure out a better way to do it
+ fmode = U_ALTERNATE;
+ fill_mode = DRAW_PAINT;
+ brushStyle = U_BS_SOLID;
+ hatchType = U_HS_SOLIDCLR;
+ bkColor = U_RGB(0, 0, 0);
+ if (fcolor) {
+ hatchColor = *fcolor;
+ } else {
+ hatchColor = U_RGB(0, 0, 0);
+ }
+
+ if (!fcolor && style) {
+ if (style->fill.isColor()) {
+ fill_mode = DRAW_PAINT;
+#if 0
+// opacity not supported by EMF
+ float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
+ if (opacity <= 0.0) {
+ opacity = 0.0; // basically the same as no fill
+ }
+#endif
+ sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
+ hatchColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]);
+
+ fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE);
+ } else if (SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))) { // must be paint-server
+ SPPaintServer *paintserver = style->fill.value.href->getObject();
+ SPPattern *pat = SP_PATTERN(paintserver);
+ double dwidth = pattern_width(pat);
+ double dheight = pattern_height(pat);
+ width = dwidth;
+ height = dheight;
+ brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor);
+ if (pixbuf) {
+ fill_mode = DRAW_IMAGE;
+ } else { // pattern
+ fill_mode = DRAW_PATTERN;
+ if (hatchType == -1) { // Not a standard hatch, so force it to something
+ hatchType = U_HS_CROSS;
+ hatchColor = U_RGB(0xFF, 0xC3, 0xC3);
+ }
+ }
+ if (FixPPTPatternAsHatch) {
+ if (hatchType == -1) { // image or unclassified
+ fill_mode = DRAW_PATTERN;
+ hatchType = U_HS_DIAGCROSS;
+ hatchColor = U_RGB(0xFF, 0xC3, 0xC3);
+ }
+ }
+ brushStyle = U_BS_HATCHED;
+ } else if (SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))) { // must be a gradient
+ // currently we do not do anything with gradients, the code below just sets the color to the average of the stops
+ SPPaintServer *paintserver = style->fill.value.href->getObject();
+ SPLinearGradient *lg = NULL;
+ SPRadialGradient *rg = NULL;
+
+ if (SP_IS_LINEARGRADIENT(paintserver)) {
+ lg = SP_LINEARGRADIENT(paintserver);
+ SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
+ fill_mode = DRAW_LINEAR_GRADIENT;
+ } else if (SP_IS_RADIALGRADIENT(paintserver)) {
+ rg = SP_RADIALGRADIENT(paintserver);
+ SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
+ fill_mode = DRAW_RADIAL_GRADIENT;
+ } else {
+ // default fill
+ }
+
+ if (rg) {
+ if (FixPPTGrad2Polys) {
+ return hold_gradient(rg, fill_mode);
+ } else {
+ hatchColor = avg_stop_color(rg);
+ }
+ } else if (lg) {
+ if (FixPPTGrad2Polys || FixPPTLinGrad) {
+ return hold_gradient(lg, fill_mode);
+ } else {
+ hatchColor = avg_stop_color(lg);
+ }
+ }
+ }
+ } else { // if (!style)
+ // default fill
+ }
+
+ lb = logbrush_set(brushStyle, hatchColor, hatchType);
+
+ switch (fill_mode) {
+ case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices
+ case DRAW_RADIAL_GRADIENT: // ditto
+ case DRAW_PAINT:
+ case DRAW_PATTERN:
+ // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output.
+ if (usebk) {
+ rec = U_EMRSETBKCOLOR_set(bkColor);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKCOLOR_set");
+ }
+ rec = U_EMRSETBKMODE_set(U_OPAQUE);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKMODE_set");
+ }
+ }
+ rec = createbrushindirect_set(&brush, eht, lb);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_brush at createbrushindirect_set");
+ }
+ break;
+ case DRAW_IMAGE:
+ char *px;
+ char *rgba_px;
+ uint32_t cbPx;
+ uint32_t colortype;
+ PU_RGBQUAD ct;
+ int numCt;
+ U_BITMAPINFOHEADER Bmih;
+ PU_BITMAPINFO Bmi;
+ rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!!
+ colortype = U_BCBM_COLOR32;
+ (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1);
+ // Not sure why the next swap is needed because the preceding does it, and the code is identical
+ // to that in stretchdibits_set, which does not need this.
+ swapRBinRGBA(px, width * height);
+ Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
+ Bmi = bitmapinfo_set(Bmih, ct);
+ rec = createdibpatternbrushpt_set(&brush, eht, U_DIB_RGB_COLORS, Bmi, cbPx, px);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_brush at createdibpatternbrushpt_set");
+ }
+ free(px);
+ free(Bmi); // ct will be NULL because of colortype
+ break;
+ }
+
+ hbrush = brush; // need this later for destroy_brush
+ rec = selectobject_set(brush, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_brush at selectobject_set");
+ }
+
+ if (fmode != hpolyfillmode) {
+ hpolyfillmode = fmode;
+ rec = U_EMRSETPOLYFILLMODE_set(fmode);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETPOLYdrawmode_set");
+ }
+ }
+
+ return 0;
+}
+
+
+void PrintEmf::destroy_brush()
+{
+ char *rec;
+ // before an object may be safely deleted it must no longer be selected
+ // select in a stock object to deselect this one, the stock object should
+ // never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work?
+ rec = selectobject_set(U_NULL_BRUSH, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::destroy_brush at selectobject_set");
+ }
+ if (hbrush) {
+ rec = deleteobject_set(&hbrush, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::destroy_brush");
+ }
+ hbrush = 0;
+ }
+}
+
+
+int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
+{
+ U_EXTLOGPEN *elp;
+ U_NUM_STYLEENTRY n_dash = 0;
+ U_STYLEENTRY *dash = NULL;
+ char *rec = NULL;
+ int linestyle = U_PS_SOLID;
+ int linecap = 0;
+ int linejoin = 0;
+ uint32_t pen;
+ uint32_t brushStyle;
+ Inkscape::Pixbuf *pixbuf;
+ int hatchType;
+ U_COLORREF hatchColor;
+ U_COLORREF bkColor;
+ uint32_t width, height;
+ char *px = NULL;
+ char *rgba_px;
+ uint32_t cbPx = 0;
+ uint32_t colortype;
+ PU_RGBQUAD ct = NULL;
+ int numCt = 0;
+ U_BITMAPINFOHEADER Bmih;
+ PU_BITMAPINFO Bmi = NULL;
+
+ if (!et) {
+ return 0;
+ }
+
+ // set a default stroke in case we can't figure out a better way to do it
+ brushStyle = U_BS_SOLID;
+ hatchColor = U_RGB(0, 0, 0);
+ hatchType = U_HS_HORIZONTAL;
+ bkColor = U_RGB(0, 0, 0);
+
+ if (style) {
+ float rgb[3];
+
+ if (SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style))) { // must be paint-server
+ SPPaintServer *paintserver = style->stroke.value.href->getObject();
+ SPPattern *pat = SP_PATTERN(paintserver);
+ double dwidth = pattern_width(pat);
+ double dheight = pattern_height(pat);
+ width = dwidth;
+ height = dheight;
+ brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor);
+ if (pixbuf) {
+ brushStyle = U_BS_DIBPATTERN;
+ rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!!
+ colortype = U_BCBM_COLOR32;
+ (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1);
+ // Not sure why the next swap is needed because the preceding does it, and the code is identical
+ // to that in stretchdibits_set, which does not need this.
+ swapRBinRGBA(px, width * height);
+ Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
+ Bmi = bitmapinfo_set(Bmih, ct);
+ } else { // pattern
+ brushStyle = U_BS_HATCHED;
+ if (usebk) { // OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output.
+ rec = U_EMRSETBKCOLOR_set(bkColor);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETBKCOLOR_set");
+ }
+ rec = U_EMRSETBKMODE_set(U_OPAQUE);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETBKMODE_set");
+ }
+ }
+ if (hatchType == -1) { // Not a standard hatch, so force it to something
+ hatchType = U_HS_CROSS;
+ hatchColor = U_RGB(0xFF, 0xC3, 0xC3);
+ }
+ }
+ if (FixPPTPatternAsHatch) {
+ if (hatchType == -1) { // image or unclassified
+ brushStyle = U_BS_HATCHED;
+ hatchType = U_HS_DIAGCROSS;
+ hatchColor = U_RGB(0xFF, 0xC3, 0xC3);
+ }
+ }
+ } else if (SP_IS_GRADIENT(SP_STYLE_STROKE_SERVER(style))) { // must be a gradient
+ // currently we do not do anything with gradients, the code below has no net effect.
+
+ SPPaintServer *paintserver = style->stroke.value.href->getObject();
+ if (SP_IS_LINEARGRADIENT(paintserver)) {
+ SPLinearGradient *lg = SP_LINEARGRADIENT(paintserver);
+
+ SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
+
+ Geom::Point p1(lg->x1.computed, lg->y1.computed);
+ Geom::Point p2(lg->x2.computed, lg->y2.computed);
+
+ if (lg->gradientTransform_set) {
+ p1 = p1 * lg->gradientTransform;
+ p2 = p2 * lg->gradientTransform;
+ }
+ hatchColor = avg_stop_color(lg);
+ } else if (SP_IS_RADIALGRADIENT(paintserver)) {
+ SPRadialGradient *rg = SP_RADIALGRADIENT(paintserver);
+
+ SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
+ double r = rg->r.computed;
+
+ Geom::Point c(rg->cx.computed, rg->cy.computed);
+ Geom::Point xhandle_point(r, 0);
+ Geom::Point yhandle_point(0, -r);
+ yhandle_point += c;
+ xhandle_point += c;
+ if (rg->gradientTransform_set) {
+ c = c * rg->gradientTransform;
+ yhandle_point = yhandle_point * rg->gradientTransform;
+ xhandle_point = xhandle_point * rg->gradientTransform;
+ }
+ hatchColor = avg_stop_color(rg);
+ } else {
+ // default fill
+ }
+ } else if (style->stroke.isColor()) { // test last, always seems to be set, even for other types above
+ sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
+ brushStyle = U_BS_SOLID;
+ hatchColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]);
+ hatchType = U_HS_SOLIDCLR;
+ } else {
+ // default fill
+ }
+
+
+
+ using Geom::X;
+ using Geom::Y;
+
+ Geom::Point zero(0, 0);
+ Geom::Point one(1, 1);
+ Geom::Point p0(zero * transform);
+ Geom::Point p1(one * transform);
+ Geom::Point p(p1 - p0);
+
+ double scale = sqrt((p[X] * p[X]) + (p[Y] * p[Y])) / sqrt(2);
+
+ if (!style->stroke_width.computed) {
+ return 0; //if width is 0 do not (reset) the pen, it should already be NULL_PEN
+ }
+ uint32_t linewidth = MAX(1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD));
+
+ if (style->stroke_linecap.computed == 0) {
+ linecap = U_PS_ENDCAP_FLAT;
+ } else if (style->stroke_linecap.computed == 1) {
+ linecap = U_PS_ENDCAP_ROUND;
+ } else if (style->stroke_linecap.computed == 2) {
+ linecap = U_PS_ENDCAP_SQUARE;
+ }
+
+ if (style->stroke_linejoin.computed == 0) {
+ linejoin = U_PS_JOIN_MITER;
+ } else if (style->stroke_linejoin.computed == 1) {
+ linejoin = U_PS_JOIN_ROUND;
+ } else if (style->stroke_linejoin.computed == 2) {
+ linejoin = U_PS_JOIN_BEVEL;
+ }
+
+ if (!style->stroke_dasharray.values.empty()) {
+ if (FixPPTDashLine) { // will break up line into many smaller lines. Override gradient if that was set, cannot do both.
+ brushStyle = U_BS_SOLID;
+ hatchType = U_HS_HORIZONTAL;
+ } else {
+ unsigned i = 0;
+ while ((linestyle != U_PS_USERSTYLE) && (i < style->stroke_dasharray.values.size())) {
+ if (style->stroke_dasharray.values[i] > 0.00000001) {
+ linestyle = U_PS_USERSTYLE;
+ }
+ i++;
+ }
+
+ if (linestyle == U_PS_USERSTYLE) {
+ n_dash = style->stroke_dasharray.values.size();
+ dash = new uint32_t[n_dash];
+ for (i = 0; i < n_dash; i++) {
+ dash[i] = (uint32_t)(Inkscape::Util::Quantity::convert(1, "mm", "px") * style->stroke_dasharray.values[i]);
+ }
+ }
+ }
+ }
+
+ elp = extlogpen_set(
+ U_PS_GEOMETRIC | linestyle | linecap | linejoin,
+ linewidth,
+ brushStyle,
+ hatchColor,
+ hatchType,
+ n_dash,
+ dash);
+
+ } else { // if (!style)
+ linejoin = 0;
+ elp = extlogpen_set(
+ linestyle,
+ 1,
+ U_BS_SOLID,
+ U_RGB(0, 0, 0),
+ U_HS_HORIZONTAL,
+ 0,
+ NULL);
+ }
+
+ rec = extcreatepen_set(&pen, eht, Bmi, cbPx, px, elp);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_pen at extcreatepen_set");
+ }
+ free(elp);
+ if (Bmi) {
+ free(Bmi);
+ }
+ if (px) {
+ free(px); // ct will always be NULL
+ }
+
+ rec = selectobject_set(pen, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_pen at selectobject_set");
+ }
+ hpen = pen; // need this later for destroy_pen
+
+ if (linejoin == U_PS_JOIN_MITER) {
+ float miterlimit = style->stroke_miterlimit.value; // This is a ratio.
+
+ if (miterlimit < 1) {
+ miterlimit = 1;
+ }
+
+ rec = U_EMRSETMITERLIMIT_set((uint32_t) miterlimit);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETMITERLIMIT_set");
+ }
+ }
+
+ if (n_dash) {
+ delete[] dash;
+ }
+ return 0;
+}
+
+// set the current pen to the stock object NULL_PEN and then delete the defined pen object, if there is one.
+void PrintEmf::destroy_pen()
+{
+ char *rec = NULL;
+ // before an object may be safely deleted it must no longer be selected
+ // select in a stock object to deselect this one, the stock object should
+ // never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work?
+ rec = selectobject_set(U_NULL_PEN, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::destroy_pen at selectobject_set");
+ }
+ if (hpen) {
+ rec = deleteobject_set(&hpen, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::destroy_pen");
+ }
+ hpen = 0;
+ }
+}
+
+/* Return a Path consisting of just the corner points of the single path in a a PathVector. If the
+PathVector has more than one path, or that one path is open, or any of its segments are curved, then the
+returned PathVector is . If the input path is already just straight lines and vertices the output will be the
+same as the sole path in the input. */
+
+Geom::Path PrintEmf::pathv_to_simple_polygon(Geom::PathVector const &pathv, int *vertices)
+{
+ Geom::Point P1_trail;
+ Geom::Point P1;
+ Geom::Point P1_lead;
+ Geom::Point v1,v2;
+ Geom::Path output;
+ Geom::Path bad;
+ Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv);
+ Geom::PathVector::const_iterator pit = pv.begin();
+ Geom::PathVector::const_iterator pit2 = pv.begin();
+ ++pit2;
+ *vertices = 0;
+ if(pit->end_closed() != pit->end_default())return(bad); // path must be closed
+ if(pit2 != pv.end())return(bad); // there may only be one path
+ P1_trail = pit->finalPoint();
+ Geom::Path::const_iterator cit = pit->begin();
+ P1 = cit->initialPoint();
+ for(;cit != pit->end_closed();++cit) {
+ if (!is_straight_curve(*cit)) {
+ *vertices = 0;
+ return(bad);
+ }
+ P1_lead = cit->finalPoint();
+ if(Geom::are_near(P1_lead, P1, 1e-5))continue; // duplicate points at the same coordinate
+ v1 = unit_vector(P1 - P1_trail);
+ v2 = unit_vector(P1_lead - P1 );
+ if(Geom::are_near(dot(v1,v2), 1.0, 1e-5)){ // P1 is within a straight line
+ P1 = P1_lead;
+ continue;
+ }
+ // P1 is the center point of a turn of some angle
+ if(!*vertices){
+ output.start( P1 );
+ output.close( pit->closed() );
+ }
+ *vertices += 1;
+ Geom::LineSegment ls(P1_trail, P1);
+ output.append(ls);
+ P1_trail = P1;
+ P1 = P1_lead;
+ }
+ return(output);
+}
+
+/* Returns the simplified PathVector (no matter what).
+ Sets is_rect if it is a rectangle.
+ Sets angle that will rotate side closest to horizontal onto horizontal.
+*/
+Geom::Path PrintEmf::pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, double *angle)
+{
+ Geom::Point P1_trail;
+ Geom::Point P1;
+ Geom::Point P1_lead;
+ Geom::Point v1,v2;
+ int vertices;
+ Geom::Path pR = pathv_to_simple_polygon(pathv, &vertices);
+ *is_rect = false;
+ if(vertices==4){ // or else it cannot be a rectangle
+ int vertex_count=0;
+ /* Get the ends of the LAST line segment.
+ Find minimum rotation to align rectangle with X,Y axes. (Very degenerate if it is rotated 45 degrees.) */
+ *angle = 10.0; /* must be > than the actual angle in radians. */
+ for(Geom::Path::const_iterator cit = pR.begin(); cit != pR.end_open(); ++cit){
+ P1_trail = cit->initialPoint();
+ P1 = cit->finalPoint();
+ v1 = unit_vector(P1 - P1_trail);
+ if(v1[Geom::X] > 0){ // only check the 1 or 2 points on vectors aimed the same direction as unit X
+ double ang = asin(v1[Geom::Y]); // because component is rotation by ang of {1,0| vector
+ if(fabs(ang) < fabs(*angle))*angle = -ang; // y increases down, flips sign on angle
+ }
+ }
+
+ /* For increased numerical stability, snap the angle to the nearest 1/100th of a degree. */
+ double convert = 36000.0/ (2.0 * M_PI);
+ *angle = round(*angle * convert)/convert;
+
+ for(Geom::Path::const_iterator cit = pR.begin(); cit != pR.end_open();++cit) {
+ P1_lead = cit->finalPoint();
+ v1 = unit_vector(P1 - P1_trail);
+ v2 = unit_vector(P1_lead - P1 );
+ // P1 is center of a turn that is not 90 degrees. Limit comes from cos(89.9) = .001745
+ if(!Geom::are_near(dot(v1,v2), 0.0, 2e-3))break;
+ P1_trail = P1;
+ P1 = P1_lead;
+ vertex_count++;
+ }
+ if(vertex_count == 4){
+ *is_rect=true;
+ }
+ }
+ return(pR);
+}
+
+/* Compare a vector with a rectangle's orientation (angle needed to rotate side(s)
+ closest to horizontal to exactly horizontal) and return:
+ 0 none of the following
+ 1 parallel to horizontal
+ 2 parallel to vertical
+ 3 antiparallel to horizontal
+ 4 antiparallel to vertical
+*/
+int PrintEmf::vector_rect_alignment(double angle, Geom::Point vtest){
+ int stat = 0;
+ Geom::Point v1 = Geom::unit_vector(vtest); // unit vector to test alignment
+ Geom::Point v2 = Geom::Point(1,0) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN)
+ if( Geom::are_near(dot(v1,v2), 1.0, 1e-5)){ stat = 1; }
+ else if(Geom::are_near(dot(v1,v2),-1.0, 1e-5)){ stat = 2; }
+ if(!stat){
+ v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side
+ if( Geom::are_near(dot(v1,v2), 1.0, 1e-5)){ stat = 3; }
+ else if(Geom::are_near(dot(v1,v2),-1.0, 1e-5)){ stat = 4; }
+ }
+ return(stat);
+}
+
+/* retrieve the point at the indicated corner:
+ 0 UL (and default)
+ 1 UR
+ 2 LR
+ 3 LL
+ Needed because the start can be any point, and the direction could run either
+ clockwise or counterclockwise. This should work even if the corners of the rectangle
+ are slightly displaced.
+*/
+Geom::Point PrintEmf::get_pathrect_corner(Geom::Path pathRect, double angle, int corner){
+ Geom::Point center(0,0);
+ for(Geom::Path::const_iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) {
+ center += cit->initialPoint()/4.0;
+ }
+
+ int LR; // 1 if Left, 0 if Right
+ int UL; // 1 if Lower, 0 if Upper (as viewed on screen, y coordinates increase downwards)
+ switch(corner){
+ case 1: //UR
+ LR = 0;
+ UL = 0;
+ break;
+ case 2: //LR
+ LR = 0;
+ UL = 1;
+ break;
+ case 3: //LL
+ LR = 1;
+ UL = 1;
+ break;
+ default: //UL
+ LR = 1;
+ UL = 0;
+ break;
+ }
+
+ Geom::Point v1 = Geom::Point(1,0) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN)
+ Geom::Point v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side (sign change because Y increases DOWN)
+ Geom::Point P1;
+ for(Geom::Path::const_iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) {
+ P1 = cit->initialPoint();
+
+ if ( ( LR == (dot(P1 - center,v1) > 0 ? 0 : 1) )
+ && ( UL == (dot(P1 - center,v2) > 0 ? 1 : 0) ) ) break;
+ }
+ return(P1);
+}
+
+U_TRIVERTEX PrintEmf::make_trivertex(Geom::Point Pt, U_COLORREF uc){
+ U_TRIVERTEX tv;
+ using Geom::X;
+ using Geom::Y;
+ tv.x = (int32_t) round(Pt[X]);
+ tv.y = (int32_t) round(Pt[Y]);
+ tv.Red = uc.Red << 8;
+ tv.Green = uc.Green << 8;
+ tv.Blue = uc.Blue << 8;
+ tv.Alpha = uc.Reserved << 8; // EMF will ignore this
+ return(tv);
+}
+
+unsigned int PrintEmf::fill(
+ Inkscape::Extension::Print * /*mod*/,
+ Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style,
+ Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
+{
+ using Geom::X;
+ using Geom::Y;
+
+ Geom::Affine tf = m_tr_stack.top();
+
+ use_fill = true;
+ use_stroke = false;
+
+ fill_transform = tf;
+
+ int brush_stat = create_brush(style, NULL);
+
+ /* native linear gradients are only used if the object is a rectangle AND the gradient is parallel to the sides of the object */
+ bool is_Rect = false;
+ double angle;
+ int rectDir=0;
+ Geom::Path pathRect;
+ if(FixPPTLinGrad && brush_stat && gv.mode == DRAW_LINEAR_GRADIENT){
+ Geom::PathVector pvr = pathv * fill_transform;
+ pathRect = pathv_to_rect(pvr, &is_Rect, &angle);
+ if(is_Rect){
+ /* Gradientfill records can only be used if the gradient is parallel to the sides of the rectangle.
+ That must be checked here so that we can fall back to another form of gradient fill if it is not
+ the case. */
+ rectDir = vector_rect_alignment(angle, (gv.p2 - gv.p1) * fill_transform);
+ if(!rectDir)is_Rect = false;
+ }
+ if(!is_Rect && !FixPPTGrad2Polys)brush_stat=0; // fall all the way back to a solid fill
+ }
+
+ if (brush_stat) { // only happens if the style is a gradient
+ /*
+ Handle gradients. Uses modified livarot as 2geom boolops is currently broken.
+ Can handle gradients with multiple stops.
+
+ The overlap is needed to avoid antialiasing artifacts when edges are not strictly aligned on pixel boundaries.
+ There is an inevitable loss of accuracy saving through an EMF file because of the integer coordinate system.
+ Keep the overlap quite large so that loss of accuracy does not remove an overlap.
+ */
+ destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below
+ Geom::Path cutter;
+ float rgb[3];
+ U_COLORREF wc, c1, c2;
+ FillRule frb = SPWR_to_LVFR((SPWindRule) style->fill_rule.computed);
+ double doff, doff_base, doff_range;
+ double divisions = 128.0;
+ int nstops;
+ int istop = 1;
+ float opa; // opacity at stop
+
+ SPRadialGradient *tg = (SPRadialGradient *)(gv.grad); // linear/radial are the same here
+ nstops = tg->vector.stops.size();
+ sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb);
+ opa = tg->vector.stops[0].opacity; // first stop
+ c1 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+ sp_color_get_rgb_floatv(&tg->vector.stops[nstops - 1].color, rgb);
+ opa = tg->vector.stops[nstops - 1].opacity; // last stop
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+
+ doff = 0.0;
+ doff_base = 0.0;
+ doff_range = tg->vector.stops[1].offset; // next or last stop
+
+ if (gv.mode == DRAW_RADIAL_GRADIENT) {
+ Geom::Point xv = gv.p2 - gv.p1; // X' vector
+ Geom::Point yv = gv.p3 - gv.p1; // Y' vector
+ Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector
+ double rx = hypot(xv[X], xv[Y]);
+ double ry = hypot(yv[X], yv[Y]);
+ double range = fmax(rx, ry); // length along the gradient
+ double step = range / divisions; // adequate approximation for gradient
+ double overlap = step / 4.0; // overlap slices slightly
+ double start;
+ double stop;
+ Geom::PathVector pathvc, pathvr;
+
+ /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity".
+ Do this first so that outer colored ring will overlay it.
+ */
+ pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx * (1.0 - overlap / range), ry * (1.0 - overlap / range), asin(xuv[Y]));
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb);
+ wc = weight_opacity(c2);
+ (void) create_brush(style, &wc);
+ print_pathv(pathvr, fill_transform);
+
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+
+ for (start = 0.0; start < range; start += step, doff += 1. / divisions) {
+ stop = start + step + overlap;
+ if (stop > range) {
+ stop = range;
+ }
+ wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base));
+ (void) create_brush(style, &wc);
+
+ pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx * start / range, ry * start / range, rx * stop / range, ry * stop / range, asin(xuv[Y]));
+
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform); // show the intersection
+
+ if (doff >= doff_range) {
+ istop++;
+ if (istop >= nstops) {
+ istop = nstops - 1;
+ continue; // could happen on a rounding error
+ }
+ doff_base = doff_range;
+ doff_range = tg->vector.stops[istop].offset; // next or last stop
+ c1 = c2;
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+ }
+ }
+ } else if (gv.mode == DRAW_LINEAR_GRADIENT) {
+ if(is_Rect){
+ char *rec;
+ int gMode;
+ Geom::Point ul, ur, lr;
+ Geom::Point outUL, outLR; // UL,LR corners of a stop rectangle, in OUTPUT coordinates
+ U_TRIVERTEX ut[2];
+ U_GRADIENT4 ug4;
+ U_RECTL rcb;
+ U_XFORM tmpTransform;
+ double wRect, hRect;
+
+ /* coordinates: upper left, upper right, and lower right corners of the rectangle.
+ inkscape transform already applied, but needs to be scaled to EMF coordinates. */
+ ul = get_pathrect_corner(pathRect, angle, 0) * PX2WORLD;
+ ur = get_pathrect_corner(pathRect, angle, 1) * PX2WORLD;
+ lr = get_pathrect_corner(pathRect, angle, 2) * PX2WORLD;
+ wRect = Geom::distance(ul,ur);
+ hRect = Geom::distance(ur,lr);
+
+ /* The basic rectangle for all of these is placed with its UL corner at 0,0 with a size wRect,hRect.
+ Apply a world transform to place/scale it into the appropriate position on the drawing.
+ Actual gradientfill records are either this entire rectangle or slices of it as defined by the stops.
+ This rectangle has already been transformed by tf (whatever rotation/scale) Inkscape had applied to it.
+ */
+
+ Geom::Affine tf2 = Geom::Rotate(-angle); // the rectangle may be drawn skewed to the coordinate system
+ tmpTransform.eM11 = tf2[0];
+ tmpTransform.eM12 = tf2[1];
+ tmpTransform.eM21 = tf2[2];
+ tmpTransform.eM22 = tf2[3];
+ tmpTransform.eDx = round((ul)[Geom::X]); // use explicit round for better stability
+ tmpTransform.eDy = round((ul)[Geom::Y]);
+
+ rec = U_EMRSAVEDC_set();
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set");
+ }
+
+ rec = U_EMRMODIFYWORLDTRANSFORM_set(tmpTransform, U_MWT_LEFTMULTIPLY);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at EMRMODIFYWORLDTRANSFORM");
+ }
+
+ for(;istop<nstops;istop++){
+ doff_range = tg->vector.stops[istop].offset; // next or last stop
+ if(rectDir == 1 || rectDir == 2){
+ outUL = Geom::Point(doff_base *wRect, 0 );
+ outLR = Geom::Point(doff_range*wRect, hRect);
+ gMode = U_GRADIENT_FILL_RECT_H;
+ }
+ else {
+ outUL = Geom::Point(0, doff_base *hRect);
+ outLR = Geom::Point(wRect,doff_range*hRect);
+ gMode = U_GRADIENT_FILL_RECT_V;
+ }
+ doff_base = doff_range;
+ rcb.left = round(outUL[X]); // use explicit round for better stability
+ rcb.top = round(outUL[Y]);
+ rcb.right = round(outLR[X]);
+ rcb.bottom = round(outLR[Y]);
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+
+ if(rectDir == 2 || rectDir == 4){ // gradient is reversed, so swap colors
+ ut[0] = make_trivertex(outUL, c2);
+ ut[1] = make_trivertex(outLR, c1);
+ }
+ else {
+ ut[0] = make_trivertex(outUL, c1);
+ ut[1] = make_trivertex(outLR, c2);
+ }
+ c1 = c2; // for next stop
+ ug4.UpperLeft = 0;
+ ug4.LowerRight= 1;
+ rec = U_EMRGRADIENTFILL_set(rcb, 2, 1, gMode, ut, (uint32_t *) &ug4 );
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::fill at U_EMRGRADIENTFILL_set");
+ }
+ }
+
+ rec = U_EMRRESTOREDC_set(-1);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::fill at U_EMRRESTOREDC_set");
+ }
+ }
+ else {
+ Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector
+ Geom::Point puv = uv.cw(); // perp. to unit vector
+ double range = Geom::distance(gv.p1, gv.p2); // length along the gradient
+ double step = range / divisions; // adequate approximation for gradient
+ double overlap = step / 4.0; // overlap slices slightly
+ double start;
+ double stop;
+ Geom::PathVector pathvc, pathvr;
+
+ /* before lower end of gradient, overlap first slice position */
+ wc = weight_opacity(c1);
+ (void) create_brush(style, &wc);
+ pathvc = rect_cutter(gv.p1, uv * (overlap), uv * (-50000.0), puv * 50000.0);
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform);
+
+ /* after high end of gradient, overlap last slice position */
+ wc = weight_opacity(c2);
+ (void) create_brush(style, &wc);
+ pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0);
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform);
+
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+
+ for (start = 0.0; start < range; start += step, doff += 1. / divisions) {
+ stop = start + step + overlap;
+ if (stop > range) {
+ stop = range;
+ }
+ pathvc = rect_cutter(gv.p1, uv * start, uv * stop, puv * 50000.0);
+
+ wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base));
+ (void) create_brush(style, &wc);
+ Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform); // show the intersection
+
+ if (doff >= doff_range) {
+ istop++;
+ if (istop >= nstops) {
+ istop = nstops - 1;
+ continue; // could happen on a rounding error
+ }
+ doff_base = doff_range;
+ doff_range = tg->vector.stops[istop].offset; // next or last stop
+ c1 = c2;
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+ }
+ }
+ }
+ } else {
+ g_error("Fatal programming error in PrintEmf::fill, invalid gradient type detected");
+ }
+ use_fill = false; // gradients handled, be sure stroke does not use stroke and fill
+ } else {
+ /*
+ Inkscape was not calling create_pen for objects with no border.
+ This was because it never called stroke() (next method).
+ PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can
+ become a visible border.
+ To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill.
+ */
+ if (style->stroke.noneSet || style->stroke_width.computed == 0.0) {
+ destroy_pen(); //this sets the NULL_PEN
+ }
+
+ /* postpone fill in case stroke also required AND all stroke paths closed
+ Dashes converted to line segments will "open" a closed path.
+ */
+ bool all_closed = true;
+ for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) {
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
+ if (pit->end_default() != pit->end_closed()) {
+ all_closed = false;
+ }
+ }
+ }
+ if (
+ (style->stroke.isNone() || style->stroke.noneSet || style->stroke_width.computed == 0.0) ||
+ (!style->stroke_dasharray.values.empty() && FixPPTDashLine) ||
+ !all_closed
+ ) {
+ print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv
+ use_fill = false;
+ }
+ }
+
+ return 0;
+}
+
+
+unsigned int PrintEmf::stroke(
+ Inkscape::Extension::Print * /*mod*/,
+ Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style,
+ Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
+{
+
+ char *rec = NULL;
+ Geom::Affine tf = m_tr_stack.top();
+
+ use_stroke = true;
+ // use_fill was set in ::fill, if it is needed
+
+ if (create_pen(style, tf)) {
+ return 0;
+ }
+
+ if (!style->stroke_dasharray.values.empty() && FixPPTDashLine) {
+ // convert the path, gets its complete length, and then make a new path with parameter length instead of t
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end
+ int n_dash = style->stroke_dasharray.values.size();
+ int i = 0; //dash index
+ double tlength; // length of tmp_pathpw
+ double slength = 0.0; // start of gragment
+ double elength; // end of gragment
+ for (unsigned int i = 0; i < pathv.size(); i++) {
+ tmp_pathpw.concat(pathv[i].toPwSb());
+ }
+ tlength = length(tmp_pathpw, 0.1);
+ tmp_pathpw2 = arc_length_parametrization(tmp_pathpw);
+
+ // go around the dash array repeatedly until the entire path is consumed (but not beyond).
+ while (slength < tlength) {
+ elength = slength + style->stroke_dasharray.values[i++];
+ if (elength > tlength) {
+ elength = tlength;
+ }
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength));
+ if (slength) {
+ tmp_pathpw3.concat(fragment);
+ } else {
+ first_frag = fragment;
+ }
+ slength = elength;
+ slength += style->stroke_dasharray.values[i++]; // the gap
+ if (i >= n_dash) {
+ i = 0;
+ }
+ }
+ tmp_pathpw3.concat(first_frag); // may merge line around start point
+ Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01);
+ print_pathv(out_pathv, tf);
+ } else {
+ print_pathv(pathv, tf);
+ }
+
+ use_stroke = false;
+ use_fill = false;
+
+ if (usebk) { // OPAQUE was set, revert to TRANSPARENT
+ usebk = false;
+ rec = U_EMRSETBKMODE_set(U_TRANSPARENT);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::stroke at U_EMRSETBKMODE_set");
+ }
+ }
+
+ return 0;
+}
+
+
+// Draws simple_shapes, those with closed EMR_* primitives, like polygons, rectangles and ellipses.
+// These use whatever the current pen/brush are and need not be followed by a FILLPATH or STROKEPATH.
+// For other paths it sets a few flags and returns.
+bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform)
+{
+
+ Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * transform);
+
+ int nodes = 0;
+ int moves = 0;
+ int lines = 0;
+ int curves = 0;
+ char *rec = NULL;
+
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
+ moves++;
+ nodes++;
+
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
+ nodes++;
+
+ if (is_straight_curve(*cit)) {
+ lines++;
+ } else if (&*cit) {
+ curves++;
+ }
+ }
+ }
+
+ if (!nodes) {
+ return false;
+ }
+
+ U_POINT *lpPoints = new U_POINT[moves + lines + curves * 3];
+ int i = 0;
+
+ /**
+ * For all Subpaths in the <path>
+ */
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
+ using Geom::X;
+ using Geom::Y;
+
+ Geom::Point p0 = pit->initialPoint();
+
+ p0[X] = (p0[X] * PX2WORLD);
+ p0[Y] = (p0[Y] * PX2WORLD);
+
+ int32_t const x0 = (int32_t) round(p0[X]);
+ int32_t const y0 = (int32_t) round(p0[Y]);
+
+ lpPoints[i].x = x0;
+ lpPoints[i].y = y0;
+ i = i + 1;
+
+ /**
+ * For all segments in the subpath
+ */
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
+ if (is_straight_curve(*cit)) {
+ //Geom::Point p0 = cit->initialPoint();
+ Geom::Point p1 = cit->finalPoint();
+
+ //p0[X] = (p0[X] * PX2WORLD);
+ p1[X] = (p1[X] * PX2WORLD);
+ //p0[Y] = (p0[Y] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
+ int32_t const x1 = (int32_t) round(p1[X]);
+ int32_t const y1 = (int32_t) round(p1[Y]);
+
+ lpPoints[i].x = x1;
+ lpPoints[i].y = y1;
+ i = i + 1;
+ } else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*cit)) {
+ std::vector<Geom::Point> points = cubic->points();
+ //Geom::Point p0 = points[0];
+ Geom::Point p1 = points[1];
+ Geom::Point p2 = points[2];
+ Geom::Point p3 = points[3];
+
+ //p0[X] = (p0[X] * PX2WORLD);
+ p1[X] = (p1[X] * PX2WORLD);
+ p2[X] = (p2[X] * PX2WORLD);
+ p3[X] = (p3[X] * PX2WORLD);
+ //p0[Y] = (p0[Y] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ p2[Y] = (p2[Y] * PX2WORLD);
+ p3[Y] = (p3[Y] * PX2WORLD);
+
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
+ int32_t const x1 = (int32_t) round(p1[X]);
+ int32_t const y1 = (int32_t) round(p1[Y]);
+ int32_t const x2 = (int32_t) round(p2[X]);
+ int32_t const y2 = (int32_t) round(p2[Y]);
+ int32_t const x3 = (int32_t) round(p3[X]);
+ int32_t const y3 = (int32_t) round(p3[Y]);
+
+ lpPoints[i].x = x1;
+ lpPoints[i].y = y1;
+ lpPoints[i + 1].x = x2;
+ lpPoints[i + 1].y = y2;
+ lpPoints[i + 2].x = x3;
+ lpPoints[i + 2].y = y3;
+ i = i + 3;
+ }
+ }
+ }
+
+ bool done = false;
+ bool closed = (lpPoints[0].x == lpPoints[i - 1].x) && (lpPoints[0].y == lpPoints[i - 1].y);
+ bool polygon = false;
+ bool rectangle = false;
+ bool ellipse = false;
+
+ if (moves == 1 && moves + lines == nodes && closed) {
+ polygon = true;
+ // if (nodes==5) { // disable due to LP Bug 407394
+ // if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x &&
+ // lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y)
+ // {
+ // rectangle = true;
+ // }
+ // }
+ } else if (moves == 1 && nodes == 5 && moves + curves == nodes && closed) {
+ // if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
+ // lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
+ // lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
+ // lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
+ // lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
+ // lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
+ // { // disable due to LP Bug 407394
+ // ellipse = true;
+ // }
+ }
+
+ if (polygon || ellipse) {
+
+ if (use_fill && !use_stroke) { // only fill
+ rec = selectobject_set(U_NULL_PEN, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen");
+ }
+ } else if (!use_fill && use_stroke) { // only stroke
+ rec = selectobject_set(U_NULL_BRUSH, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush");
+ }
+ }
+
+ if (polygon) {
+ if (rectangle) {
+ U_RECTL rcl = rectl_set((U_POINTL) {
+ lpPoints[0].x, lpPoints[0].y
+ }, (U_POINTL) {
+ lpPoints[2].x, lpPoints[2].y
+ });
+ rec = U_EMRRECTANGLE_set(rcl);
+ } else {
+ rec = U_EMRPOLYGON_set(U_RCL_DEF, nodes, lpPoints);
+ }
+ } else if (ellipse) {
+ U_RECTL rcl = rectl_set((U_POINTL) {
+ lpPoints[6].x, lpPoints[3].y
+ }, (U_POINTL) {
+ lpPoints[0].x, lpPoints[9].y
+ });
+ rec = U_EMRELLIPSE_set(rcl);
+ }
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at retangle/ellipse/polygon");
+ }
+
+ done = true;
+
+ // replace the handle we moved above, assuming there was something set already
+ if (use_fill && !use_stroke && hpen) { // only fill
+ rec = selectobject_set(hpen, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen");
+ }
+ } else if (!use_fill && use_stroke && hbrush) { // only stroke
+ rec = selectobject_set(hbrush, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush");
+ }
+ }
+ }
+
+ delete[] lpPoints;
+
+ return done;
+}
+
+/** Some parts based on win32.cpp by Lauris Kaplinski <lauris@kaplinski.com>. Was a part of Inkscape
+ in the past (or will be in the future?) Not in current trunk. (4/19/2012)
+
+ Limitations of this code:
+ 1. Transparency is lost on export. (Apparently a limitation of the EMF format.)
+ 2. Probably messes up if row stride != w*4
+ 3. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine
+ that calls this one and passes px, but never removes the rest of the pixbuf. The first time
+ this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more.
+ If this routine is reduced to
+ if(1)return(0);
+ and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the
+ size of two bitmaps.
+*/
+
+unsigned int PrintEmf::image(
+ Inkscape::Extension::Print * /* module */, /** not used */
+ unsigned char *rgba_px, /** array of pixel values, Gdk::Pixbuf bitmap format */
+ unsigned int w, /** width of bitmap */
+ unsigned int h, /** height of bitmap */
+ unsigned int rs, /** row stride (normally w*4) */
+ Geom::Affine const &tf_rect, /** affine transform only used for defining location and size of rect, for all other tranforms, use the one from m_tr_stack */
+ SPStyle const * /*style*/) /** provides indirect link to image object */
+{
+ double x1, y1, dw, dh;
+ char *rec = NULL;
+ Geom::Affine tf = m_tr_stack.top();
+
+ rec = U_EMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at EMRHEADER");
+ }
+
+ x1 = tf_rect[4];
+ y1 = tf_rect[5];
+ dw = ((double) w) * tf_rect[0];
+ dh = ((double) h) * tf_rect[3];
+ Geom::Point pLL(x1, y1);
+ Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates
+
+ char *px;
+ uint32_t cbPx;
+ uint32_t colortype;
+ PU_RGBQUAD ct;
+ int numCt;
+ U_BITMAPINFOHEADER Bmih;
+ PU_BITMAPINFO Bmi;
+ colortype = U_BCBM_COLOR32;
+ (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w * 4, colortype, 0, 1);
+ Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
+ Bmi = bitmapinfo_set(Bmih, ct);
+
+ U_POINTL Dest = pointl_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD));
+ U_POINTL cDest = pointl_set(round(dw * PX2WORLD), round(dh * PX2WORLD));
+ U_POINTL Src = pointl_set(0, 0);
+ U_POINTL cSrc = pointl_set(w, h);
+ /* map the integer Dest coordinates back into pLL2, so that the rounded part does not destabilize the transform offset below */
+ pLL2[Geom::X] = Dest.x;
+ pLL2[Geom::Y] = Dest.y;
+ pLL2 /= PX2WORLD;
+ if (!FixImageRot) { /* Rotate images - some programs cannot read them in correctly if they are rotated */
+ tf[4] = tf[5] = 0.0; // get rid of the offset in the transform
+ Geom::Point pLL2prime = pLL2 * tf;
+ U_XFORM tmpTransform;
+ tmpTransform.eM11 = tf[0];
+ tmpTransform.eM12 = tf[1];
+ tmpTransform.eM21 = tf[2];
+ tmpTransform.eM22 = tf[3];
+ tmpTransform.eDx = (pLL2[Geom::X] - pLL2prime[Geom::X]) * PX2WORLD;
+ tmpTransform.eDy = (pLL2[Geom::Y] - pLL2prime[Geom::Y]) * PX2WORLD;
+
+ rec = U_EMRSAVEDC_set();
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set");
+ }
+
+ rec = U_EMRMODIFYWORLDTRANSFORM_set(tmpTransform, U_MWT_LEFTMULTIPLY);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at EMRMODIFYWORLDTRANSFORM");
+ }
+ }
+ rec = U_EMRSTRETCHDIBITS_set(
+ U_RCL_DEF, //! Bounding rectangle in device units
+ Dest, //! Destination UL corner in logical units
+ cDest, //! Destination W & H in logical units
+ Src, //! Source UL corner in logical units
+ cSrc, //! Source W & H in logical units
+ U_DIB_RGB_COLORS, //! DIBColors Enumeration
+ U_SRCCOPY, //! RasterOPeration Enumeration
+ Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section)
+ h * rs, //! size in bytes of px
+ px //! (Optional) bitmapbuffer (U_BITMAPINFO section)
+ );
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at U_EMRSTRETCHDIBITS_set");
+ }
+ free(px);
+ free(Bmi);
+ if (numCt) {
+ free(ct);
+ }
+
+ if (!FixImageRot) {
+ rec = U_EMRRESTOREDC_set(-1);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at U_EMRRESTOREDC_set");
+ }
+ }
+
+ return 0;
+}
+
+// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything
+unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform)
+{
+ Geom::Affine tf = transform;
+ char *rec = NULL;
+
+ simple_shape = print_simple_shape(pathv, tf);
+ if (simple_shape || pathv.empty()) {
+ if (use_fill) {
+ destroy_brush(); // these must be cleared even if nothing is drawn or hbrush,hpen fill up
+ }
+ if (use_stroke) {
+ destroy_pen();
+ }
+ return TRUE;
+ }
+
+ /* inkscape to EMF scaling is done below, but NOT the rotation/translation transform,
+ that is handled by the EMF MODIFYWORLDTRANSFORM record
+ */
+
+ Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * tf);
+
+ rec = U_EMRBEGINPATH_set();
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRBEGINPATH_set");
+ }
+
+ /**
+ * For all Subpaths in the <path>
+ */
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
+ using Geom::X;
+ using Geom::Y;
+
+
+ Geom::Point p0 = pit->initialPoint();
+
+ p0[X] = (p0[X] * PX2WORLD);
+ p0[Y] = (p0[Y] * PX2WORLD);
+
+ U_POINTL ptl = pointl_set((int32_t) round(p0[X]), (int32_t) round(p0[Y]));
+ rec = U_EMRMOVETOEX_set(ptl);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRMOVETOEX_set");
+ }
+
+ /**
+ * For all segments in the subpath
+ */
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
+ if (is_straight_curve(*cit)) {
+ //Geom::Point p0 = cit->initialPoint();
+ Geom::Point p1 = cit->finalPoint();
+
+ //p0[X] = (p0[X] * PX2WORLD);
+ p1[X] = (p1[X] * PX2WORLD);
+ //p0[Y] = (p0[Y] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
+
+ ptl = pointl_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
+ rec = U_EMRLINETO_set(ptl);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRLINETO_set");
+ }
+ } else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*cit)) {
+ std::vector<Geom::Point> points = cubic->points();
+ //Geom::Point p0 = points[0];
+ Geom::Point p1 = points[1];
+ Geom::Point p2 = points[2];
+ Geom::Point p3 = points[3];
+
+ //p0[X] = (p0[X] * PX2WORLD);
+ p1[X] = (p1[X] * PX2WORLD);
+ p2[X] = (p2[X] * PX2WORLD);
+ p3[X] = (p3[X] * PX2WORLD);
+ //p0[Y] = (p0[Y] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ p2[Y] = (p2[Y] * PX2WORLD);
+ p3[Y] = (p3[Y] * PX2WORLD);
+
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
+ int32_t const x1 = (int32_t) round(p1[X]);
+ int32_t const y1 = (int32_t) round(p1[Y]);
+ int32_t const x2 = (int32_t) round(p2[X]);
+ int32_t const y2 = (int32_t) round(p2[Y]);
+ int32_t const x3 = (int32_t) round(p3[X]);
+ int32_t const y3 = (int32_t) round(p3[Y]);
+
+ U_POINTL pt[3];
+ pt[0].x = x1;
+ pt[0].y = y1;
+ pt[1].x = x2;
+ pt[1].y = y2;
+ pt[2].x = x3;
+ pt[2].y = y3;
+
+ rec = U_EMRPOLYBEZIERTO_set(U_RCL_DEF, 3, pt);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRPOLYBEZIERTO_set");
+ }
+ } else {
+ g_warning("logical error, because pathv_to_linear_and_cubic_beziers was used");
+ }
+ }
+
+ if (pit->end_default() == pit->end_closed()) { // there may be multiples of this on a single path
+ rec = U_EMRCLOSEFIGURE_set();
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRCLOSEFIGURE_set");
+ }
+ }
+
+ }
+
+ rec = U_EMRENDPATH_set(); // there may be only be one of these on a single path
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRENDPATH_set");
+ }
+
+ // explicit FILL/STROKE commands are needed for each sub section of the path
+ if (use_fill && !use_stroke) {
+ rec = U_EMRFILLPATH_set(U_RCL_DEF);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::fill at U_EMRFILLPATH_set");
+ }
+ } else if (use_fill && use_stroke) {
+ rec = U_EMRSTROKEANDFILLPATH_set(U_RCL_DEF);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEANDFILLPATH_set");
+ }
+ } else if (!use_fill && use_stroke) {
+ rec = U_EMRSTROKEPATH_set(U_RCL_DEF);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEPATH_set");
+ }
+ }
+
+ // clean out brush and pen, but only after all parts of the draw complete
+ if (use_fill) {
+ destroy_brush();
+ }
+ if (use_stroke) {
+ destroy_pen();
+ }
+
+ return TRUE;
+}
+
+
+unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p,
+ SPStyle const *const style)
+{
+ if (!et) {
+ return 0;
+ }
+
+ char *rec = NULL;
+ int ccount, newfont;
+ int fix90n = 0;
+ uint32_t hfont = 0;
+ Geom::Affine tf = m_tr_stack.top();
+ double rot = -1800.0 * std::atan2(tf[1], tf[0]) / M_PI; // 0.1 degree rotation, - sign for MM_TEXT
+ double rotb = -std::atan2(tf[1], tf[0]); // rotation for baseline offset for superscript/subscript, used below
+ double dx, dy;
+ double ky;
+
+ // the dx array is smuggled in like: text<nul>w1 w2 w3 ...wn<nul><nul>, where the widths are floats 7 characters wide, including the space
+ int ndx, rtl;
+ uint32_t *adx;
+ smuggle_adxkyrtl_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(), tf.expansionY())); // side effect: free() adx
+
+ uint32_t textalignment;
+ if (rtl > 0) {
+ textalignment = U_TA_BASELINE | U_TA_LEFT;
+ } else {
+ textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING;
+ }
+ if (textalignment != htextalignment) {
+ htextalignment = textalignment;
+ rec = U_EMRSETTEXTALIGN_set(textalignment);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::text at U_EMRSETTEXTALIGN_set");
+ }
+ }
+
+ char *text2 = strdup(text); // because U_Utf8ToUtf16le calls iconv which does not like a const char *
+ uint16_t *unicode_text = U_Utf8ToUtf16le(text2, 0, NULL);
+ free(text2);
+ //translates Unicode to NonUnicode, if possible. If any translate, all will, and all to
+ //the same font, because of code in Layout::print
+ UnicodeToNon(unicode_text, &ccount, &newfont);
+
+ //PPT gets funky with text within +-1 degree of a multiple of 90, but only for SOME fonts.Snap those to the central value
+ //Some funky ones: Arial, Times New Roman
+ //Some not funky ones: Symbol and Verdana.
+ //Without a huge table we cannot catch them all, so just the most common problem ones.
+ FontfixParams params;
+
+ if (FixPPTCharPos) {
+ switch (newfont) {
+ case CVTSYM:
+ _lookup_ppt_fontfix("Convert To Symbol", params);
+ break;
+ case CVTZDG:
+ _lookup_ppt_fontfix("Convert To Zapf Dingbats", params);
+ break;
+ case CVTWDG:
+ _lookup_ppt_fontfix("Convert To Wingdings", params);
+ break;
+ default: //also CVTNON
+ _lookup_ppt_fontfix(style->text->font_family.value, params);
+ break;
+ }
+ if (params.f2 != 0 || params.f3 != 0) {
+ int irem = ((int) round(rot)) % 900 ;
+ if (irem <= 9 && irem >= -9) {
+ fix90n = 1; //assume vertical
+ rot = (double)(((int) round(rot)) - irem);
+ rotb = rot * M_PI / 1800.0;
+ if (abs(rot) == 900.0) {
+ fix90n = 2;
+ }
+ }
+ }
+ }
+
+ /* Note that text font sizes are stored into the EMF as fairly small integers and that limits their precision.
+ The EMF output files produced here have been designed so that the integer valued pt sizes
+ land right on an integer value in the EMF file, so those are exact. However, something like 18.1 pt will be
+ somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.)
+ */
+ int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(), tf.expansionY()));
+
+ if (!hfont) {
+ // Get font face name. Use changed font name if unicode mapped to one
+ // of the special fonts.
+ uint16_t *wfacename;
+ if (!newfont) {
+ wfacename = U_Utf8ToUtf16le(style->text->font_family.value, 0, NULL);
+ } else {
+ wfacename = U_Utf8ToUtf16le(FontName(newfont), 0, NULL);
+ }
+
+ // Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if
+ // it was streteched asymmetrically.) Few applications support text from EMF which is scaled
+ // differently by height/width, so leave lfWidth alone.
+
+ U_LOGFONT lf = logfont_set(
+ textheight,
+ 0,
+ round(rot),
+ round(rot),
+ _translate_weight(style->font_weight.computed),
+ (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC),
+ style->text_decoration_line.underline,
+ style->text_decoration_line.line_through,
+ U_DEFAULT_CHARSET,
+ U_OUT_DEFAULT_PRECIS,
+ U_CLIP_DEFAULT_PRECIS,
+ U_DEFAULT_QUALITY,
+ U_DEFAULT_PITCH | U_FF_DONTCARE,
+ wfacename);
+ free(wfacename);
+
+ rec = extcreatefontindirectw_set(&hfont, eht, (char *) &lf, NULL);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::text at extcreatefontindirectw_set");
+ }
+ }
+
+ rec = selectobject_set(hfont, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::text at selectobject_set");
+ }
+
+ float rgb[3];
+ sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
+ // only change the text color when it needs to be changed
+ if (memcmp(htextcolor_rgb, rgb, 3 * sizeof(float))) {
+ memcpy(htextcolor_rgb, rgb, 3 * sizeof(float));
+ rec = U_EMRSETTEXTCOLOR_set(U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]));
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::text at U_EMRSETTEXTCOLOR_set");
+ }
+ }
+
+ Geom::Point p2 = p * tf;
+
+ //Handle super/subscripts and vertical kerning
+ /* Previously used this, but vertical kerning was not supported
+ p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb );
+ p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb );
+ */
+ p2[Geom::X] += ky * std::sin(rotb);
+ p2[Geom::Y] += ky * std::cos(rotb);
+
+ //Conditionally handle compensation for PPT EMF import bug (affects PPT 2003-2010, at least)
+ if (FixPPTCharPos) {
+ if (fix90n == 1) { //vertical
+ dx = 0.0;
+ dy = params.f3 * style->font_size.computed * std::cos(rotb);
+ } else if (fix90n == 2) { //horizontal
+ dx = params.f2 * style->font_size.computed * std::sin(rotb);
+ dy = 0.0;
+ } else {
+ dx = params.f1 * style->font_size.computed * std::sin(rotb);
+ dy = params.f1 * style->font_size.computed * std::cos(rotb);
+ }
+ p2[Geom::X] += dx;
+ p2[Geom::Y] += dy;
+ }
+
+ p2[Geom::X] = (p2[Geom::X] * PX2WORLD);
+ p2[Geom::Y] = (p2[Geom::Y] * PX2WORLD);
+
+ int32_t const xpos = (int32_t) round(p2[Geom::X]);
+ int32_t const ypos = (int32_t) round(p2[Geom::Y]);
+
+
+ // The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is
+ // the number of VISIBLE characters, since some may combine from the UTF (8 originally,
+ // now 16) encoding. Conversely strlen() or wchar16len() would give the absolute number of
+ // encoding characters. Unclear if emrtext wants the former or the latter but for now assume the former.
+
+ // This is currently being smuggled in from caller as part of text, works
+ // MUCH better than the fallback hack below
+ // uint32_t *adx = dx_set(textheight, U_FW_NORMAL, slen); // dx is needed, this makes one up
+ char *rec2;
+ if (rtl > 0) {
+ rec2 = emrtext_set((U_POINTL) {
+ xpos, ypos
+ }, ndx, 2, unicode_text, U_ETO_NONE, U_RCL_DEF, adx);
+ } else { // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case
+ rec2 = emrtext_set((U_POINTL) {
+ xpos, ypos
+ }, ndx, 2, unicode_text, U_ETO_RTLREADING, U_RCL_DEF, adx);
+ }
+ free(unicode_text);
+ free(adx);
+ rec = U_EMREXTTEXTOUTW_set(U_RCL_DEF, U_GM_COMPATIBLE, 1.0, 1.0, (PU_EMRTEXT)rec2);
+ free(rec2);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::text at U_EMREXTTEXTOUTW_set");
+ }
+
+ // Must deselect an object before deleting it. Put the default font (back) in.
+ rec = selectobject_set(U_DEVICE_DEFAULT_FONT, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::text at selectobject_set");
+ }
+
+ if (hfont) {
+ rec = deleteobject_set(&hfont, eht);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::text at deleteobject_set");
+ }
+ }
+
+ return 0;
+}
+
+void PrintEmf::init(void)
+{
+ _load_ppt_fontfix_data();
+
+ /* EMF print */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>Enhanced Metafile Print</name>\n"
+ "<id>org.inkscape.print.emf</id>\n"
+ "<param name=\"destination\" type=\"string\"></param>\n"
+ "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
+ "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n"
+ "<param name=\"FixPPTCharPos\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTDashLine\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTGrad2Polys\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTLinGrad\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTPatternAsHatch\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixImageRot\" type=\"boolean\">false</param>\n"
+ "<print/>\n"
+ "</inkscape-extension>", new PrintEmf());
+
+ return;
+}
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h
new file mode 100644
index 000000000..1e4970a46
--- /dev/null
+++ b/src/extension/internal/emf-print.h
@@ -0,0 +1,99 @@
+/** @file
+ * @brief Enhanced Metafile printing - implementation
+ */
+/* Authors:
+ * Ulf Erikson <ulferikson@users.sf.net>
+ * David Mathog
+ *
+ * Copyright (C) 2006-2008 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+#ifndef SEEN_INKSCAPE_EXTENSION_INTERNAL_EMF_PRINT_H
+#define SEEN_INKSCAPE_EXTENSION_INTERNAL_EMF_PRINT_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <libuemf/uemf.h>
+#include "extension/internal/metafile-print.h"
+
+#include "sp-gradient.h"
+#include "splivarot.h" // pieces for union on shapes
+#include "display/canvas-bpath.h" // for SPWindRule
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class PrintEmf : public PrintMetafile
+{
+ uint32_t hbrush, hbrushOld, hpen, hpenOld;
+
+ unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform);
+ bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform);
+
+public:
+ PrintEmf();
+
+ /* Print functions */
+ virtual unsigned int setup (Inkscape::Extension::Print * module);
+
+ virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc);
+ virtual unsigned int finish (Inkscape::Extension::Print * module);
+
+ /* Rendering methods */
+ virtual unsigned int fill (Inkscape::Extension::Print *module,
+ Geom::PathVector const &pathv,
+ Geom::Affine const &ctm, SPStyle const *style,
+ Geom::OptRect const &pbox, Geom::OptRect const &dbox,
+ Geom::OptRect const &bbox);
+ virtual unsigned int stroke (Inkscape::Extension::Print * module,
+ Geom::PathVector const &pathv,
+ Geom::Affine const &ctm, SPStyle const *style,
+ Geom::OptRect const &pbox, Geom::OptRect const &dbox,
+ Geom::OptRect const &bbox);
+ virtual unsigned int image(Inkscape::Extension::Print *module,
+ unsigned char *px,
+ unsigned int w,
+ unsigned int h,
+ unsigned int rs,
+ Geom::Affine const &transform,
+ SPStyle const *style);
+ virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment);
+ virtual unsigned int text(Inkscape::Extension::Print *module, char const *text,
+ Geom::Point const &p, SPStyle const *style);
+
+ static void init (void);
+protected:
+ static void smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale);
+
+ Geom::Path pathv_to_simple_polygon(Geom::PathVector const &pathv, int *vertices);
+ Geom::Path pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, double *angle);
+ Geom::Point get_pathrect_corner(Geom::Path pathRect, double angle, int corner);
+ U_TRIVERTEX make_trivertex(Geom::Point Pt, U_COLORREF uc);
+ int vector_rect_alignment(double angle, Geom::Point vtest);
+ int create_brush(SPStyle const *style, PU_COLORREF fcolor);
+ void destroy_brush();
+ int create_pen(SPStyle const *style, const Geom::Affine &transform);
+ void destroy_pen();
+};
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+
+#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_H__ */
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/emf-win32-inout.cpp b/src/extension/internal/emf-win32-inout.cpp
deleted file mode 100644
index f54bfc6ea..000000000
--- a/src/extension/internal/emf-win32-inout.cpp
+++ /dev/null
@@ -1,2524 +0,0 @@
-/** @file
- * @brief Windows-only Enhanced Metafile input and output.
- */
-/* Authors:
- * Ulf Erikson <ulferikson@users.sf.net>
- * Jon A. Cruz <jon@joncruz.org>
- * Abhishek Sharma
- *
- * Copyright (C) 2006-2008 Authors
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- *
- * References:
- * - How to Create & Play Enhanced Metafiles in Win32
- * http://support.microsoft.com/kb/q145999/
- * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
- * http://support.microsoft.com/kb/q66949/
- * - Metafile Functions
- * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
- * - Metafile Structures
- * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
- */
-
-#ifdef WIN32
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sp-root.h"
-#include "sp-path.h"
-#include "style.h"
-#include "print.h"
-#include "extension/system.h"
-#include "extension/print.h"
-#include "extension/db.h"
-#include "extension/output.h"
-#include "display/drawing.h"
-#include "display/drawing-item.h"
-#include "unit-constants.h"
-#include "clear-n_.h"
-#include "document.h"
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-#include "emf-win32-print.h"
-#include "emf-win32-inout.h"
-
-
-#define PRINT_EMF_WIN32 "org.inkscape.print.emf.win32"
-
-#ifndef PS_JOIN_MASK
-#define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND)
-#endif
-
-#define DPA 0x00A000C9 // TernaryRasterOperation
-
-namespace Inkscape {
-namespace Extension {
-namespace Internal {
-
-static float device_scale = DEVICESCALE;
-static RECTL rc_old;
-static bool clipset = false;
-
-EmfWin32::EmfWin32 (void) // The null constructor
-{
- return;
-}
-
-
-EmfWin32::~EmfWin32 (void) //The destructor
-{
- return;
-}
-
-
-bool
-EmfWin32::check (Inkscape::Extension::Extension * /*module*/)
-{
- if (NULL == Inkscape::Extension::db.get(PRINT_EMF_WIN32))
- return FALSE;
- return TRUE;
-}
-
-
-static void
-emf_print_document_to_file(SPDocument *doc, gchar const *filename)
-{
- Inkscape::Extension::Print *mod;
- SPPrintContext context;
- gchar const *oldconst;
- gchar *oldoutput;
- unsigned int ret;
-
- doc->ensureUpToDate();
-
- mod = Inkscape::Extension::get_print(PRINT_EMF_WIN32);
- oldconst = mod->get_param_string("destination");
- oldoutput = g_strdup(oldconst);
- mod->set_param_string("destination", filename);
-
-/* Start */
- context.module = mod;
- /* fixme: This has to go into module constructor somehow */
- /* Create new arena */
- mod->base = doc->getRoot();
- Inkscape::Drawing drawing;
- mod->dkey = SPItem::display_key_new(1);
- mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY);
- drawing.setRoot(mod->root);
- /* Print document */
- ret = mod->begin(doc);
- if (ret) {
- g_free(oldoutput);
- throw Inkscape::Extension::Output::save_failed();
- }
- mod->base->invoke_print(&context);
- ret = mod->finish();
- /* Release arena */
- mod->base->invoke_hide(mod->dkey);
- mod->base = NULL;
- mod->root = NULL; // deleted by invoke_hide
-/* end */
-
- mod->set_param_string("destination", oldoutput);
- g_free(oldoutput);
-
- return;
-}
-
-
-void
-EmfWin32::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
-{
- Inkscape::Extension::Extension * ext;
-
- ext = Inkscape::Extension::db.get(PRINT_EMF_WIN32);
- if (ext == NULL)
- return;
-
- bool old_textToPath = ext->get_param_bool("textToPath");
- bool new_val = mod->get_param_bool("textToPath");
- ext->set_param_bool("textToPath", new_val);
-
- emf_print_document_to_file(doc, filename);
-
- ext->set_param_bool("textToPath", old_textToPath);
-
- return;
-}
-
-
-
-typedef struct {
- int type;
- int level;
- ENHMETARECORD *lpEMFR;
-} EMF_OBJECT, *PEMF_OBJECT;
-
-typedef struct emf_device_context {
- struct SPStyle style;
- class SPTextStyle tstyle;
- bool stroke_set;
- bool fill_set;
-
- SIZEL sizeWnd;
- SIZEL sizeView;
- float PixelsInX, PixelsInY;
- float PixelsOutX, PixelsOutY;
- POINTL winorg;
- POINTL vieworg;
- double ScaleInX, ScaleInY;
- double ScaleOutX, ScaleOutY;
- COLORREF textColor;
- bool textColorSet;
- DWORD textAlign;
- XFORM worldTransform;
- POINTL cur;
-} EMF_DEVICE_CONTEXT, *PEMF_DEVICE_CONTEXT;
-
-#define EMF_MAX_DC 128
-
-typedef struct emf_callback_data {
- Glib::ustring *outsvg;
- Glib::ustring *path;
- Glib::ustring *outdef;
-
- EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic..
- int level;
-
- double xDPI, yDPI;
- bool pathless_stroke;
- bool inpath;
-
- float MMX;
- float MMY;
- float dwInchesX;
- float dwInchesY;
-
- unsigned int id;
- CHAR *pDesc;
-
- int n_obj;
- PEMF_OBJECT emf_obj;
-} EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA;
-
-
-static void
-output_style(PEMF_CALLBACK_DATA d, int iType)
-{
-// SVGOStringStream tmp_id;
- SVGOStringStream tmp_style;
- char tmp[1024] = {0};
-
- float fill_rgb[3];
- sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb );
-
- float stroke_rgb[3];
- sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb);
-
-// tmp_id << "\n\tid=\"" << (d->id++) << "\"";
-// *(d->outsvg) += tmp_id.str().c_str();
- *(d->outsvg) += "\n\tstyle=\"";
- if (iType == EMR_STROKEPATH || !d->dc[d->level].fill_set) {
- tmp_style << "fill:none;";
- } else {
- snprintf(tmp, 1023,
- "fill:#%02x%02x%02x;",
- SP_COLOR_F_TO_U(fill_rgb[0]),
- SP_COLOR_F_TO_U(fill_rgb[1]),
- SP_COLOR_F_TO_U(fill_rgb[2]));
- tmp_style << tmp;
- snprintf(tmp, 1023,
- "fill-rule:%s;",
- d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero");
- tmp_style << tmp;
- tmp_style << "fill-opacity:1;";
-
- if (d->dc[d->level].fill_set && d->dc[d->level].stroke_set && d->dc[d->level].style.stroke_width.value == 1 &&
- fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2])
- {
- d->dc[d->level].stroke_set = false;
- }
- }
-
- if (iType == EMR_FILLPATH || !d->dc[d->level].stroke_set) {
- tmp_style << "stroke:none;";
- } else {
- snprintf(tmp, 1023,
- "stroke:#%02x%02x%02x;",
- SP_COLOR_F_TO_U(stroke_rgb[0]),
- SP_COLOR_F_TO_U(stroke_rgb[1]),
- SP_COLOR_F_TO_U(stroke_rgb[2]));
- tmp_style << tmp;
-
- tmp_style << "stroke-width:" <<
- MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
-
- tmp_style << "stroke-linecap:" <<
- (d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" :
- d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" :
- d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" :
- "unknown") << ";";
-
- tmp_style << "stroke-linejoin:" <<
- (d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" :
- d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" :
- d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" :
- "unknown") << ";";
-
- if (d->dc[d->level].style.stroke_linejoin.computed == 0) {
- tmp_style << "stroke-miterlimit:" <<
- MAX( 0.01, d->dc[d->level].style.stroke_miterlimit.value ) << ";";
- }
-
- if (d->dc[d->level].style.stroke_dasharray_set &&
- d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash)
- {
- tmp_style << "stroke-dasharray:";
- for (int i=0; i<d->dc[d->level].style.stroke_dash.n_dash; i++) {
- if (i)
- tmp_style << ",";
- tmp_style << d->dc[d->level].style.stroke_dash.dash[i];
- }
- tmp_style << ";";
- tmp_style << "stroke-dashoffset:0;";
- } else {
- tmp_style << "stroke-dasharray:none;";
- }
- tmp_style << "stroke-opacity:1;";
- }
- tmp_style << "\" ";
- if (clipset)
- tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->id << ")\" ";
- clipset = false;
-
- *(d->outsvg) += tmp_style.str().c_str();
-}
-
-
-static double
-_pix_x_to_point(PEMF_CALLBACK_DATA d, double px)
-{
- double tmp = px - d->dc[d->level].winorg.x;
- tmp *= d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0;
- tmp += d->dc[d->level].vieworg.x;
- return tmp;
-}
-
-static double
-_pix_y_to_point(PEMF_CALLBACK_DATA d, double px)
-{
- double tmp = px - d->dc[d->level].winorg.y;
- tmp *= d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0;
- tmp += d->dc[d->level].vieworg.y;
- return tmp;
-}
-
-
-static double
-pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py)
-{
- double ppx = _pix_x_to_point(d, px);
- double ppy = _pix_y_to_point(d, py);
-
- double x = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx;
- x *= device_scale;
-
- return x;
-}
-
-static double
-pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py)
-{
- double ppx = _pix_x_to_point(d, px);
- double ppy = _pix_y_to_point(d, py);
-
- double y = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy;
- y *= device_scale;
-
- return y;
-}
-
-static double
-pix_to_size_point(PEMF_CALLBACK_DATA d, double px)
-{
- double ppx = px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0);
- double ppy = 0;
-
- double dx = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21;
- dx *= device_scale;
- double dy = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22;
- dy *= device_scale;
-
- double tmp = sqrt(dx * dx + dy * dy);
- return tmp;
-}
-
-
-static void
-select_pen(PEMF_CALLBACK_DATA d, int index)
-{
- PEMRCREATEPEN pEmr = NULL;
-
- if (index >= 0 && index < d->n_obj)
- pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR;
-
- if (!pEmr)
- return;
-
- switch (pEmr->lopn.lopnStyle & PS_STYLE_MASK) {
- case PS_DASH:
- case PS_DOT:
- case PS_DASHDOT:
- case PS_DASHDOTDOT:
- {
- int i = 0;
- int penstyle = (pEmr->lopn.lopnStyle & PS_STYLE_MASK);
- d->dc[d->level].style.stroke_dash.n_dash =
- penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2;
- if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash)))
- delete[] d->dc[d->level].style.stroke_dash.dash;
- d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash];
- if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
- d->dc[d->level].style.stroke_dash.dash[i++] = 3;
- d->dc[d->level].style.stroke_dash.dash[i++] = 1;
- }
- if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
- d->dc[d->level].style.stroke_dash.dash[i++] = 1;
- d->dc[d->level].style.stroke_dash.dash[i++] = 1;
- }
- if (penstyle==PS_DASHDOTDOT) {
- d->dc[d->level].style.stroke_dash.dash[i++] = 1;
- d->dc[d->level].style.stroke_dash.dash[i++] = 1;
- }
-
- d->dc[d->level].style.stroke_dasharray_set = 1;
- break;
- }
-
- case PS_SOLID:
- default:
- {
- d->dc[d->level].style.stroke_dasharray_set = 0;
- break;
- }
- }
-
- switch (pEmr->lopn.lopnStyle & PS_ENDCAP_MASK) {
- case PS_ENDCAP_ROUND:
- {
- d->dc[d->level].style.stroke_linecap.computed = 1;
- break;
- }
- case PS_ENDCAP_SQUARE:
- {
- d->dc[d->level].style.stroke_linecap.computed = 2;
- break;
- }
- case PS_ENDCAP_FLAT:
- default:
- {
- d->dc[d->level].style.stroke_linecap.computed = 0;
- break;
- }
- }
-
- switch (pEmr->lopn.lopnStyle & PS_JOIN_MASK) {
- case PS_JOIN_BEVEL:
- {
- d->dc[d->level].style.stroke_linejoin.computed = 2;
- break;
- }
- case PS_JOIN_MITER:
- {
- d->dc[d->level].style.stroke_linejoin.computed = 0;
- break;
- }
- case PS_JOIN_ROUND:
- default:
- {
- d->dc[d->level].style.stroke_linejoin.computed = 1;
- break;
- }
- }
-
- d->dc[d->level].stroke_set = true;
-
- if (pEmr->lopn.lopnStyle == PS_NULL) {
- d->dc[d->level].style.stroke_width.value = 0;
- d->dc[d->level].stroke_set = false;
- } else if (pEmr->lopn.lopnWidth.x) {
- int cur_level = d->level;
- d->level = d->emf_obj[index].level;
- double pen_width = pix_to_size_point( d, pEmr->lopn.lopnWidth.x );
- d->level = cur_level;
- d->dc[d->level].style.stroke_width.value = pen_width;
- } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
- //d->dc[d->level].style.stroke_width.value = 1.0;
- int cur_level = d->level;
- d->level = d->emf_obj[index].level;
- double pen_width = pix_to_size_point( d, 1 );
- d->level = cur_level;
- d->dc[d->level].style.stroke_width.value = pen_width;
- }
-
- double r, g, b;
- r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) );
- g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) );
- b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) );
- d->dc[d->level].style.stroke.value.color.set( r, g, b );
-}
-
-
-static void
-select_extpen(PEMF_CALLBACK_DATA d, int index)
-{
- PEMREXTCREATEPEN pEmr = NULL;
-
- if (index >= 0 && index < d->n_obj)
- pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR;
-
- if (!pEmr)
- return;
-
- switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) {
- case PS_USERSTYLE:
- {
- if (pEmr->elp.elpNumEntries) {
- d->dc[d->level].style.stroke_dash.n_dash = pEmr->elp.elpNumEntries;
- if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash)))
- delete[] d->dc[d->level].style.stroke_dash.dash;
- d->dc[d->level].style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries];
- for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
- int cur_level = d->level;
- d->level = d->emf_obj[index].level;
- double dash_length = pix_to_size_point( d, pEmr->elp.elpStyleEntry[i] );
- d->level = cur_level;
- d->dc[d->level].style.stroke_dash.dash[i] = dash_length;
- }
- d->dc[d->level].style.stroke_dasharray_set = 1;
- } else {
- d->dc[d->level].style.stroke_dasharray_set = 0;
- }
- break;
- }
-
- case PS_DASH:
- case PS_DOT:
- case PS_DASHDOT:
- case PS_DASHDOTDOT:
- {
- int i = 0;
- int penstyle = (pEmr->elp.elpPenStyle & PS_STYLE_MASK);
- d->dc[d->level].style.stroke_dash.n_dash =
- penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2;
- if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash)))
- delete[] d->dc[d->level].style.stroke_dash.dash;
- d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash];
- if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
- d->dc[d->level].style.stroke_dash.dash[i++] = 3;
- d->dc[d->level].style.stroke_dash.dash[i++] = 2;
- }
- if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
- d->dc[d->level].style.stroke_dash.dash[i++] = 1;
- d->dc[d->level].style.stroke_dash.dash[i++] = 2;
- }
- if (penstyle==PS_DASHDOTDOT) {
- d->dc[d->level].style.stroke_dash.dash[i++] = 1;
- d->dc[d->level].style.stroke_dash.dash[i++] = 2;
- }
-
- d->dc[d->level].style.stroke_dasharray_set = 1;
- break;
- }
-
- case PS_SOLID:
- default:
- {
- d->dc[d->level].style.stroke_dasharray_set = 0;
- break;
- }
- }
-
- switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) {
- case PS_ENDCAP_ROUND:
- {
- d->dc[d->level].style.stroke_linecap.computed = 1;
- break;
- }
- case PS_ENDCAP_SQUARE:
- {
- d->dc[d->level].style.stroke_linecap.computed = 2;
- break;
- }
- case PS_ENDCAP_FLAT:
- default:
- {
- d->dc[d->level].style.stroke_linecap.computed = 0;
- break;
- }
- }
-
- switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) {
- case PS_JOIN_BEVEL:
- {
- d->dc[d->level].style.stroke_linejoin.computed = 2;
- break;
- }
- case PS_JOIN_MITER:
- {
- d->dc[d->level].style.stroke_linejoin.computed = 0;
- break;
- }
- case PS_JOIN_ROUND:
- default:
- {
- d->dc[d->level].style.stroke_linejoin.computed = 1;
- break;
- }
- }
-
- d->dc[d->level].stroke_set = true;
-
- if (pEmr->elp.elpPenStyle == PS_NULL) {
- d->dc[d->level].style.stroke_width.value = 0;
- d->dc[d->level].stroke_set = false;
- } else if (pEmr->elp.elpWidth) {
- int cur_level = d->level;
- d->level = d->emf_obj[index].level;
- double pen_width = pix_to_size_point( d, pEmr->elp.elpWidth );
- d->level = cur_level;
- d->dc[d->level].style.stroke_width.value = pen_width;
- } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
- //d->dc[d->level].style.stroke_width.value = 1.0;
- int cur_level = d->level;
- d->level = d->emf_obj[index].level;
- double pen_width = pix_to_size_point( d, 1 );
- d->level = cur_level;
- d->dc[d->level].style.stroke_width.value = pen_width;
- }
-
- double r, g, b;
- r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) );
- g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) );
- b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) );
-
- d->dc[d->level].style.stroke.value.color.set( r, g, b );
-}
-
-
-static void
-select_brush(PEMF_CALLBACK_DATA d, int index)
-{
- PEMRCREATEBRUSHINDIRECT pEmr = NULL;
-
- if (index >= 0 && index < d->n_obj)
- pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;
-
- if (!pEmr)
- return;
-
- if (pEmr->lb.lbStyle == BS_SOLID) {
- double r, g, b;
- r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) );
- g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) );
- b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) );
- d->dc[d->level].style.fill.value.color.set( r, g, b );
- }
-
- d->dc[d->level].fill_set = true;
-}
-
-
-static void
-select_font(PEMF_CALLBACK_DATA d, int index)
-{
- PEMREXTCREATEFONTINDIRECTW pEmr = NULL;
-
- if (index >= 0 && index < d->n_obj)
- pEmr = (PEMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR;
-
- if (!pEmr)
- return;
-
- int cur_level = d->level;
- d->level = d->emf_obj[index].level;
- double font_size = pix_to_size_point( d, pEmr->elfw.elfLogFont.lfHeight );
- d->level = cur_level;
- d->dc[d->level].style.font_size.computed = font_size;
- d->dc[d->level].style.font_weight.value =
- pEmr->elfw.elfLogFont.lfWeight == FW_THIN ? SP_CSS_FONT_WEIGHT_100 :
- pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 :
- pEmr->elfw.elfLogFont.lfWeight == FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 :
- pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 :
- pEmr->elfw.elfLogFont.lfWeight == FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 :
- pEmr->elfw.elfLogFont.lfWeight == FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 :
- pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_700 :
- pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 :
- pEmr->elfw.elfLogFont.lfWeight == FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 :
- pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL :
- pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD :
- pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER :
- pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER :
- FW_NORMAL;
- d->dc[d->level].style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL);
- d->dc[d->level].style.text_decoration.underline = pEmr->elfw.elfLogFont.lfUnderline;
- d->dc[d->level].style.text_decoration.line_through = pEmr->elfw.elfLogFont.lfStrikeOut;
- if (d->dc[d->level].tstyle.font_family.value)
- g_free(d->dc[d->level].tstyle.font_family.value);
- d->dc[d->level].tstyle.font_family.value =
- (gchar *) g_utf16_to_utf8( (gunichar2*) pEmr->elfw.elfLogFont.lfFaceName, -1, NULL, NULL, NULL );
- d->dc[d->level].style.baseline_shift.value = ((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600) / 10; // use baseline_shift instead of text_transform to avoid overflow
-}
-
-static void
-delete_object(PEMF_CALLBACK_DATA d, int index)
-{
- if (index >= 0 && index < d->n_obj) {
- d->emf_obj[index].type = 0;
- if (d->emf_obj[index].lpEMFR)
- free(d->emf_obj[index].lpEMFR);
- d->emf_obj[index].lpEMFR = NULL;
- }
-}
-
-
-static void
-insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj)
-{
- if (index >= 0 && index < d->n_obj) {
- delete_object(d, index);
- d->emf_obj[index].type = type;
- d->emf_obj[index].level = d->level;
- d->emf_obj[index].lpEMFR = pObj;
- }
-}
-
-static void
-assert_empty_path(PEMF_CALLBACK_DATA d, const char * /*fun*/)
-{
- if (!d->path->empty()) {
- // g_debug("emf-win32-inout: assert_empty_path failed for %s\n", fun);
-
- *(d->outsvg) += "<!--\n";
- *(d->outsvg) += " <path \t";
- output_style(d, EMR_STROKEPATH);
- if (strstr(d->path->c_str(), "d=\"") == NULL) {
- *(d->outsvg) += "d=\"";
- *(d->outsvg) += "\n\t";
- }
- *(d->outsvg) += *(d->path);
- *(d->outsvg) += " \" /> \n";
- *(d->outsvg) += "-->\n";
-
- *(d->path) = "";
- }
-}
-
-
-static int CALLBACK
-myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const *lpEMFR, int /*nObj*/, LPARAM lpData)
-{
- PEMF_CALLBACK_DATA d;
- SVGOStringStream tmp_outsvg;
- SVGOStringStream tmp_path;
- SVGOStringStream tmp_str;
- SVGOStringStream dbg_str;
-
- d = (PEMF_CALLBACK_DATA) lpData;
-
- if (d->pathless_stroke) {
- if (lpEMFR->iType!=EMR_POLYBEZIERTO && lpEMFR->iType!=EMR_POLYBEZIERTO16 &&
- lpEMFR->iType!=EMR_POLYLINETO && lpEMFR->iType!=EMR_POLYLINETO16 &&
- lpEMFR->iType!=EMR_LINETO && lpEMFR->iType!=EMR_ARCTO &&
- lpEMFR->iType!=EMR_SETBKCOLOR && lpEMFR->iType!=EMR_SETROP2 &&
- lpEMFR->iType!=EMR_SETBKMODE && lpEMFR->iType!=EMR_BEGINPATH)
- {
- *(d->outsvg) += " <path ";
- output_style(d, EMR_STROKEPATH);
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += *(d->path);
- *(d->outsvg) += " \" /> \n";
- *(d->path) = "";
- d->pathless_stroke = false;
- }
- }
-
- switch (lpEMFR->iType)
- {
- case EMR_HEADER:
- {
- dbg_str << "<!-- EMR_HEADER -->\n";
-
- *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
-
- if (d->pDesc) {
- *(d->outdef) += "<!-- ";
- *(d->outdef) += d->pDesc;
- *(d->outdef) += " -->\n";
- }
-
- ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR;
- SVGOStringStream tmp_outdef;
- tmp_outdef << "<svg\n";
- tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
- tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n";
- tmp_outdef << " version=\"1.0\"\n";
-
- d->xDPI = 2540;
- d->yDPI = 2540;
-
- d->dc[d->level].PixelsInX = pEmr->rclFrame.right; // - pEmr->rclFrame.left;
- d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom; // - pEmr->rclFrame.top;
-
- d->MMX = d->dc[d->level].PixelsInX / 100.0;
- d->MMY = d->dc[d->level].PixelsInY / 100.0;
-
- d->dc[d->level].PixelsOutX = d->MMX * PX_PER_MM;
- d->dc[d->level].PixelsOutY = d->MMY * PX_PER_MM;
-
- // calculate ratio of Inkscape dpi/device dpi
- if (pEmr->szlMillimeters.cx && pEmr->szlDevice.cx)
- device_scale = PX_PER_MM*pEmr->szlMillimeters.cx/pEmr->szlDevice.cx;
-
- tmp_outdef <<
- " width=\"" << d->MMX << "mm\"\n" <<
- " height=\"" << d->MMY << "mm\">\n";
- *(d->outdef) += tmp_outdef.str().c_str();
- *(d->outdef) += "<defs>"; // temporary end of header
-
- tmp_outsvg << "\n</defs>\n<g>\n"; // start of main body
-
- if (pEmr->nHandles) {
- d->n_obj = pEmr->nHandles;
- d->emf_obj = new EMF_OBJECT[d->n_obj];
-
- // Init the new emf_obj list elements to null, provided the
- // dynamic allocation succeeded.
- if ( d->emf_obj != NULL )
- {
- for( int i=0; i < d->n_obj; ++i )
- d->emf_obj[i].lpEMFR = NULL;
- } //if
-
- } else {
- d->emf_obj = NULL;
- }
-
- break;
- }
- case EMR_POLYBEZIER:
- {
- dbg_str << "<!-- EMR_POLYBEZIER -->\n";
-
- PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR;
- DWORD i,j;
-
- if (pEmr->cptl<4)
- break;
-
- if (!d->inpath) {
- assert_empty_path(d, "EMR_POLYBEZIER");
-
- *(d->outsvg) += " <path ";
- output_style(d, EMR_STROKEPATH);
- *(d->outsvg) += "\n\td=\"";
- }
-
- tmp_str <<
- "\n\tM " <<
- pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
- pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " ";
-
- for (i=1; i<pEmr->cptl; ) {
- tmp_str << "\n\tC ";
- for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
- tmp_str <<
- pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
- pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
- }
- }
-
- if (d->inpath) {
- tmp_path << tmp_str.str().c_str();
- }
- else {
- *(d->outsvg) += tmp_str.str().c_str();
- *(d->outsvg) += " \" /> \n";
- }
-
- break;
- }
- case EMR_POLYGON:
- {
- dbg_str << "<!-- EMR_POLYGON -->\n";
-
- EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR;
- DWORD i;
-
- if (pEmr->cptl < 2)
- break;
-
- assert_empty_path(d, "EMR_POLYGON");
-
- *(d->outsvg) += " <path ";
- output_style(d, EMR_STROKEANDFILLPATH);
- *(d->outsvg) += "\n\td=\"";
-
- tmp_str <<
- "\n\tM " <<
- pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
- pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
-
- for (i=1; i<pEmr->cptl; i++) {
- tmp_str <<
- "\n\tL " <<
- pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
- pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
- }
-
- *(d->outsvg) += tmp_str.str().c_str();
- *(d->outsvg) += " z \" /> \n";
-
- break;
- }
- case EMR_POLYLINE:
- {
- dbg_str << "<!-- EMR_POLYLINE -->\n";
-
- EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR;
- DWORD i;
-
- if (pEmr->cptl<2)
- break;
-
- if (!d->inpath) {
- assert_empty_path(d, "EMR_POLYLINE");
-
- *(d->outsvg) += " <path ";
- output_style(d, EMR_STROKEPATH);
- *(d->outsvg) += "\n\td=\"";
- }
-
- tmp_str <<
- "\n\tM " <<
- pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
- pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
-
- for (i=1; i<pEmr->cptl; i++) {
- tmp_str <<
- "\n\tL " <<
- pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
- pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
- }
-
- if (d->inpath) {
- tmp_path << tmp_str.str().c_str();
- }
- else {
- *(d->outsvg) += tmp_str.str().c_str();
- *(d->outsvg) += " \" /> \n";
- }
-
- break;
- }
- case EMR_POLYBEZIERTO:
- {
- dbg_str << "<!-- EMR_POLYBEZIERTO -->\n";
-
- PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR;
- DWORD i,j;
-
- if (d->path->empty()) {
- d->pathless_stroke = true;
- *(d->path) = "d=\"";
- }
-
- for (i=0; i<pEmr->cptl;) {
- tmp_path << "\n\tC ";
- for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
- tmp_path <<
- pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
- pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
- }
- }
-
- break;
- }
- case EMR_POLYLINETO:
- {
- dbg_str << "<!-- EMR_POLYLINETO -->\n";
-
- PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR;
- DWORD i;
-
- if (d->path->empty()) {
- d->pathless_stroke = true;
- *(d->path) = "d=\"";
- }
-
- for (i=0; i<pEmr->cptl;i++) {
- tmp_path <<
- "\n\tL " <<
- pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
- pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
- }
-
- break;
- }
- case EMR_POLYPOLYLINE:
- case EMR_POLYPOLYGON:
- {
- if (lpEMFR->iType == EMR_POLYPOLYLINE)
- dbg_str << "<!-- EMR_POLYPOLYLINE -->\n";
- if (lpEMFR->iType == EMR_POLYPOLYGON)
- dbg_str << "<!-- EMR_POLYPOLYGON -->\n";
-
- PEMRPOLYPOLYGON pEmr = (PEMRPOLYPOLYGON) lpEMFR;
- unsigned int n, i, j;
-
- if (!d->inpath) {
- assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON ? "EMR_POLYPOLYGON" : "EMR_POLYPOLYLINE");
-
- *(d->outsvg) += " <path ";
- output_style(d, lpEMFR->iType==EMR_POLYPOLYGON ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
- *(d->outsvg) += "\n\td=\"";
- }
-
- POINTL *aptl = (POINTL *) &pEmr->aPolyCounts[pEmr->nPolys];
-
- i = 0;
- for (n=0; n<pEmr->nPolys && i<pEmr->cptl; n++) {
- SVGOStringStream poly_path;
-
- poly_path << "\n\tM " <<
- pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " <<
- pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " ";
- i++;
-
- for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cptl; j++) {
- poly_path << "\n\tL " <<
- pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " <<
- pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " ";
- i++;
- }
-
- tmp_str << poly_path.str().c_str();
- if (lpEMFR->iType == EMR_POLYPOLYGON)
- tmp_str << " z";
- tmp_str << " \n";
- }
-
- if (d->inpath) {
- tmp_path << tmp_str.str().c_str();
- }
- else {
- *(d->outsvg) += tmp_str.str().c_str();
- *(d->outsvg) += " \" /> \n";
- }
-
- break;
- }
- case EMR_SETWINDOWEXTEX:
- {
- dbg_str << "<!-- EMR_SETWINDOWEXTEX -->\n";
-
- PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR;
-
- d->dc[d->level].sizeWnd = pEmr->szlExtent;
-
- if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
- d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
- if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
- d->dc[d->level].sizeWnd.cx = d->dc[d->level].PixelsOutX;
- d->dc[d->level].sizeWnd.cy = d->dc[d->level].PixelsOutY;
- }
- }
-
- if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
- d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
- }
-
- d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx;
- d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy;
-
- if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) {
- d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX;
- d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY;
- }
- else {
- d->dc[d->level].ScaleInX = 1;
- d->dc[d->level].ScaleInY = 1;
- }
-
- break;
- }
- case EMR_SETWINDOWORGEX:
- {
- dbg_str << "<!-- EMR_SETWINDOWORGEX -->\n";
-
- PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR;
- d->dc[d->level].winorg = pEmr->ptlOrigin;
- break;
- }
- case EMR_SETVIEWPORTEXTEX:
- {
- dbg_str << "<!-- EMR_SETVIEWPORTEXTEX -->\n";
-
- PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR;
-
- d->dc[d->level].sizeView = pEmr->szlExtent;
-
- if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
- d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
- if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
- d->dc[d->level].sizeView.cx = d->dc[d->level].PixelsOutX;
- d->dc[d->level].sizeView.cy = d->dc[d->level].PixelsOutY;
- }
- }
-
- if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
- d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
- }
-
- d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx;
- d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy;
-
- if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) {
- d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX;
- d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY;
- }
- else {
- d->dc[d->level].ScaleInX = 1;
- d->dc[d->level].ScaleInY = 1;
- }
-
- break;
- }
- case EMR_SETVIEWPORTORGEX:
- {
- dbg_str << "<!-- EMR_SETVIEWPORTORGEX -->\n";
-
- PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR;
- d->dc[d->level].vieworg = pEmr->ptlOrigin;
- break;
- }
- case EMR_SETBRUSHORGEX:
- dbg_str << "<!-- EMR_SETBRUSHORGEX -->\n";
- break;
- case EMR_EOF:
- {
- dbg_str << "<!-- EMR_EOF -->\n";
-
- assert_empty_path(d, "EMR_EOF");
- tmp_outsvg << "</g>\n";
- tmp_outsvg << "</svg>\n";
- *(d->outsvg) = *(d->outdef) + *(d->outsvg);
- break;
- }
- case EMR_SETPIXELV:
- dbg_str << "<!-- EMR_SETPIXELV -->\n";
- break;
- case EMR_SETMAPPERFLAGS:
- dbg_str << "<!-- EMR_SETMAPPERFLAGS -->\n";
- break;
- case EMR_SETMAPMODE:
- dbg_str << "<!-- EMR_SETMAPMODE -->\n";
- break;
- case EMR_SETBKMODE:
- dbg_str << "<!-- EMR_SETBKMODE -->\n";
- break;
- case EMR_SETPOLYFILLMODE:
- {
- dbg_str << "<!-- EMR_SETPOLYFILLMODE -->\n";
-
- PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR;
- d->dc[d->level].style.fill_rule.value =
- (pEmr->iMode == ALTERNATE ? 0 :
- pEmr->iMode == WINDING ? 1 : 0);
- break;
- }
- case EMR_SETROP2:
- dbg_str << "<!-- EMR_SETROP2 -->\n";
- break;
- case EMR_SETSTRETCHBLTMODE:
- dbg_str << "<!-- EMR_SETSTRETCHBLTMODE -->\n";
- break;
- case EMR_SETTEXTALIGN:
- {
- dbg_str << "<!-- EMR_SETTEXTALIGN -->\n";
-
- PEMRSETTEXTALIGN pEmr = (PEMRSETTEXTALIGN) lpEMFR;
- d->dc[d->level].textAlign = pEmr->iMode;
- break;
- }
- case EMR_SETCOLORADJUSTMENT:
- dbg_str << "<!-- EMR_SETCOLORADJUSTMENT -->\n";
- break;
- case EMR_SETTEXTCOLOR:
- {
- dbg_str << "<!-- EMR_SETTEXTCOLOR -->\n";
-
- PEMRSETTEXTCOLOR pEmr = (PEMRSETTEXTCOLOR) lpEMFR;
- d->dc[d->level].textColor = pEmr->crColor;
- d->dc[d->level].textColorSet = true;
- break;
- }
- case EMR_SETBKCOLOR:
- dbg_str << "<!-- EMR_SETBKCOLOR -->\n";
- break;
- case EMR_OFFSETCLIPRGN:
- dbg_str << "<!-- EMR_OFFSETCLIPRGN -->\n";
- break;
- case EMR_MOVETOEX:
- {
- dbg_str << "<!-- EMR_MOVETOEX -->\n";
-
- PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR;
-
- if (d->path->empty()) {
- d->pathless_stroke = true;
- *(d->path) = "d=\"";
- }
-
- d->dc[d->level].cur = pEmr->ptl;
-
- tmp_path <<
- "\n\tM " <<
- pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " <<
- pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
- break;
- }
- case EMR_SETMETARGN:
- dbg_str << "<!-- EMR_SETMETARGN -->\n";
- break;
- case EMR_EXCLUDECLIPRECT:
- dbg_str << "<!-- EMR_EXCLUDECLIPRECT -->\n";
- break;
- case EMR_INTERSECTCLIPRECT:
- {
- dbg_str << "<!-- EMR_INTERSECTCLIPRECT -->\n";
-
- PEMRINTERSECTCLIPRECT pEmr = (PEMRINTERSECTCLIPRECT) lpEMFR;
- RECTL rc = pEmr->rclClip;
- clipset = true;
- if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom))
- break;
- rc_old = rc;
-
- double l = pix_to_x_point( d, rc.left, rc.top );
- double t = pix_to_y_point( d, rc.left, rc.top );
- double r = pix_to_x_point( d, rc.right, rc.bottom );
- double b = pix_to_y_point( d, rc.right, rc.bottom );
-
- SVGOStringStream tmp_rectangle;
- tmp_rectangle << "\n<clipPath\n\tclipPathUnits=\"userSpaceOnUse\" ";
- tmp_rectangle << "\n\tid=\"clipEmfPath" << ++(d->id) << "\" >";
- tmp_rectangle << "\n<rect ";
- tmp_rectangle << "\n\tx=\"" << l << "\" ";
- tmp_rectangle << "\n\ty=\"" << t << "\" ";
- tmp_rectangle << "\n\twidth=\"" << r-l << "\" ";
- tmp_rectangle << "\n\theight=\"" << b-t << "\" />";
- tmp_rectangle << "\n</clipPath>";
-
- assert_empty_path(d, "EMR_RECTANGLE");
-
- *(d->outdef) += tmp_rectangle.str().c_str();
- *(d->path) = "";
- break;
- }
- case EMR_SCALEVIEWPORTEXTEX:
- dbg_str << "<!-- EMR_SCALEVIEWPORTEXTEX -->\n";
- break;
- case EMR_SCALEWINDOWEXTEX:
- dbg_str << "<!-- EMR_SCALEWINDOWEXTEX -->\n";
- break;
- case EMR_SAVEDC:
- dbg_str << "<!-- EMR_SAVEDC -->\n";
-
- if (d->level < EMF_MAX_DC) {
- d->dc[d->level + 1] = d->dc[d->level];
- d->level = d->level + 1;
- }
- break;
- case EMR_RESTOREDC:
- {
- dbg_str << "<!-- EMR_RESTOREDC -->\n";
-
- PEMRRESTOREDC pEmr = (PEMRRESTOREDC) lpEMFR;
- int old_level = d->level;
- if (pEmr->iRelative >= 0) {
- if (pEmr->iRelative < d->level)
- d->level = pEmr->iRelative;
- }
- else {
- if (d->level + pEmr->iRelative >= 0)
- d->level = d->level + pEmr->iRelative;
- }
- while (old_level > d->level) {
- if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash)))
- delete[] d->dc[old_level].style.stroke_dash.dash;
- old_level--;
- }
- break;
- }
- case EMR_SETWORLDTRANSFORM:
- {
- dbg_str << "<!-- EMR_SETWORLDTRANSFORM -->\n";
-
- PEMRSETWORLDTRANSFORM pEmr = (PEMRSETWORLDTRANSFORM) lpEMFR;
- d->dc[d->level].worldTransform = pEmr->xform;
- break;
- }
- case EMR_MODIFYWORLDTRANSFORM:
- {
- dbg_str << "<!-- EMR_MODIFYWORLDTRANSFORM -->\n";
-
- PEMRMODIFYWORLDTRANSFORM pEmr = (PEMRMODIFYWORLDTRANSFORM) lpEMFR;
- switch (pEmr->iMode)
- {
- case MWT_IDENTITY:
- d->dc[d->level].worldTransform.eM11 = 1.0;
- d->dc[d->level].worldTransform.eM12 = 0.0;
- d->dc[d->level].worldTransform.eM21 = 0.0;
- d->dc[d->level].worldTransform.eM22 = 1.0;
- d->dc[d->level].worldTransform.eDx = 0.0;
- d->dc[d->level].worldTransform.eDy = 0.0;
- break;
- case MWT_LEFTMULTIPLY:
- {
-// d->dc[d->level].worldTransform = pEmr->xform * worldTransform;
-
- float a11 = pEmr->xform.eM11;
- float a12 = pEmr->xform.eM12;
- float a13 = 0.0;
- float a21 = pEmr->xform.eM21;
- float a22 = pEmr->xform.eM22;
- float a23 = 0.0;
- float a31 = pEmr->xform.eDx;
- float a32 = pEmr->xform.eDy;
- float a33 = 1.0;
-
- float b11 = d->dc[d->level].worldTransform.eM11;
- float b12 = d->dc[d->level].worldTransform.eM12;
- //float b13 = 0.0;
- float b21 = d->dc[d->level].worldTransform.eM21;
- float b22 = d->dc[d->level].worldTransform.eM22;
- //float b23 = 0.0;
- float b31 = d->dc[d->level].worldTransform.eDx;
- float b32 = d->dc[d->level].worldTransform.eDy;
- //float b33 = 1.0;
-
- float c11 = a11*b11 + a12*b21 + a13*b31;;
- float c12 = a11*b12 + a12*b22 + a13*b32;;
- //float c13 = a11*b13 + a12*b23 + a13*b33;;
- float c21 = a21*b11 + a22*b21 + a23*b31;;
- float c22 = a21*b12 + a22*b22 + a23*b32;;
- //float c23 = a21*b13 + a22*b23 + a23*b33;;
- float c31 = a31*b11 + a32*b21 + a33*b31;;
- float c32 = a31*b12 + a32*b22 + a33*b32;;
- //float c33 = a31*b13 + a32*b23 + a33*b33;;
-
- d->dc[d->level].worldTransform.eM11 = c11;;
- d->dc[d->level].worldTransform.eM12 = c12;;
- d->dc[d->level].worldTransform.eM21 = c21;;
- d->dc[d->level].worldTransform.eM22 = c22;;
- d->dc[d->level].worldTransform.eDx = c31;
- d->dc[d->level].worldTransform.eDy = c32;
-
- break;
- }
- case MWT_RIGHTMULTIPLY:
- {
-// d->dc[d->level].worldTransform = worldTransform * pEmr->xform;
-
- float a11 = d->dc[d->level].worldTransform.eM11;
- float a12 = d->dc[d->level].worldTransform.eM12;
- float a13 = 0.0;
- float a21 = d->dc[d->level].worldTransform.eM21;
- float a22 = d->dc[d->level].worldTransform.eM22;
- float a23 = 0.0;
- float a31 = d->dc[d->level].worldTransform.eDx;
- float a32 = d->dc[d->level].worldTransform.eDy;
- float a33 = 1.0;
-
- float b11 = pEmr->xform.eM11;
- float b12 = pEmr->xform.eM12;
- //float b13 = 0.0;
- float b21 = pEmr->xform.eM21;
- float b22 = pEmr->xform.eM22;
- //float b23 = 0.0;
- float b31 = pEmr->xform.eDx;
- float b32 = pEmr->xform.eDy;
- //float b33 = 1.0;
-
- float c11 = a11*b11 + a12*b21 + a13*b31;;
- float c12 = a11*b12 + a12*b22 + a13*b32;;
- //float c13 = a11*b13 + a12*b23 + a13*b33;;
- float c21 = a21*b11 + a22*b21 + a23*b31;;
- float c22 = a21*b12 + a22*b22 + a23*b32;;
- //float c23 = a21*b13 + a22*b23 + a23*b33;;
- float c31 = a31*b11 + a32*b21 + a33*b31;;
- float c32 = a31*b12 + a32*b22 + a33*b32;;
- //float c33 = a31*b13 + a32*b23 + a33*b33;;
-
- d->dc[d->level].worldTransform.eM11 = c11;;
- d->dc[d->level].worldTransform.eM12 = c12;;
- d->dc[d->level].worldTransform.eM21 = c21;;
- d->dc[d->level].worldTransform.eM22 = c22;;
- d->dc[d->level].worldTransform.eDx = c31;
- d->dc[d->level].worldTransform.eDy = c32;
-
- break;
- }
-// case MWT_SET:
- default:
- d->dc[d->level].worldTransform = pEmr->xform;
- break;
- }
- break;
- }
- case EMR_SELECTOBJECT:
- {
- dbg_str << "<!-- EMR_SELECTOBJECT -->\n";
-
- PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR;
- unsigned int index = pEmr->ihObject;
-
- if (index >= ENHMETA_STOCK_OBJECT) {
- index -= ENHMETA_STOCK_OBJECT;
- switch (index) {
- case NULL_BRUSH:
- d->dc[d->level].fill_set = false;
- break;
- case BLACK_BRUSH:
- case DKGRAY_BRUSH:
- case GRAY_BRUSH:
- case LTGRAY_BRUSH:
- case WHITE_BRUSH:
- {
- float val = 0;
- switch (index) {
- case BLACK_BRUSH:
- val = 0.0 / 255.0;
- break;
- case DKGRAY_BRUSH:
- val = 64.0 / 255.0;
- break;
- case GRAY_BRUSH:
- val = 128.0 / 255.0;
- break;
- case LTGRAY_BRUSH:
- val = 192.0 / 255.0;
- break;
- case WHITE_BRUSH:
- val = 255.0 / 255.0;
- break;
- }
- d->dc[d->level].style.fill.value.color.set( val, val, val );
-
- d->dc[d->level].fill_set = true;
- break;
- }
- case NULL_PEN:
- d->dc[d->level].stroke_set = false;
- break;
- case BLACK_PEN:
- case WHITE_PEN:
- {
- float val = index == BLACK_PEN ? 0 : 1;
- d->dc[d->level].style.stroke_dasharray_set = 0;
- d->dc[d->level].style.stroke_width.value = 1.0;
- d->dc[d->level].style.stroke.value.color.set( val, val, val );
-
- d->dc[d->level].stroke_set = true;
-
- break;
- }
- }
- } else {
- if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) {
- switch (d->emf_obj[index].type)
- {
- case EMR_CREATEPEN:
- select_pen(d, index);
- break;
- case EMR_CREATEBRUSHINDIRECT:
- select_brush(d, index);
- break;
- case EMR_EXTCREATEPEN:
- select_extpen(d, index);
- break;
- case EMR_EXTCREATEFONTINDIRECTW:
- select_font(d, index);
- break;
- }
- }
- }
- break;
- }
- case EMR_CREATEPEN:
- {
- dbg_str << "<!-- EMR_CREATEPEN -->\n";
-
- PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR;
- int index = pEmr->ihPen;
-
- EMRCREATEPEN *pPen =
- (EMRCREATEPEN *) malloc( sizeof(EMRCREATEPEN) );
- pPen->lopn = pEmr->lopn;
- insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen);
-
- break;
- }
- case EMR_CREATEBRUSHINDIRECT:
- {
- dbg_str << "<!-- EMR_CREATEBRUSHINDIRECT -->\n";
-
- PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR;
- int index = pEmr->ihBrush;
-
- EMRCREATEBRUSHINDIRECT *pBrush =
- (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) );
- pBrush->lb = pEmr->lb;
- insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush);
-
- break;
- }
- case EMR_DELETEOBJECT:
- dbg_str << "<!-- EMR_DELETEOBJECT -->\n";
- break;
- case EMR_ANGLEARC:
- dbg_str << "<!-- EMR_ANGLEARC -->\n";
- break;
- case EMR_ELLIPSE:
- {
- dbg_str << "<!-- EMR_ELLIPSE -->\n";
-
- PEMRELLIPSE pEmr = (PEMRELLIPSE) lpEMFR;
- RECTL rclBox = pEmr->rclBox;
-
- double l = pix_to_x_point( d, pEmr->rclBox.left, pEmr->rclBox.top );
- double t = pix_to_y_point( d, pEmr->rclBox.left, pEmr->rclBox.top );
- double r = pix_to_x_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom );
- double b = pix_to_y_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom );
-
- double cx = (l + r) / 2.0;
- double cy = (t + b) / 2.0;
- double rx = fabs(l - r) / 2.0;
- double ry = fabs(t - b) / 2.0;
-
- SVGOStringStream tmp_ellipse;
- tmp_ellipse << "cx=\"" << cx << "\" ";
- tmp_ellipse << "cy=\"" << cy << "\" ";
- tmp_ellipse << "rx=\"" << rx << "\" ";
- tmp_ellipse << "ry=\"" << ry << "\" ";
-
- assert_empty_path(d, "EMR_ELLIPSE");
-
- *(d->outsvg) += " <ellipse ";
- output_style(d, lpEMFR->iType);
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += tmp_ellipse.str().c_str();
- *(d->outsvg) += "/> \n";
- *(d->path) = "";
- break;
- }
- case EMR_RECTANGLE:
- {
- dbg_str << "<!-- EMR_RECTANGLE -->\n";
-
- PEMRRECTANGLE pEmr = (PEMRRECTANGLE) lpEMFR;
- RECTL rc = pEmr->rclBox;
-
- double l = pix_to_x_point( d, rc.left, rc.top );
- double t = pix_to_y_point( d, rc.left, rc.top );
- double r = pix_to_x_point( d, rc.right, rc.bottom );
- double b = pix_to_y_point( d, rc.right, rc.bottom );
-
- SVGOStringStream tmp_rectangle;
- tmp_rectangle << "d=\"";
- tmp_rectangle << "\n\tM " << l << " " << t << " ";
- tmp_rectangle << "\n\tL " << r << " " << t << " ";
- tmp_rectangle << "\n\tL " << r << " " << b << " ";
- tmp_rectangle << "\n\tL " << l << " " << b << " ";
- tmp_rectangle << "\n\tz";
-
- assert_empty_path(d, "EMR_RECTANGLE");
-
- *(d->outsvg) += " <path ";
- output_style(d, lpEMFR->iType);
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += tmp_rectangle.str().c_str();
- *(d->outsvg) += " \" /> \n";
- *(d->path) = "";
- break;
- }
- case EMR_ROUNDRECT:
- {
- dbg_str << "<!-- EMR_ROUNDRECT -->\n";
-
- PEMRROUNDRECT pEmr = (PEMRROUNDRECT) lpEMFR;
- RECTL rc = pEmr->rclBox;
- SIZEL corner = pEmr->szlCorner;
- double f = 4.*(sqrt(2) - 1)/3;
-
- double l = pix_to_x_point(d, rc.left, rc.top);
- double t = pix_to_y_point(d, rc.left, rc.top);
- double r = pix_to_x_point(d, rc.right, rc.bottom);
- double b = pix_to_y_point(d, rc.right, rc.bottom);
- double cnx = pix_to_size_point(d, corner.cx/2);
- double cny = pix_to_size_point(d, corner.cy/2);
-
- SVGOStringStream tmp_rectangle;
- tmp_rectangle << "d=\"";
- tmp_rectangle << "\n\tM " << l << ", " << t + cny << " ";
- tmp_rectangle << "\n\tC " << l << ", " << t + (1-f)*cny << " " << l + (1-f)*cnx << ", " << t << " " << l + cnx << ", " << t << " ";
- tmp_rectangle << "\n\tL " << r - cnx << ", " << t << " ";
- tmp_rectangle << "\n\tC " << r - (1-f)*cnx << ", " << t << " " << r << ", " << t + (1-f)*cny << " " << r << ", " << t + cny << " ";
- tmp_rectangle << "\n\tL " << r << ", " << b - cny << " ";
- tmp_rectangle << "\n\tC " << r << ", " << b - (1-f)*cny << " " << r - (1-f)*cnx << ", " << b << " " << r - cnx << ", " << b << " ";
- tmp_rectangle << "\n\tL " << l + cnx << ", " << b << " ";
- tmp_rectangle << "\n\tC " << l + (1-f)*cnx << ", " << b << " " << l << ", " << b - (1-f)*cny << " " << l << ", " << b - cny << " ";
- tmp_rectangle << "\n\tz";
- assert_empty_path(d, "EMR_ROUNDRECT");
-
- *(d->outsvg) += " <path ";
- output_style(d, lpEMFR->iType);
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += tmp_rectangle.str().c_str();
- *(d->outsvg) += " \" /> \n";
- *(d->path) = "";
- break;
- }
- case EMR_ARC:
- dbg_str << "<!-- EMR_ARC -->\n";
- break;
- case EMR_CHORD:
- dbg_str << "<!-- EMR_CHORD -->\n";
- break;
- case EMR_PIE:
- dbg_str << "<!-- EMR_PIE -->\n";
- break;
- case EMR_SELECTPALETTE:
- dbg_str << "<!-- EMR_SELECTPALETTE -->\n";
- break;
- case EMR_CREATEPALETTE:
- dbg_str << "<!-- EMR_CREATEPALETTE -->\n";
- break;
- case EMR_SETPALETTEENTRIES:
- dbg_str << "<!-- EMR_SETPALETTEENTRIES -->\n";
- break;
- case EMR_RESIZEPALETTE:
- dbg_str << "<!-- EMR_RESIZEPALETTE -->\n";
- break;
- case EMR_REALIZEPALETTE:
- dbg_str << "<!-- EMR_REALIZEPALETTE -->\n";
- break;
- case EMR_EXTFLOODFILL:
- dbg_str << "<!-- EMR_EXTFLOODFILL -->\n";
- break;
- case EMR_LINETO:
- {
- dbg_str << "<!-- EMR_LINETO -->\n";
-
- PEMRLINETO pEmr = (PEMRLINETO) lpEMFR;
-
- if (d->path->empty()) {
- d->pathless_stroke = true;
- *(d->path) = "d=\"";
- }
-
- tmp_path <<
- "\n\tL " <<
- pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " <<
- pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
- break;
- }
- case EMR_ARCTO:
- dbg_str << "<!-- EMR_ARCTO -->\n";
- break;
- case EMR_POLYDRAW:
- dbg_str << "<!-- EMR_POLYDRAW -->\n";
- break;
- case EMR_SETARCDIRECTION:
- dbg_str << "<!-- EMR_SETARCDIRECTION -->\n";
- break;
- case EMR_SETMITERLIMIT:
- {
- dbg_str << "<!-- EMR_SETMITERLIMIT -->\n";
-
- PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR;
-
- float miterlimit = pEmr->eMiterLimit;
- miterlimit = miterlimit * 4.0 / 10.0;
- d->dc[d->level].style.stroke_miterlimit.value = pix_to_size_point( d, miterlimit );
- if (d->dc[d->level].style.stroke_miterlimit.value < 1)
- d->dc[d->level].style.stroke_miterlimit.value = 4.0;
- break;
- }
- case EMR_BEGINPATH:
- {
- dbg_str << "<!-- EMR_BEGINPATH -->\n";
-
- if (!d->pathless_stroke) {
- tmp_path << "d=\"";
- *(d->path) = "";
- }
- d->pathless_stroke = false;
- d->inpath = true;
- break;
- }
- case EMR_ENDPATH:
- {
- dbg_str << "<!-- EMR_ENDPATH -->\n";
-
- tmp_path << "\"";
- d->inpath = false;
- break;
- }
- case EMR_CLOSEFIGURE:
- {
- dbg_str << "<!-- EMR_CLOSEFIGURE -->\n";
-
- tmp_path << "\n\tz";
- break;
- }
- case EMR_FILLPATH:
- case EMR_STROKEANDFILLPATH:
- case EMR_STROKEPATH:
- {
- if (lpEMFR->iType == EMR_FILLPATH)
- dbg_str << "<!-- EMR_FILLPATH -->\n";
- if (lpEMFR->iType == EMR_STROKEANDFILLPATH)
- dbg_str << "<!-- EMR_STROKEANDFILLPATH -->\n";
- if (lpEMFR->iType == EMR_STROKEPATH)
- dbg_str << "<!-- EMR_STROKEPATH -->\n";
-
- *(d->outsvg) += " <path ";
- output_style(d, lpEMFR->iType);
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += *(d->path);
- *(d->outsvg) += " /> \n";
- *(d->path) = "";
- break;
- }
- case EMR_FLATTENPATH:
- dbg_str << "<!-- EMR_FLATTENPATH -->\n";
- break;
- case EMR_WIDENPATH:
- dbg_str << "<!-- EMR_WIDENPATH -->\n";
- break;
- case EMR_SELECTCLIPPATH:
- dbg_str << "<!-- EMR_SELECTCLIPPATH -->\n";
- break;
- case EMR_ABORTPATH:
- dbg_str << "<!-- EMR_ABORTPATH -->\n";
- break;
- case EMR_GDICOMMENT:
- {
- dbg_str << "<!-- EMR_GDICOMMENT -->\n";
-
- PEMRGDICOMMENT pEmr = (PEMRGDICOMMENT) lpEMFR;
-
- CHAR *szTxt = (CHAR *) pEmr->Data;
-
- for (DWORD i = 0; i < pEmr->cbData; i++) {
- if ( *szTxt) {
- if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) {
- tmp_str << *szTxt;
- }
- szTxt++;
- }
- }
-
- if (0 && strlen(tmp_str.str().c_str())) {
- tmp_outsvg << " <!-- \"";
- tmp_outsvg << tmp_str.str().c_str();
- tmp_outsvg << "\" -->\n";
- }
-
- break;
- }
- case EMR_FILLRGN:
- dbg_str << "<!-- EMR_FILLRGN -->\n";
- break;
- case EMR_FRAMERGN:
- dbg_str << "<!-- EMR_FRAMERGN -->\n";
- break;
- case EMR_INVERTRGN:
- dbg_str << "<!-- EMR_INVERTRGN -->\n";
- break;
- case EMR_PAINTRGN:
- dbg_str << "<!-- EMR_PAINTRGN -->\n";
- break;
- case EMR_EXTSELECTCLIPRGN:
- {
- dbg_str << "<!-- EMR_EXTSELECTCLIPRGN -->\n";
-
- PEMREXTSELECTCLIPRGN pEmr = (PEMREXTSELECTCLIPRGN) lpEMFR;
- if (pEmr->iMode == RGN_COPY)
- clipset = false;
- break;
- }
- case EMR_BITBLT:
- {
- dbg_str << "<!-- EMR_BITBLT -->\n";
-
- PEMRBITBLT pEmr = (PEMRBITBLT) lpEMFR;
- if (pEmr->dwRop == DPA) {
- // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead
- double l = pix_to_x_point( d, pEmr->xDest, pEmr->yDest);
- double t = pix_to_y_point( d, pEmr->xDest, pEmr->yDest);
- double r = pix_to_x_point( d, pEmr->xDest + pEmr->cxDest, pEmr->yDest + pEmr->cyDest);
- double b = pix_to_y_point( d, pEmr->xDest + pEmr->cxDest, pEmr->yDest + pEmr->cyDest);
-
- SVGOStringStream tmp_rectangle;
- tmp_rectangle << "d=\"";
- tmp_rectangle << "\n\tM " << l << " " << t << " ";
- tmp_rectangle << "\n\tL " << r << " " << t << " ";
- tmp_rectangle << "\n\tL " << r << " " << b << " ";
- tmp_rectangle << "\n\tL " << l << " " << b << " ";
- tmp_rectangle << "\n\tz";
-
- assert_empty_path(d, "EMR_BITBLT");
-
- *(d->outsvg) += " <path ";
- output_style(d, lpEMFR->iType);
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += tmp_rectangle.str().c_str();
- *(d->outsvg) += " \" /> \n";
- *(d->path) = "";
- }
- break;
- }
- case EMR_STRETCHBLT:
- dbg_str << "<!-- EMR_STRETCHBLT -->\n";
- break;
- case EMR_MASKBLT:
- dbg_str << "<!-- EMR_MASKBLT -->\n";
- break;
- case EMR_PLGBLT:
- dbg_str << "<!-- EMR_PLGBLT -->\n";
- break;
- case EMR_SETDIBITSTODEVICE:
- dbg_str << "<!-- EMR_SETDIBITSTODEVICE -->\n";
- break;
- case EMR_STRETCHDIBITS:
- dbg_str << "<!-- EMR_STRETCHDIBITS -->\n";
- break;
- case EMR_EXTCREATEFONTINDIRECTW:
- {
- dbg_str << "<!-- EMR_EXTCREATEFONTINDIRECTW -->\n";
-
- PEMREXTCREATEFONTINDIRECTW pEmr = (PEMREXTCREATEFONTINDIRECTW) lpEMFR;
- int index = pEmr->ihFont;
-
- EMREXTCREATEFONTINDIRECTW *pFont =
- (EMREXTCREATEFONTINDIRECTW *) malloc( sizeof(EMREXTCREATEFONTINDIRECTW) );
- pFont->elfw = pEmr->elfw;
- insert_object(d, index, EMR_EXTCREATEFONTINDIRECTW, (ENHMETARECORD *) pFont);
- break;
- }
- case EMR_EXTTEXTOUTA:
- {
- dbg_str << "<!-- EMR_EXTTEXTOUTA -->\n";
- break;
- }
- case EMR_EXTTEXTOUTW:
- {
- dbg_str << "<!-- EMR_EXTTEXTOUTW -->\n";
-
- PEMREXTTEXTOUTW pEmr = (PEMREXTTEXTOUTW) lpEMFR;
-
- double x1 = pEmr->emrtext.ptlReference.x;
- double y1 = pEmr->emrtext.ptlReference.y;
-
- if (d->dc[d->level].textAlign & TA_UPDATECP) {
- x1 = d->dc[d->level].cur.x;
- y1 = d->dc[d->level].cur.y;
- }
-
- double x = pix_to_x_point(d, x1, y1);
- double y = pix_to_y_point(d, x1, y1);
-
- if (!(d->dc[d->level].textAlign & TA_BOTTOM))
- if (d->dc[d->level].style.baseline_shift.value) {
- x += std::sin(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed);
- y += std::cos(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed);
- }
- else
- y += fabs(d->dc[d->level].style.font_size.computed);
-
- wchar_t *wide_text = (wchar_t *) ((char *) pEmr + pEmr->emrtext.offString);
-
- gchar *ansi_text =
- (gchar *) g_utf16_to_utf8( (gunichar2 *) wide_text, pEmr->emrtext.nChars, NULL, NULL, NULL );
-
- if (ansi_text) {
-// gchar *p = ansi_text;
-// while (*p) {
-// if (*p < 32 || *p >= 127) {
-// g_free(ansi_text);
-// ansi_text = g_strdup("");
-// break;
-// }
-// p++;
-// }
-
- SVGOStringStream ts;
-
- gchar *escaped_text = g_markup_escape_text(ansi_text, -1);
-
-// float text_rgb[3];
-// sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), text_rgb );
-
-// if (!d->dc[d->level].textColorSet) {
-// d->dc[d->level].textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]),
-// SP_COLOR_F_TO_U(text_rgb[1]),
-// SP_COLOR_F_TO_U(text_rgb[2]));
-// }
-
- char tmp[128];
- snprintf(tmp, 127,
- "fill:#%02x%02x%02x;",
- GetRValue(d->dc[d->level].textColor),
- GetGValue(d->dc[d->level].textColor),
- GetBValue(d->dc[d->level].textColor));
-
- bool i = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_ITALIC);
- //bool o = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE);
- bool b = (d->dc[d->level].style.font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) ||
- (d->dc[d->level].style.font_weight.value >= SP_CSS_FONT_WEIGHT_500 && d->dc[d->level].style.font_weight.value <= SP_CSS_FONT_WEIGHT_900);
- int lcr = ((d->dc[d->level].textAlign & TA_CENTER) == TA_CENTER) ? 2 : ((d->dc[d->level].textAlign & TA_RIGHT) == TA_RIGHT) ? 1 : 0;
-
- assert_empty_path(d, "EMR_EXTTEXTOUTW");
-
- ts << " <text\n";
-// ts << " id=\"" << (d->id++) << "\"\n";
- ts << " xml:space=\"preserve\"\n";
- ts << " x=\"" << x << "\"\n";
- ts << " y=\"" << y << "\"\n";
- if (d->dc[d->level].style.baseline_shift.value) {
- ts << " transform=\""
- << "rotate(-" << d->dc[d->level].style.baseline_shift.value
- << " " << x << " " << y << ")"
- << "\"\n";
- }
- ts << " style=\""
- << "font-size:" << fabs(d->dc[d->level].style.font_size.computed) << "px;"
- << tmp
- << "font-style:" << (i ? "italic" : "normal") << ";"
- << "font-weight:" << (b ? "bold" : "normal") << ";"
- << "text-align:" << (lcr==2 ? "center" : lcr==1 ? "end" : "start") << ";"
- << "text-anchor:" << (lcr==2 ? "middle" : lcr==1 ? "end" : "start") << ";"
- << "font-family:" << d->dc[d->level].tstyle.font_family.value << ";"
- << "\"\n";
- ts << " >";
- ts << escaped_text;
- ts << "</text>\n";
-
- *(d->outsvg) += ts.str().c_str();
-
- g_free(escaped_text);
- g_free(ansi_text);
- }
-
- break;
- }
- case EMR_POLYBEZIER16:
- {
- dbg_str << "<!-- EMR_POLYBEZIER16 -->\n";
-
- PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR;
- POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
- DWORD i,j;
-
- if (pEmr->cpts<4)
- break;
-
- if (!d->inpath) {
- assert_empty_path(d, "EMR_POLYBEZIER16");
-
- *(d->outsvg) += " <path ";
- output_style(d, EMR_STROKEPATH);
- *(d->outsvg) += "\n\td=\"";
- }
-
- tmp_str <<
- "\n\tM " <<
- pix_to_x_point( d, apts[0].x, apts[0].y ) << " " <<
- pix_to_y_point( d, apts[0].x, apts[0].y ) << " ";
-
- for (i=1; i<pEmr->cpts; ) {
- tmp_str << "\n\tC ";
- for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
- tmp_str <<
- pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
- pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
- }
- }
-
- if (d->inpath) {
- tmp_path << tmp_str.str().c_str();
- }
- else {
- *(d->outsvg) += tmp_str.str().c_str();
- *(d->outsvg) += " \" /> \n";
- }
-
- break;
- }
- case EMR_POLYGON16:
- {
- dbg_str << "<!-- EMR_POLYGON16 -->\n";
-
- PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR;
- POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
- SVGOStringStream tmp_poly;
- unsigned int i;
- unsigned int first = 0;
-
- assert_empty_path(d, "EMR_POLYGON16");
-
- *(d->outsvg) += " <path ";
- output_style(d, EMR_STROKEANDFILLPATH);
- *(d->outsvg) += "\n\td=\"";
-
- // skip the first point?
- tmp_poly << "\n\tM " <<
- pix_to_x_point( d, apts[first].x, apts[first].y ) << " " <<
- pix_to_y_point( d, apts[first].x, apts[first].y ) << " ";
-
- for (i=first+1; i<pEmr->cpts; i++) {
- tmp_poly << "\n\tL " <<
- pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
- pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
- }
-
- *(d->outsvg) += tmp_poly.str().c_str();
- *(d->outsvg) += " z \" /> \n";
-
- break;
- }
- case EMR_POLYLINE16:
- {
- dbg_str << "<!-- EMR_POLYLINE16 -->\n";
-
- EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR;
- POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
- DWORD i;
-
- if (pEmr->cpts<2)
- break;
-
- if (!d->inpath) {
- assert_empty_path(d, "EMR_POLYLINE16");
-
- *(d->outsvg) += " <path ";
- output_style(d, EMR_STROKEPATH);
- *(d->outsvg) += "\n\td=\"";
- }
-
- tmp_str <<
- "\n\tM " <<
- pix_to_x_point( d, apts[0].x, apts[0].y ) << " " <<
- pix_to_y_point( d, apts[0].x, apts[0].y ) << " ";
-
- for (i=1; i<pEmr->cpts; i++) {
- tmp_str <<
- "\n\tL " <<
- pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
- pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
- }
-
- if (d->inpath) {
- tmp_path << tmp_str.str().c_str();
- }
- else {
- *(d->outsvg) += tmp_str.str().c_str();
- *(d->outsvg) += " \" /> \n";
- }
-
- break;
- }
- case EMR_POLYBEZIERTO16:
- {
- dbg_str << "<!-- EMR_POLYBEZIERTO16 -->\n";
-
- PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR;
- POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
- DWORD i,j;
-
- if (d->path->empty()) {
- d->pathless_stroke = true;
- *(d->path) = "d=\"";
- }
-
- for (i=0; i<pEmr->cpts;) {
- tmp_path << "\n\tC ";
- for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
- tmp_path <<
- pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
- pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
- }
- }
-
- break;
- }
- case EMR_POLYLINETO16:
- {
- dbg_str << "<!-- EMR_POLYLINETO16 -->\n";
-
- PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR;
- POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
- DWORD i;
-
- if (d->path->empty()) {
- d->pathless_stroke = true;
- *(d->path) = "d=\"";
- }
-
- for (i=0; i<pEmr->cpts;i++) {
- tmp_path <<
- "\n\tL " <<
- pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
- pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
- }
-
- break;
- }
- case EMR_POLYPOLYLINE16:
- case EMR_POLYPOLYGON16:
- {
- if (lpEMFR->iType == EMR_POLYPOLYLINE16)
- dbg_str << "<!-- EMR_POLYPOLYLINE16 -->\n";
- if (lpEMFR->iType == EMR_POLYPOLYGON16)
- dbg_str << "<!-- EMR_POLYPOLYGON16 -->\n";
-
- PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR;
- unsigned int n, i, j;
-
- if (!d->inpath) {
- assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON16 ? "EMR_POLYPOLYGON16" : "EMR_POLYPOLYLINE16");
-
- *(d->outsvg) += " <path ";
- output_style(d, lpEMFR->iType==EMR_POLYPOLYGON16 ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
- *(d->outsvg) += "\n\td=\"";
- }
-
- POINTS *apts = (POINTS *) &pEmr->aPolyCounts[pEmr->nPolys];
-
- i = 0;
- for (n=0; n<pEmr->nPolys && i<pEmr->cpts; n++) {
- SVGOStringStream poly_path;
-
- poly_path << "\n\tM " <<
- pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
- pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
- i++;
-
- for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cpts; j++) {
- poly_path << "\n\tL " <<
- pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
- pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
- i++;
- }
-
- tmp_str << poly_path.str().c_str();
- if (lpEMFR->iType == EMR_POLYPOLYGON16)
- tmp_str << " z";
- tmp_str << " \n";
- }
-
- if (d->inpath) {
- tmp_path << tmp_str.str().c_str();
- }
- else {
- *(d->outsvg) += tmp_str.str().c_str();
- *(d->outsvg) += " \" /> \n";
- }
-
- break;
- }
- case EMR_POLYDRAW16:
- dbg_str << "<!-- EMR_POLYDRAW16 -->\n";
- break;
- case EMR_CREATEMONOBRUSH:
- dbg_str << "<!-- EMR_CREATEMONOBRUSH -->\n";
- break;
- case EMR_CREATEDIBPATTERNBRUSHPT:
- {
- dbg_str << "<!-- EMR_CREATEDIBPATTERNBRUSHPT -->\n";
-
- PEMRCREATEDIBPATTERNBRUSHPT pEmr = (PEMRCREATEDIBPATTERNBRUSHPT) lpEMFR;
- int index = pEmr->ihBrush;
-
- EMRCREATEDIBPATTERNBRUSHPT *pBrush =
- (EMRCREATEDIBPATTERNBRUSHPT *) malloc( sizeof(EMRCREATEDIBPATTERNBRUSHPT) );
- insert_object(d, index, EMR_CREATEDIBPATTERNBRUSHPT, (ENHMETARECORD *) pBrush);
- break;
- }
- case EMR_EXTCREATEPEN:
- {
- dbg_str << "<!-- EMR_EXTCREATEPEN -->\n";
-
- PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR;
- int index = pEmr->ihPen;
-
- EMREXTCREATEPEN *pPen =
- (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) +
- sizeof(DWORD) * pEmr->elp.elpNumEntries );
- pPen->ihPen = pEmr->ihPen;
- pPen->offBmi = pEmr->offBmi;
- pPen->cbBmi = pEmr->cbBmi;
- pPen->offBits = pEmr->offBits;
- pPen->cbBits = pEmr->cbBits;
- pPen->elp = pEmr->elp;
- for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
- pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i];
- }
- insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen);
-
- break;
- }
- case EMR_POLYTEXTOUTA:
- dbg_str << "<!-- EMR_POLYTEXTOUTA -->\n";
- break;
- case EMR_POLYTEXTOUTW:
- dbg_str << "<!-- EMR_POLYTEXTOUTW -->\n";
- break;
- case EMR_SETICMMODE:
- dbg_str << "<!-- EMR_SETICMMODE -->\n";
- break;
- case EMR_CREATECOLORSPACE:
- dbg_str << "<!-- EMR_CREATECOLORSPACE -->\n";
- break;
- case EMR_SETCOLORSPACE:
- dbg_str << "<!-- EMR_SETCOLORSPACE -->\n";
- break;
- case EMR_DELETECOLORSPACE:
- dbg_str << "<!-- EMR_DELETECOLORSPACE -->\n";
- break;
- case EMR_GLSRECORD:
- dbg_str << "<!-- EMR_GLSRECORD -->\n";
- break;
- case EMR_GLSBOUNDEDRECORD:
- dbg_str << "<!-- EMR_GLSBOUNDEDRECORD -->\n";
- break;
- case EMR_PIXELFORMAT:
- dbg_str << "<!-- EMR_PIXELFORMAT -->\n";
- break;
- default:
- dbg_str << "<!-- EMR_??? -->\n";
- break;
- }
-
-// *(d->outsvg) += dbg_str.str().c_str();
- *(d->outsvg) += tmp_outsvg.str().c_str();
- *(d->path) += tmp_path.str().c_str();
-
- return 1;
-}
-
-static int CALLBACK
-myMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, METARECORD * /*lpMFR*/, int /*nObj*/, LPARAM /*lpData*/)
-{
- g_warning("Unable to import Windows Meta File.\n");
- return 0;
-}
-
-// Aldus Placeable Header ===================================================
-// Since we are a 32bit app, we have to be sure this structure compiles to
-// be identical to a 16 bit app's version. To do this, we use the #pragma
-// to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT
-// for the bbox rectangle.
-#pragma pack( push )
-#pragma pack( 2 )
-typedef struct
-{
- DWORD dwKey;
- WORD hmf;
- SMALL_RECT bbox;
- WORD wInch;
- DWORD dwReserved;
- WORD wCheckSum;
-} APMHEADER, *PAPMHEADER;
-#pragma pack( pop )
-
-
-SPDocument *
-EmfWin32::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
-{
- EMF_CALLBACK_DATA d;
-
- memset(&d, 0, sizeof(d));
-
- d.dc[0].worldTransform.eM11 = 1.0;
- d.dc[0].worldTransform.eM12 = 0.0;
- d.dc[0].worldTransform.eM21 = 0.0;
- d.dc[0].worldTransform.eM22 = 1.0;
- d.dc[0].worldTransform.eDx = 0.0;
- d.dc[0].worldTransform.eDy = 0.0;
-
- gsize bytesRead = 0;
- gsize bytesWritten = 0;
- GError* error = NULL;
- gchar *local_fn =
- g_filename_from_utf8( uri, -1, &bytesRead, &bytesWritten, &error );
-
- if (local_fn == NULL) {
- return NULL;
- }
-
- d.outsvg = new Glib::ustring("");
- d.path = new Glib::ustring("");
- d.outdef = new Glib::ustring("");
-
- CHAR *ansi_uri = (CHAR *) local_fn;
- gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
- WCHAR *unicode_uri = (WCHAR *) unicode_fn;
-
- DWORD filesize = 0;
- HANDLE fp = NULL;
-
- HMETAFILE hmf;
- HENHMETAFILE hemf;
-
- fp = CreateFileW(unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if ( fp != INVALID_HANDLE_VALUE ) {
- filesize = GetFileSize(fp, NULL);
- CloseHandle(fp);
- }
-
- // Try open as Enhanced Metafile
- hemf = GetEnhMetaFileW(unicode_uri);
-
- if (!hemf) {
- // Try open as Windows Metafile
- hmf = GetMetaFileW(unicode_uri);
-
- METAFILEPICT mp;
- HDC hDC;
-
- if (!hmf) {
- WCHAR szTemp[MAX_PATH];
-
- DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH );
- if (dw) {
- hmf = GetMetaFileW( szTemp );
- }
- }
-
- if (hmf) {
- DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );
-
- if (!nSize)
- nSize = filesize;
-
- if (nSize) {
- BYTE *lpvData = new BYTE[nSize];
- if (lpvData) {
- DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );
- if (dw) {
- // Fill out a METAFILEPICT structure
- mp.mm = MM_ANISOTROPIC;
- mp.xExt = 1000;
- mp.yExt = 1000;
- mp.hMF = NULL;
- // Get a reference DC
- hDC = GetDC( NULL );
- // Make an enhanced metafile from the windows metafile
- hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );
- // Clean up
- ReleaseDC( NULL, hDC );
- DeleteMetaFile( hmf );
- hmf = NULL;
- }
- else {
- // EnumMetaFile
- }
- delete[] lpvData;
- }
- else {
- DeleteMetaFile( hmf );
- hmf = NULL;
- }
- }
- else {
- DeleteMetaFile( hmf );
- hmf = NULL;
- }
- }
- else {
- // Try open as Aldus Placeable Metafile
- HANDLE hFile;
- hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
-
- if (hFile != INVALID_HANDLE_VALUE) {
- DWORD nSize = GetFileSize( hFile, NULL );
- if (nSize) {
- BYTE *lpvData = new BYTE[nSize];
- if (lpvData) {
- DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL );
- if (dw) {
- if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) {
- // Fill out a METAFILEPICT structure
- mp.mm = MM_ANISOTROPIC;
- mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left;
- mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
- mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top;
- mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
- mp.hMF = NULL;
- // Get a reference DC
- hDC = GetDC( NULL );
- // Create an enhanced metafile from the bits
- hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp );
- // Clean up
- ReleaseDC( NULL, hDC );
- }
- }
- delete[] lpvData;
- }
- }
- CloseHandle( hFile );
- }
- }
- }
-
- if ((!hemf && !hmf) || !d.outsvg || !d.path) {
- if (d.outsvg)
- delete d.outsvg;
- if (d.path)
- delete d.path;
- if (d.outdef)
- delete d.outdef;
- if (local_fn)
- g_free(local_fn);
- if (unicode_fn)
- g_free(unicode_fn);
- if (hemf)
- DeleteEnhMetaFile(hemf);
- if (hmf)
- DeleteMetaFile(hmf);
- return NULL;
- }
-
- d.pDesc = NULL;
-
- if (hemf) {
- DWORD dwNeeded = GetEnhMetaFileDescriptionA( hemf, 0, NULL );
- if ( dwNeeded > 0 ) {
- d.pDesc = (CHAR *) malloc( dwNeeded + 1 );
- if ( GetEnhMetaFileDescription( hemf, dwNeeded, d.pDesc ) == 0 )
- lstrcpy( d.pDesc, "" );
- if ( lstrlen( d.pDesc ) > 1 )
- d.pDesc[lstrlen(d.pDesc)] = '#';
- }
-
- // This ugly reinterpret_cast is to prevent old versions of gcc from whining about a mismatch in the const-ness of the arguments
- EnumEnhMetaFile(NULL, hemf, reinterpret_cast<ENHMFENUMPROC>(myEnhMetaFileProc), (LPVOID) &d, NULL);
- DeleteEnhMetaFile(hemf);
- }
- else {
- EnumMetaFile(NULL, hmf, myMetaFileProc, (LPARAM) &d);
- DeleteMetaFile(hmf);
- }
-
- if (d.pDesc)
- free( d.pDesc );
-
-// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
-
- SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE);
-
- delete d.outsvg;
- delete d.path;
- delete d.outdef;
-
- if (d.emf_obj) {
- int i;
- for (i=0; i<d.n_obj; i++)
- delete_object(&d, i);
- delete[] d.emf_obj;
- }
-
- if (d.dc[0].style.stroke_dash.dash)
- delete[] d.dc[0].style.stroke_dash.dash;
-
- if (local_fn)
- g_free(local_fn);
- if (unicode_fn)
- g_free(unicode_fn);
-
- return doc;
-}
-
-
-void
-EmfWin32::init (void)
-{
- /* EMF in */
- Inkscape::Extension::build_from_mem(
- "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
- "<name>" N_("EMF Input") "</name>\n"
- "<id>org.inkscape.input.emf.win32</id>\n"
- "<input>\n"
- "<extension>.emf</extension>\n"
- "<mimetype>image/x-emf</mimetype>\n"
- "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"
- "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"
- "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
- "</input>\n"
- "</inkscape-extension>", new EmfWin32());
-
- /* WMF in */
- Inkscape::Extension::build_from_mem(
- "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
- "<name>" N_("WMF Input") "</name>\n"
- "<id>org.inkscape.input.wmf.win32</id>\n"
- "<input>\n"
- "<extension>.wmf</extension>\n"
- "<mimetype>image/x-wmf</mimetype>\n"
- "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"
- "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"
- "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
- "</input>\n"
- "</inkscape-extension>", new EmfWin32());
-
- /* EMF out */
- Inkscape::Extension::build_from_mem(
- "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
- "<name>" N_("EMF Output") "</name>\n"
- "<id>org.inkscape.output.emf.win32</id>\n"
- "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n"
- "<output>\n"
- "<extension>.emf</extension>\n"
- "<mimetype>image/x-emf</mimetype>\n"
- "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"
- "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"
- "</output>\n"
- "</inkscape-extension>", new EmfWin32());
-
- return;
-}
-
-
-} } } /* namespace Inkscape, Extension, Implementation */
-
-#endif /* WIN32 */
-/*
- 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/emf-win32-inout.h b/src/extension/internal/emf-win32-inout.h
deleted file mode 100644
index 4b975c8de..000000000
--- a/src/extension/internal/emf-win32-inout.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/** @file
- * @brief Enhanced Metafile Input/Output
- */
-/* Authors:
- * Ulf Erikson <ulferikson@users.sf.net>
- *
- * Copyright (C) 2006-2008 Authors
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-#ifndef SEEN_EXTENSION_INTERNAL_EMF_WIN32_H
-#define SEEN_EXTENSION_INTERNAL_EMF_WIN32_H
-#ifdef WIN32
-
-#include "extension/implementation/implementation.h"
-
-namespace Inkscape {
-namespace Extension {
-namespace Internal {
-
-class EmfWin32 : Inkscape::Extension::Implementation::Implementation { //This is a derived class
-
-public:
- EmfWin32(); // Empty constructor
-
- virtual ~EmfWin32();//Destructor
-
- bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now)
-
- void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename
- SPDocument *doc,
- gchar const *filename);
-
- virtual SPDocument *open( Inkscape::Extension::Input *mod,
- const gchar *uri );
-
- static void init(void);//Initialize the class
-
-private:
-};
-
-} } } /* namespace Inkscape, Extension, Implementation */
-
-#endif /* WIN32 */
-
-#endif /* EXTENSION_INTERNAL_EMF_WIN32_H */
-
-/*
- 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/emf-win32-print.cpp b/src/extension/internal/emf-win32-print.cpp
deleted file mode 100644
index ef76c2c14..000000000
--- a/src/extension/internal/emf-win32-print.cpp
+++ /dev/null
@@ -1,948 +0,0 @@
-/** @file
- * @brief Enhanced Metafile printing
- */
-/* Authors:
- * Ulf Erikson <ulferikson@users.sf.net>
- * Jon A. Cruz <jon@joncruz.org>
- * Abhishek Sharma
- *
- * Copyright (C) 2006-2009 Authors
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-/*
- * References:
- * - How to Create & Play Enhanced Metafiles in Win32
- * http://support.microsoft.com/kb/q145999/
- * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
- * http://support.microsoft.com/kb/q66949/
- * - Metafile Functions
- * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
- * - Metafile Structures
- * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
- */
-
-#ifdef WIN32
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-
-#include <2geom/pathvector.h>
-#include <2geom/rect.h>
-#include <2geom/bezier-curve.h>
-#include <2geom/hvlinesegment.h>
-#include "helper/geom.h"
-#include "helper/geom-curves.h"
-#include "sp-item.h"
-
-#include "style.h"
-#include "inkscape-version.h"
-#include "sp-root.h"
-
-#include "emf-win32-print.h"
-
-#include "unit-constants.h"
-
-#include "extension/system.h"
-#include "extension/print.h"
-#include "document.h"
-
-
-namespace Inkscape {
-namespace Extension {
-namespace Internal {
-
-static float dwDPI = 2540;
-
-
-PrintEmfWin32::PrintEmfWin32 (void):
- _width(0),
- _height(0),
- hdc(NULL),
- hbrush(NULL),
- hbrushOld(NULL),
- hpen(NULL),
- stroke_and_fill(false),
- fill_only(false),
- simple_shape(false)
-{
-}
-
-
-PrintEmfWin32::~PrintEmfWin32 (void)
-{
- if (hdc) {
- HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
- if ( metafile ) {
- DeleteEnhMetaFile( metafile );
- }
- DeleteDC( hdc );
- }
-
- /* restore default signal handling for SIGPIPE */
-#if !defined(_WIN32) && !defined(__WIN32__)
- (void) signal(SIGPIPE, SIG_DFL);
-#endif
- return;
-}
-
-
-unsigned int PrintEmfWin32::setup (Inkscape::Extension::Print * /*mod*/)
-{
- return TRUE;
-}
-
-
-unsigned int PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
-{
- gchar const *utf8_fn = mod->get_param_string("destination");
-
- gsize bytesRead = 0;
- gsize bytesWritten = 0;
- GError* error = NULL;
- gchar *local_fn =
- g_filename_from_utf8( utf8_fn, -1, &bytesRead, &bytesWritten, &error );
-
- if (local_fn == NULL) {
- return 1;
- }
-
- CHAR *ansi_uri = (CHAR *) local_fn;
- gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
- WCHAR *unicode_uri = (WCHAR *) unicode_fn;
-
- // width and height in px
- _width = doc->getWidth();
- _height = doc->getHeight();
-
- bool pageBoundingBox;
- pageBoundingBox = mod->get_param_bool("pageBoundingBox");
-
- Geom::Rect d;
- if (pageBoundingBox) {
- d = Geom::Rect::from_xywh(0, 0, _width, _height);
- } else {
- SPItem* doc_item = doc->getRoot();
- Geom::OptRect bbox = doc_item->desktopVisualBounds();
- if (bbox) d = *bbox;
- }
-
- d *= Geom::Scale(IN_PER_PX);
-
- float dwInchesX = d.width();
- float dwInchesY = d.height();
-
- // dwInchesX x dwInchesY in .01mm units
- SetRect( &rc, 0, 0, (int) ceil(dwInchesX*2540), (int) ceil(dwInchesY*2540) );
-
- // Get a Reference DC
- HDC hScreenDC = GetDC( NULL );
-
- // Get the physical characteristics of the reference DC
- int PixelsX = GetDeviceCaps( hScreenDC, HORZRES );
- int PixelsY = GetDeviceCaps( hScreenDC, VERTRES );
- int MMX = GetDeviceCaps( hScreenDC, HORZSIZE );
- int MMY = GetDeviceCaps( hScreenDC, VERTSIZE );
-
- CHAR buff[1024];
- ZeroMemory(buff, sizeof(buff));
- snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)", Inkscape::version_string, __DATE__);
- INT len = strlen(buff);
- CHAR *p1 = strrchr(ansi_uri, '\\');
- CHAR *p2 = strrchr(ansi_uri, '/');
- CHAR *p = MAX(p1, p2);
- if (p)
- p++;
- else
- p = ansi_uri;
- snprintf(buff+len+1, sizeof(buff)-len-2, "%s", p);
-
- // Create the Metafile
- {
- WCHAR wbuff[1024];
- ZeroMemory(wbuff, sizeof(wbuff));
- MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, sizeof(buff)/sizeof(buff[0]), wbuff, sizeof(wbuff)/sizeof(wbuff[0]));
- hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, wbuff );
- }
-
- // Release the reference DC
- ReleaseDC( NULL, hScreenDC );
-
- // Did we get a good metafile?
- if (hdc == NULL)
- {
- g_free(local_fn);
- g_free(unicode_fn);
- return 1;
- }
-
- // Anisotropic mapping mode
- SetMapMode( hdc, MM_ANISOTROPIC );
-
- // Set the Windows extent
- int windowextX = (int) ceil(dwInchesX*dwDPI);
- int windowextY = (int) ceil(dwInchesY*dwDPI);
- SetWindowExtEx( hdc, windowextX, windowextY, NULL );
-
- // Set the viewport extent to reflect
- // dwInchesX" x dwInchesY" in device units
- int viewportextX = (int)((float)dwInchesX*25.4f*(float)PixelsX/(float)MMX);
- int viewportextY = (int)((float)dwInchesY*25.4f*(float)PixelsY/(float)MMY);
- SetViewportExtEx( hdc, viewportextX, viewportextY, NULL );
-
- if (1) {
- snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY);
- GdiComment(hdc, strlen(buff), (BYTE*) buff);
-
- snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * MM_PER_IN, dwInchesY * MM_PER_IN);
- GdiComment(hdc, strlen(buff), (BYTE*) buff);
- }
-
- SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) );
-
- g_free(local_fn);
- g_free(unicode_fn);
-
- m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, doc->getHeight())); /// @fixme hardcoded doc2dt transform
-
- return 0;
-}
-
-
-unsigned int PrintEmfWin32::finish (Inkscape::Extension::Print * /*mod*/)
-{
- if (!hdc) return 0;
-
- flush_fill(); // flush any pending fills
-
- HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
- if ( metafile ) {
- DeleteEnhMetaFile( metafile );
- }
- DeleteDC( hdc );
-
- hdc = NULL;
-
- return 0;
-}
-
-
-unsigned int PrintEmfWin32::comment (Inkscape::Extension::Print * /*module*/,
- const char * /*comment*/)
-{
- if (!hdc) return 0;
-
- flush_fill(); // flush any pending fills
-
- return 0;
-}
-
-
-int PrintEmfWin32::create_brush(SPStyle const *style)
-{
- float rgb[3];
-
- if (style) {
- float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
- if (opacity <= 0.0)
- return 1;
-
- sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
- hbrush = CreateSolidBrush( RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]) );
- hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
-
- SetPolyFillMode( hdc,
- style->fill_rule.computed == 0 ? WINDING :
- style->fill_rule.computed == 2 ? ALTERNATE : ALTERNATE );
- } else { // if (!style)
- hbrush = CreateSolidBrush( RGB(255, 255, 255) );
- hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
- SetPolyFillMode( hdc, ALTERNATE );
- }
-
- return 0;
-}
-
-
-void PrintEmfWin32::destroy_brush()
-{
- SelectObject( hdc, hbrushOld );
- if (hbrush)
- DeleteObject( hbrush );
- hbrush = NULL;
- hbrushOld = NULL;
-}
-
-
-void PrintEmfWin32::create_pen(SPStyle const *style, const Geom::Affine &transform)
-{
- if (style) {
- float rgb[3];
-
- sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
-
- LOGBRUSH lb;
- ZeroMemory(&lb, sizeof(lb));
- lb.lbStyle = BS_SOLID;
- lb.lbColor = RGB( 255*rgb[0], 255*rgb[1], 255*rgb[2] );
-
- int linestyle = PS_SOLID;
- int linecap = 0;
- int linejoin = 0;
- DWORD n_dash = 0;
- DWORD *dash = NULL;
-
- using Geom::X;
- using Geom::Y;
-
- Geom::Point zero(0, 0);
- Geom::Point one(1, 1);
- Geom::Point p0(zero * transform);
- Geom::Point p1(one * transform);
- Geom::Point p(p1 - p0);
-
- double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2);
-
- DWORD linewidth = MAX( 1, (DWORD) (scale * style->stroke_width.computed * IN_PER_PX * dwDPI) );
-
- if (style->stroke_linecap.computed == 0) {
- linecap = PS_ENDCAP_FLAT;
- }
- else if (style->stroke_linecap.computed == 1) {
- linecap = PS_ENDCAP_ROUND;
- }
- else if (style->stroke_linecap.computed == 2) {
- linecap = PS_ENDCAP_SQUARE;
- }
-
- if (style->stroke_linejoin.computed == 0) {
- linejoin = PS_JOIN_MITER;
- }
- else if (style->stroke_linejoin.computed == 1) {
- linejoin = PS_JOIN_ROUND;
- }
- else if (style->stroke_linejoin.computed == 2) {
- linejoin = PS_JOIN_BEVEL;
- }
-
- if (style->stroke_dash.n_dash &&
- style->stroke_dash.dash )
- {
- int i = 0;
- while (linestyle != PS_USERSTYLE &&
- (i < style->stroke_dash.n_dash)) {
- if (style->stroke_dash.dash[i] > 0.00000001)
- linestyle = PS_USERSTYLE;
- i++;
- }
-
- if (linestyle == PS_USERSTYLE) {
- n_dash = style->stroke_dash.n_dash;
- dash = new DWORD[n_dash];
- for (i = 0; i < style->stroke_dash.n_dash; i++) {
- dash[i] = (DWORD) (style->stroke_dash.dash[i] * IN_PER_PX * dwDPI);
- }
- }
- }
-
- hpen = ExtCreatePen(
- PS_GEOMETRIC | linestyle | linecap | linejoin,
- linewidth,
- &lb,
- n_dash,
- dash );
-
- if ( !hpen && linestyle == PS_USERSTYLE ) {
- hpen = ExtCreatePen(
- PS_GEOMETRIC | PS_SOLID | linecap | linejoin,
- linewidth,
- &lb,
- 0,
- NULL );
- }
-
- if ( !hpen ) {
- hpen = CreatePen(
- PS_SOLID,
- linewidth,
- lb.lbColor );
- }
-
- hpenOld = (HPEN) SelectObject( hdc, hpen );
-
- if (linejoin == PS_JOIN_MITER) {
- float oldmiterlimit;
- float miterlimit = style->stroke_miterlimit.value;
-
- miterlimit = miterlimit * 10.0 / 4.0;
- if (miterlimit < 1)
- miterlimit = 10.0;
-
- miterlimit = miterlimit * IN_PER_PX * dwDPI;
-
- SetMiterLimit(
- hdc,
- miterlimit,
- &oldmiterlimit );
- }
-
- if (n_dash) {
- delete[] dash;
- }
- }
- else { // if (!style)
- hpen = CreatePen( PS_SOLID, 1, RGB(0, 0, 0) );
- hpenOld = (HPEN) SelectObject( hdc, hpen );
- }
-}
-
-
-void PrintEmfWin32::destroy_pen()
-{
- SelectObject( hdc, hpenOld );
- if (hpen)
- DeleteObject( hpen );
- hpen = NULL;
-}
-
-
-void PrintEmfWin32::flush_fill()
-{
- if (!fill_pathv.empty()) {
- stroke_and_fill = false;
- fill_only = true;
- print_pathv(fill_pathv, fill_transform);
- fill_only = false;
- if (!simple_shape)
- FillPath( hdc );
- destroy_brush();
- fill_pathv.clear();
- }
-}
-
-unsigned int PrintEmfWin32::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/)
-{
- if (!m_tr_stack.empty()) {
- Geom::Affine tr_top = m_tr_stack.top();
- m_tr_stack.push(transform * tr_top);
- } else {
- m_tr_stack.push(transform);
- }
-
- return 1;
-}
-
-unsigned int PrintEmfWin32::release(Inkscape::Extension::Print * /*mod*/)
-{
- m_tr_stack.pop();
- return 1;
-}
-
-unsigned int PrintEmfWin32::fill(Inkscape::Extension::Print * /*mod*/,
- Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style,
- Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
-{
- if (!hdc) return 0;
-
- Geom::Affine tf = m_tr_stack.top();
-
- flush_fill(); // flush any pending fills
-
- if (style->fill.isColor()) {
- if (create_brush(style))
- return 0;
- } else {
- // create_brush(NULL);
- return 0;
- }
-
- fill_pathv.clear();
- std::copy(pathv.begin(), pathv.end(), std::back_inserter(fill_pathv));
- fill_transform = tf;
-
- // postpone fill in case of stroke-and-fill
-
- return 0;
-}
-
-
-unsigned int PrintEmfWin32::stroke (Inkscape::Extension::Print * /*mod*/,
- Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style,
- Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
-{
- if (!hdc) return 0;
-
- Geom::Affine tf = m_tr_stack.top();
-
- stroke_and_fill = ( pathv == fill_pathv );
-
- if (!stroke_and_fill) {
- flush_fill(); // flush any pending fills
- }
-
- if (style->stroke.isColor()) {
- create_pen(style, tf);
- } else {
- // create_pen(NULL, tf);
- return 0;
- }
-
- print_pathv(pathv, tf);
-
- if (stroke_and_fill) {
- if (!simple_shape)
- StrokeAndFillPath( hdc );
- destroy_brush();
- fill_pathv.clear();
- } else {
- if (!simple_shape)
- StrokePath( hdc );
- }
-
- destroy_pen();
-
- return 0;
-}
-
-
-bool PrintEmfWin32::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform)
-{
- Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform );
-
- int nodes = 0;
- int moves = 0;
- int lines = 0;
- int curves = 0;
-
- for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
- {
- moves++;
- nodes++;
-
- for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
- {
- nodes++;
-
- if ( is_straight_curve(*cit) ) {
- lines++;
- }
- else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) {
- cubic = cubic;
- curves++;
- }
- }
- }
-
- if (!nodes)
- return false;
-
- POINT *lpPoints = new POINT[moves + lines + curves*3];
- int i = 0;
-
- /**
- * For all Subpaths in the <path>
- */
- for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
- {
- using Geom::X;
- using Geom::Y;
-
- Geom::Point p0 = pit->initialPoint();
-
- p0[X] = (p0[X] * IN_PER_PX * dwDPI);
- p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
-
- LONG const x0 = (LONG) round(p0[X]);
- LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
-
- lpPoints[i].x = x0;
- lpPoints[i].y = y0;
- i = i + 1;
-
- /**
- * For all segments in the subpath
- */
- for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
- {
- if ( is_straight_curve(*cit) )
- {
- //Geom::Point p0 = cit->initialPoint();
- Geom::Point p1 = cit->finalPoint();
-
- //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
- p1[X] = (p1[X] * IN_PER_PX * dwDPI);
- //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
- p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
-
- //LONG const x0 = (LONG) round(p0[X]);
- //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
- LONG const x1 = (LONG) round(p1[X]);
- LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
-
- lpPoints[i].x = x1;
- lpPoints[i].y = y1;
- i = i + 1;
- }
- else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
- {
- std::vector<Geom::Point> points = cubic->points();
- //Geom::Point p0 = points[0];
- Geom::Point p1 = points[1];
- Geom::Point p2 = points[2];
- Geom::Point p3 = points[3];
-
- //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
- p1[X] = (p1[X] * IN_PER_PX * dwDPI);
- p2[X] = (p2[X] * IN_PER_PX * dwDPI);
- p3[X] = (p3[X] * IN_PER_PX * dwDPI);
- //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
- p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
- p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
- p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
-
- //LONG const x0 = (LONG) round(p0[X]);
- //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
- LONG const x1 = (LONG) round(p1[X]);
- LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
- LONG const x2 = (LONG) round(p2[X]);
- LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
- LONG const x3 = (LONG) round(p3[X]);
- LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
-
- POINT pt[3];
- pt[0].x = x1;
- pt[0].y = y1;
- pt[1].x = x2;
- pt[1].y = y2;
- pt[2].x = x3;
- pt[2].y = y3;
-
- lpPoints[i].x = x1;
- lpPoints[i].y = y1;
- lpPoints[i+1].x = x2;
- lpPoints[i+1].y = y2;
- lpPoints[i+2].x = x3;
- lpPoints[i+2].y = y3;
- i = i + 3;
- }
- }
- }
-
- bool done = false;
- bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y);
- bool polygon = false;
- bool rectangle = false;
- bool ellipse = false;
-
- if (moves == 1 && moves+lines == nodes && closed) {
- polygon = true;
-// if (nodes==5) { // disable due to LP Bug 407394
-// if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x &&
-// lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y)
-// {
-// rectangle = true;
-// }
-// }
- }
- else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) {
-// if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
-// lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
-// lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
-// lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
-// lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
-// lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
-// { // disable due to LP Bug 407394
-// ellipse = true;
-// }
- }
-
- if (polygon || ellipse) {
- HPEN hpenTmp = NULL;
- HPEN hpenOld = NULL;
- HBRUSH hbrushTmp = NULL;
- HBRUSH hbrushOld = NULL;
-
- if (!stroke_and_fill) {
- if (fill_only) {
- hpenTmp = (HPEN) GetStockObject(NULL_PEN);
- hpenOld = (HPEN) SelectObject( hdc, hpenTmp );
- }
- else { // if (stroke_only)
- hbrushTmp = (HBRUSH) GetStockObject(NULL_BRUSH);
- hbrushOld = (HBRUSH) SelectObject( hdc, hbrushTmp );
- }
- }
-
- if (polygon) {
- if (rectangle)
- Rectangle( hdc, lpPoints[0].x, lpPoints[0].y, lpPoints[2].x, lpPoints[2].y );
- else
- Polygon( hdc, lpPoints, nodes );
- }
- else if (ellipse) {
- Ellipse( hdc, lpPoints[6].x, lpPoints[3].y, lpPoints[0].x, lpPoints[9].y);
- }
-
- done = true;
-
- if (hpenOld)
- SelectObject( hdc, hpenOld );
- if (hpenTmp)
- DeleteObject( hpenTmp );
- if (hbrushOld)
- SelectObject( hdc, hbrushOld );
- if (hbrushTmp)
- DeleteObject( hbrushTmp );
- }
-
- delete[] lpPoints;
-
- return done;
-}
-
-unsigned int PrintEmfWin32::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform)
-{
- simple_shape = print_simple_shape(pathv, transform);
-
- if (simple_shape)
- return TRUE;
-
- Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform );
-
- BeginPath( hdc );
-
- /**
- * For all Subpaths in the <path>
- */
- for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
- {
- using Geom::X;
- using Geom::Y;
-
- Geom::Point p0 = pit->initialPoint();
-
- p0[X] = (p0[X] * IN_PER_PX * dwDPI);
- p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
-
- LONG const x0 = (LONG) round(p0[X]);
- LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
-
- MoveToEx( hdc, x0, y0, NULL );
-
- /**
- * For all segments in the subpath
- */
- for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
- {
- if ( is_straight_curve(*cit) )
- {
- //Geom::Point p0 = cit->initialPoint();
- Geom::Point p1 = cit->finalPoint();
-
- //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
- p1[X] = (p1[X] * IN_PER_PX * dwDPI);
- //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
- p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
-
- //LONG const x0 = (LONG) round(p0[X]);
- //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
- LONG const x1 = (LONG) round(p1[X]);
- LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
-
- LineTo( hdc, x1, y1 );
- }
- else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
- {
- std::vector<Geom::Point> points = cubic->points();
- //Geom::Point p0 = points[0];
- Geom::Point p1 = points[1];
- Geom::Point p2 = points[2];
- Geom::Point p3 = points[3];
-
- //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
- p1[X] = (p1[X] * IN_PER_PX * dwDPI);
- p2[X] = (p2[X] * IN_PER_PX * dwDPI);
- p3[X] = (p3[X] * IN_PER_PX * dwDPI);
- //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
- p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
- p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
- p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
-
- //LONG const x0 = (LONG) round(p0[X]);
- //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
- LONG const x1 = (LONG) round(p1[X]);
- LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
- LONG const x2 = (LONG) round(p2[X]);
- LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
- LONG const x3 = (LONG) round(p3[X]);
- LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
-
- POINT pt[3];
- pt[0].x = x1;
- pt[0].y = y1;
- pt[1].x = x2;
- pt[1].y = y2;
- pt[2].x = x3;
- pt[2].y = y3;
-
- PolyBezierTo( hdc, pt, 3 );
- }
- else
- {
- g_warning("logical error, because pathv_to_linear_and_cubic_beziers was used");
- }
- }
-
- if (pit->end_default() == pit->end_closed()) {
- CloseFigure( hdc );
- }
- }
-
- EndPath( hdc );
-
- return TRUE;
-}
-
-
-bool PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext)
-{
- return ext->get_param_bool("textToPath");
-}
-
-unsigned int PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p,
- SPStyle const *const style)
-{
- if (!hdc) return 0;
-
- HFONT hfont = NULL;
- Geom::Affine tf = m_tr_stack.top();
- double rot = 1800.0*std::atan2(tf[1], tf[0])/M_PI; // 0.1 degree rotation
-
-#ifdef USE_PANGO_WIN32
-/*
- font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style));
- if (tf) {
- LOGFONT *lf = pango_win32_font_logfont(tf->pFont);
- tf->Unref();
- hfont = CreateFontIndirect(lf);
- g_free(lf);
- }
-*/
-#endif
-
- if (!hfont) {
- LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW));
- g_assert(lf != NULL);
-
- lf->lfHeight = -style->font_size.computed * IN_PER_PX * dwDPI;
- lf->lfWidth = 0;
- lf->lfEscapement = rot;
- lf->lfOrientation = rot;
- lf->lfWeight =
- style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
- style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
- style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
- style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
- style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
- style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
- style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
- style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
- style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
- FW_NORMAL;
- lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC);
- lf->lfUnderline = style->text_decoration.underline;
- lf->lfStrikeOut = style->text_decoration.line_through;
- lf->lfCharSet = DEFAULT_CHARSET;
- lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
- lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf->lfQuality = DEFAULT_QUALITY;
- lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
-
- gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL );
- wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1);
- g_free(unicode_name);
-
- hfont = CreateFontIndirectW(lf);
-
- g_free(lf);
- }
-
- HFONT hfontOld = (HFONT) SelectObject(hdc, hfont);
-
- float rgb[3];
- sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
- SetTextColor(hdc, RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]));
-
- // Text alignment:
- // - (x,y) coordinates received by this filter are those of the point where the text
- // actually starts, and already takes into account the text object's alignment;
- // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT.
- SetTextAlign(hdc, TA_BASELINE | TA_LEFT);
-
- // Transparent text background
- SetBkMode(hdc, TRANSPARENT);
-
- Geom::Point p2 = p * tf;
- p2[Geom::X] = (p2[Geom::X] * IN_PER_PX * dwDPI);
- p2[Geom::Y] = (p2[Geom::Y] * IN_PER_PX * dwDPI);
-
- LONG const xpos = (LONG) round(p2[Geom::X]);
- LONG const ypos = (LONG) round(rc.bottom - p2[Geom::Y]);
-
- {
- gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL );
- TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text));
- }
-
- SelectObject(hdc, hfontOld);
- DeleteObject(hfont);
-
- return 0;
-}
-
-void PrintEmfWin32::init (void)
-{
- /* EMF print */
- Inkscape::Extension::build_from_mem(
- "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
- "<name>Enhanced Metafile Print</name>\n"
- "<id>org.inkscape.print.emf.win32</id>\n"
- "<param name=\"destination\" type=\"string\"></param>\n"
- "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
- "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n"
- "<print/>\n"
- "</inkscape-extension>", new PrintEmfWin32());
-
- return;
-}
-
-unsigned int PrintEmfWin32::image(Inkscape::Extension::Print * /* module */, /** not used */
- unsigned char *px, /** array of pixel values, Gdk::Pixbuf bitmap format */
- unsigned int /*w*/, /** width of bitmap */
- unsigned int /*h*/, /** height of bitmap */
- unsigned int /*rs*/, /** row stride (normally w*4) */
- Geom::Affine const & /*tf_ignore*/, /** WRONG affine transform, use the one from m_tr_stack */
- SPStyle const * /*style*/) /** provides indirect link to image object */
-{
- free(px);
- return 0;
-}
-
-} /* namespace Internal */
-} /* namespace Extension */
-} /* namespace Inkscape */
-
-#endif /* WIN32 */
-
-/*
- 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/filter/bevels.h b/src/extension/internal/filter/bevels.h
index 6fc73e58a..ea9d537ad 100644
--- a/src/extension/internal/filter/bevels.h
+++ b/src/extension/internal/filter/bevels.h
@@ -52,9 +52,9 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Diffuse Light") "</name>\n"
"<id>org.inkscape.effect.filter.DiffuseLight</id>\n"
- "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"10\">6</param>\n"
- "<param name=\"elevation\" gui-text=\"" N_("Elevation (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">25</param>\n"
- "<param name=\"azimuth\" gui-text=\"" N_("Azimuth (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">235</param>\n"
+ "<param name=\"smooth\" gui-text=\"" N_("Smoothness") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"10\">6</param>\n"
+ "<param name=\"elevation\" gui-text=\"" N_("Elevation (°)") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">25</param>\n"
+ "<param name=\"azimuth\" gui-text=\"" N_("Azimuth (°)") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">235</param>\n"
"<param name=\"color\" gui-text=\"" N_("Lighting color") "\" type=\"color\">-1</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -132,10 +132,10 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Matte Jelly") "</name>\n"
"<id>org.inkscape.effect.filter.MatteJelly</id>\n"
- "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"10.00\">7</param>\n"
- "<param name=\"bright\" gui-text=\"" N_("Brightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"5.00\">0.9</param>\n"
- "<param name=\"elevation\" gui-text=\"" N_("Elevation (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">60</param>\n"
- "<param name=\"azimuth\" gui-text=\"" N_("Azimuth (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">225</param>\n"
+ "<param name=\"smooth\" gui-text=\"" N_("Smoothness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"10.00\">7</param>\n"
+ "<param name=\"bright\" gui-text=\"" N_("Brightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"5.00\">0.9</param>\n"
+ "<param name=\"elevation\" gui-text=\"" N_("Elevation (°)") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">60</param>\n"
+ "<param name=\"azimuth\" gui-text=\"" N_("Azimuth (°)") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">225</param>\n"
"<param name=\"color\" gui-text=\"" N_("Lighting color") "\" type=\"color\">-1</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -216,10 +216,10 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Specular Light") "</name>\n"
"<id>org.inkscape.effect.filter.SpecularLight</id>\n"
- "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"10\">6</param>\n"
- "<param name=\"bright\" gui-text=\"" N_("Brightness:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"5\">1</param>\n"
- "<param name=\"elevation\" gui-text=\"" N_("Elevation (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">45</param>\n"
- "<param name=\"azimuth\" gui-text=\"" N_("Azimuth (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">235</param>\n"
+ "<param name=\"smooth\" gui-text=\"" N_("Smoothness") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"10\">6</param>\n"
+ "<param name=\"bright\" gui-text=\"" N_("Brightness") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"5\">1</param>\n"
+ "<param name=\"elevation\" gui-text=\"" N_("Elevation (°)") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">45</param>\n"
+ "<param name=\"azimuth\" gui-text=\"" N_("Azimuth (°)") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">235</param>\n"
"<param name=\"color\" gui-text=\"" N_("Lighting color") "\" type=\"color\">-1</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
diff --git a/src/extension/internal/filter/blurs.h b/src/extension/internal/filter/blurs.h
index 59790b1be..fe1b9c930 100644
--- a/src/extension/internal/filter/blurs.h
+++ b/src/extension/internal/filter/blurs.h
@@ -53,8 +53,8 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Blur") "</name>\n"
"<id>org.inkscape.effect.filter.Blur</id>\n"
- "<param name=\"hblur\" gui-text=\"" N_("Horizontal blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">2</param>\n"
- "<param name=\"vblur\" gui-text=\"" N_("Vertical blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">2</param>\n"
+ "<param name=\"hblur\" gui-text=\"" N_("Horizontal blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">2</param>\n"
+ "<param name=\"vblur\" gui-text=\"" N_("Vertical blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">2</param>\n"
"<param name=\"content\" gui-text=\"" N_("Blur content only") "\" type=\"boolean\">False</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -124,7 +124,7 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Clean Edges") "</name>\n"
"<id>org.inkscape.effect.filter.CleanEdges</id>\n"
- "<param name=\"blur\" gui-text=\"" N_("Strength:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"2.00\">0.4</param>\n"
+ "<param name=\"blur\" gui-text=\"" N_("Strength") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"2.00\">0.4</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -184,10 +184,10 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Cross Blur") "</name>\n"
"<id>org.inkscape.effect.filter.CrossBlur</id>\n"
- "<param name=\"bright\" gui-text=\"" N_("Brightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"10.00\">0</param>\n"
- "<param name=\"fade\" gui-text=\"" N_("Fading:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.00\">0</param>\n"
- "<param name=\"hblur\" gui-text=\"" N_("Horizontal blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">5</param>\n"
- "<param name=\"vblur\" gui-text=\"" N_("Vertical blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">5</param>\n"
+ "<param name=\"bright\" gui-text=\"" N_("Brightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"10.00\">0</param>\n"
+ "<param name=\"fade\" gui-text=\"" N_("Fading") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.00\">0</param>\n"
+ "<param name=\"hblur\" gui-text=\"" N_("Horizontal blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">5</param>\n"
+ "<param name=\"vblur\" gui-text=\"" N_("Vertical blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">5</param>\n"
"<param name=\"blend\" gui-text=\"" N_("Blend:") "\" type=\"enum\">\n"
"<_item value=\"darken\">" N_("Darken") "</_item>\n"
"<_item value=\"screen\">" N_("Screen") "</_item>\n"
@@ -259,7 +259,7 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Feather") "</name>\n"
"<id>org.inkscape.effect.filter.Feather</id>\n"
- "<param name=\"blur\" gui-text=\"" N_("Strength:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">5</param>\n"
+ "<param name=\"blur\" gui-text=\"" N_("Strength") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">5</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -326,11 +326,11 @@ public:
"<id>org.inkscape.effect.filter.ImageBlur</id>\n"
"<param name=\"tab\" type=\"notebook\">\n"
"<page name=\"optionstab\" _gui-text=\"Options\">\n"
- "<param name=\"hblur\" gui-text=\"" N_("Horizontal blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"50.00\">3</param>\n"
- "<param name=\"vblur\" gui-text=\"" N_("Vertical blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"50.00\">3</param>\n"
- "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">6</param>\n"
- "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">2</param>\n"
- "<param name=\"opacity\" gui-text=\"" N_("Opacity:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1\">1</param>\n"
+ "<param name=\"hblur\" gui-text=\"" N_("Horizontal blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"50.00\">3</param>\n"
+ "<param name=\"vblur\" gui-text=\"" N_("Vertical blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"50.00\">3</param>\n"
+ "<param name=\"dilat\" gui-text=\"" N_("Dilatation") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">6</param>\n"
+ "<param name=\"erosion\" gui-text=\"" N_("Erosion") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">2</param>\n"
+ "<param name=\"opacity\" gui-text=\"" N_("Opacity") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1\">1</param>\n"
"</page>\n"
"<page name=\"backgroundtab\" _gui-text=\"Background\">\n"
"<param name=\"color\" gui-text=\"" N_("Background color") "\" type=\"color\">-1</param>\n"
diff --git a/src/extension/internal/filter/bumps.h b/src/extension/internal/filter/bumps.h
index 8db6c67d2..b59b1ef50 100644
--- a/src/extension/internal/filter/bumps.h
+++ b/src/extension/internal/filter/bumps.h
@@ -81,13 +81,13 @@ public:
"<id>org.inkscape.effect.filter.Bump</id>\n"
"<param name=\"tab\" type=\"notebook\">\n"
"<page name=\"optionstab\" _gui-text=\"Options\">\n"
- "<param name=\"simplifyImage\" gui-text=\"" N_("Image simplification:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">0.01</param>\n"
- "<param name=\"simplifyBump\" gui-text=\"" N_("Bump simplification:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">0.01</param>\n"
- "<param name=\"crop\" gui-text=\"" N_("Crop:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">0</param>\n"
+ "<param name=\"simplifyImage\" gui-text=\"" N_("Image simplification") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">0.01</param>\n"
+ "<param name=\"simplifyBump\" gui-text=\"" N_("Bump simplification") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">0.01</param>\n"
+ "<param name=\"crop\" gui-text=\"" N_("Crop") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">0</param>\n"
"<_param name=\"sourceHeader\" type=\"description\" appearance=\"header\">" N_("Bump source") "</_param>\n"
- "<param name=\"red\" gui-text=\"" N_("Red:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">0</param>\n"
- "<param name=\"green\" gui-text=\"" N_("Green:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">0</param>\n"
- "<param name=\"blue\" gui-text=\"" N_("Blue:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">0</param>\n"
+ "<param name=\"red\" gui-text=\"" N_("Red") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">0</param>\n"
+ "<param name=\"green\" gui-text=\"" N_("Green") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">0</param>\n"
+ "<param name=\"blue\" gui-text=\"" N_("Blue") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">0</param>\n"
"<param name=\"background\" gui-text=\"" N_("Bump from background") "\" indent=\"1\" type=\"boolean\">false</param>\n"
"</page>\n"
"<page name=\"lightingtab\" _gui-text=\"Lighting\">\n"
@@ -95,9 +95,9 @@ public:
"<_item value=\"specular\">" N_("Specular") "</_item>\n"
"<_item value=\"diffuse\">" N_("Diffuse") "</_item>\n"
"</param>\n"
- "<param name=\"height\" gui-text=\"" N_("Height:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"50.\">5</param>\n"
- "<param name=\"lightness\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"5.\">1</param>\n"
- "<param name=\"precision\" gui-text=\"" N_("Precision:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"128\">15</param>\n"
+ "<param name=\"height\" gui-text=\"" N_("Height") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"50.\">5</param>\n"
+ "<param name=\"lightness\" gui-text=\"" N_("Lightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"5.\">1</param>\n"
+ "<param name=\"precision\" gui-text=\"" N_("Precision") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"128\">15</param>\n"
"<param name=\"lightingColor\" gui-text=\"" N_("Color") "\" type=\"color\">-1</param>\n"
"</page>\n"
"<page name=\"lightsourcetab\" _gui-text=\"" N_("Light source") "\">\n"
@@ -107,21 +107,21 @@ public:
"<_item value=\"spot\">" N_("Spot") "</_item>\n"
"</param>\n"
"<_param name=\"distantHeader\" type=\"description\" appearance=\"header\">" N_("Distant light options") "</_param>\n"
- "<param name=\"distantAzimuth\" gui-text=\"" N_("Azimuth:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"360\">225</param>\n"
- "<param name=\"distantElevation\" gui-text=\"" N_("Elevation:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"180\">45</param>\n"
+ "<param name=\"distantAzimuth\" gui-text=\"" N_("Azimuth") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"360\">225</param>\n"
+ "<param name=\"distantElevation\" gui-text=\"" N_("Elevation") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"180\">45</param>\n"
"<_param name=\"pointHeader\" type=\"description\" appearance=\"header\">" N_("Point light options") "</_param>\n"
- "<param name=\"pointX\" gui-text=\"" N_("X location:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">526</param>\n"
- "<param name=\"pointY\" gui-text=\"" N_("Y location:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">372</param>\n"
- "<param name=\"pointZ\" gui-text=\"" N_("Z location:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"5000\">150</param>\n"
+ "<param name=\"pointX\" gui-text=\"" N_("X location") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">526</param>\n"
+ "<param name=\"pointY\" gui-text=\"" N_("Y location") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">372</param>\n"
+ "<param name=\"pointZ\" gui-text=\"" N_("Z location") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"5000\">150</param>\n"
"<_param name=\"spotHeader\" type=\"description\" appearance=\"header\">" N_("Spot light options") "</_param>\n"
- "<param name=\"spotX\" gui-text=\"" N_("X location:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">526</param>\n"
- "<param name=\"spotY\" gui-text=\"" N_("Y location:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">372</param>\n"
- "<param name=\"spotZ\" gui-text=\"" N_("Z location:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">150</param>\n"
- "<param name=\"spotAtX\" gui-text=\"" N_("X target:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">0</param>\n"
- "<param name=\"spotAtY\" gui-text=\"" N_("Y target:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">0</param>\n"
- "<param name=\"spotAtZ\" gui-text=\"" N_("Z target:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"0\">-1000</param>\n"
- "<param name=\"spotExponent\" gui-text=\"" N_("Specular exponent:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"1\" max=\"100\">1</param>\n"
- "<param name=\"spotConeAngle\" gui-text=\"" N_("Cone angle:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"100\">50</param>\n"
+ "<param name=\"spotX\" gui-text=\"" N_("X location") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">526</param>\n"
+ "<param name=\"spotY\" gui-text=\"" N_("Y location") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">372</param>\n"
+ "<param name=\"spotZ\" gui-text=\"" N_("Z location") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">150</param>\n"
+ "<param name=\"spotAtX\" gui-text=\"" N_("X target") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">0</param>\n"
+ "<param name=\"spotAtY\" gui-text=\"" N_("Y target") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"5000\">0</param>\n"
+ "<param name=\"spotAtZ\" gui-text=\"" N_("Z target") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"-5000\" max=\"0\">-1000</param>\n"
+ "<param name=\"spotExponent\" gui-text=\"" N_("Specular exponent") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"1\" max=\"100\">1</param>\n"
+ "<param name=\"spotConeAngle\" gui-text=\"" N_("Cone angle") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"100\">50</param>\n"
"</page>\n"
"<page name=\"colortab\" _gui-text=\"Color bump\">\n"
"<param name=\"imageColor\" gui-text=\"" N_("Image color") "\" type=\"color\">-987158017</param>\n"
@@ -167,9 +167,6 @@ Bump::get_filter_text (Inkscape::Extension::Extension * ext)
std::ostringstream lightOptions;
std::ostringstream lightEnd;
- std::ostringstream lightRed;
- std::ostringstream lightGreen;
- std::ostringstream lightBlue;
std::ostringstream floodRed;
std::ostringstream floodGreen;
std::ostringstream floodBlue;
@@ -313,27 +310,27 @@ public:
"<id>org.inkscape.effect.filter.WaxBump</id>\n"
"<param name=\"tab\" type=\"notebook\">\n"
"<page name=\"optionstab\" _gui-text=\"Options\">\n"
- "<param name=\"simplifyImage\" gui-text=\"" N_("Image simplification:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">1.5</param>\n"
- "<param name=\"simplifyBump\" gui-text=\"" N_("Bump simplification:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">1</param>\n"
- "<param name=\"crop\" gui-text=\"" N_("Crop:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">1</param>\n"
+ "<param name=\"simplifyImage\" gui-text=\"" N_("Image simplification") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">1.5</param>\n"
+ "<param name=\"simplifyBump\" gui-text=\"" N_("Bump simplification") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">1</param>\n"
+ "<param name=\"crop\" gui-text=\"" N_("Crop") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">1</param>\n"
"<_param name=\"sourceHeader\" type=\"description\" appearance=\"header\">" N_("Bump source") "</_param>\n"
- "<param name=\"red\" gui-text=\"" N_("Red:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0</param>\n"
- "<param name=\"green\" gui-text=\"" N_("Green:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0</param>\n"
- "<param name=\"blue\" gui-text=\"" N_("Blue:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0</param>\n"
+ "<param name=\"red\" gui-text=\"" N_("Red") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0</param>\n"
+ "<param name=\"green\" gui-text=\"" N_("Green") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0</param>\n"
+ "<param name=\"blue\" gui-text=\"" N_("Blue") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0</param>\n"
"<param name=\"background\" gui-text=\"" N_("Background:") "\" type=\"enum\">\n"
"<_item value=\"flood1\">" N_("Color") "</_item>\n"
"<_item value=\"SourceGraphic\">" N_("Image") "</_item>\n"
"<_item value=\"blur1\">" N_("Blurred image") "</_item>\n"
"</param>\n"
- "<param name=\"bgopacity\" gui-text=\"" N_("Background opacity:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.\">0</param>\n"
+ "<param name=\"bgopacity\" gui-text=\"" N_("Background opacity") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.\">0</param>\n"
"</page>\n"
"<page name=\"lightingtab\" _gui-text=\"" N_("Lighting") "\">\n"
"<param name=\"lightingColor\" gui-text=\"" N_("Color") "\" type=\"color\">-1</param>\n"
- "<param name=\"height\" gui-text=\"" N_("Height:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">5</param>\n"
- "<param name=\"lightness\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"10.\">1.4</param>\n"
- "<param name=\"precision\" gui-text=\"" N_("Precision:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"50\">35</param>\n"
- "<param name=\"distantAzimuth\" gui-text=\"" N_("Azimuth:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"360\">225</param>\n"
- "<param name=\"distantElevation\" gui-text=\"" N_("Elevation:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"180\">60</param>\n"
+ "<param name=\"height\" gui-text=\"" N_("Height") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-50.\" max=\"50.\">5</param>\n"
+ "<param name=\"lightness\" gui-text=\"" N_("Lightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"10.\">1.4</param>\n"
+ "<param name=\"precision\" gui-text=\"" N_("Precision") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"50\">35</param>\n"
+ "<param name=\"distantAzimuth\" gui-text=\"" N_("Azimuth") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"360\">225</param>\n"
+ "<param name=\"distantElevation\" gui-text=\"" N_("Elevation") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"180\">60</param>\n"
"<param name=\"lightingblend\" gui-text=\"" N_("Lighting blend:") "\" type=\"enum\">\n"
"<_item value=\"screen\">" N_("Screen") "</_item>\n"
"<_item value=\"normal\">" N_("Normal") "</_item>\n"
diff --git a/src/extension/internal/filter/color.h b/src/extension/internal/filter/color.h
index b6b194c8b..7059ad29b 100644
--- a/src/extension/internal/filter/color.h
+++ b/src/extension/internal/filter/color.h
@@ -3,7 +3,7 @@
/* Change the 'COLOR' above to be your file name */
/*
- * Copyright (C) 2011 Authors:
+ * Copyright (C) 2013 Authors:
* Ivan Louette (filters)
* Nicolas Dufour (UI) <nicoduf@yahoo.fr>
*
@@ -20,7 +20,8 @@
* Invert
* Lighting
* Lightness-contrast
- * Nudge
+ * Nudge RGB
+ * Nudge CMY
* Quadritone
* Solarize
* Tritone
@@ -70,9 +71,9 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Brilliance") "</name>\n"
"<id>org.inkscape.effect.filter.Brilliance</id>\n"
- "<param name=\"brightness\" gui-text=\"" N_("Brightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"10.00\">2</param>\n"
- "<param name=\"sat\" gui-text=\"" N_("Over-saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.0\" max=\"10.00\">0.5</param>\n"
- "<param name=\"lightness\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0</param>\n"
+ "<param name=\"brightness\" gui-text=\"" N_("Brightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"10.00\">2</param>\n"
+ "<param name=\"sat\" gui-text=\"" N_("Over-saturation") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.0\" max=\"10.00\">0.5</param>\n"
+ "<param name=\"lightness\" gui-text=\"" N_("Lightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0</param>\n"
"<param name=\"invert\" gui-text=\"" N_("Inverted") "\" type=\"boolean\">false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -152,11 +153,11 @@ public:
"<id>org.inkscape.effect.filter.ChannelPaint</id>\n"
"<param name=\"tab\" type=\"notebook\">\n"
"<page name=\"optionstab\" _gui-text=\"Options\">\n"
- "<param name=\"saturation\" gui-text=\"" N_("Saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.\">1</param>\n"
- "<param name=\"red\" gui-text=\"" N_("Red:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">-1</param>\n"
- "<param name=\"green\" gui-text=\"" N_("Green:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0.5</param>\n"
- "<param name=\"blue\" gui-text=\"" N_("Blue:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0.5</param>\n"
- "<param name=\"alpha\" gui-text=\"" N_("Alpha:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">1</param>\n"
+ "<param name=\"saturation\" gui-text=\"" N_("Saturation") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.\">1</param>\n"
+ "<param name=\"red\" gui-text=\"" N_("Red") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">-1</param>\n"
+ "<param name=\"green\" gui-text=\"" N_("Green") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0.5</param>\n"
+ "<param name=\"blue\" gui-text=\"" N_("Blue") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0.5</param>\n"
+ "<param name=\"alpha\" gui-text=\"" N_("Alpha") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">1</param>\n"
"<param name=\"invert\" gui-text=\"" N_("Inverted") "\" type=\"boolean\">false</param>\n"
"</page>\n"
"<page name=\"colortab\" _gui-text=\"Color\">\n"
@@ -211,7 +212,7 @@ ChannelPaint::get_filter_text (Inkscape::Extension::Extension * ext)
}
_filter = g_strdup_printf(
- "<filter inkscape:label=\"Channel Painting\" style=\"color-interpolation-filters:sRGB;\" >\n"
+ "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" style=\"color-interpolation-filters:sRGB;\" inkscape:label=\"Channel Painting\">\n"
"<feColorMatrix values=\"%s\" type=\"saturate\" result=\"colormatrix1\" />\n"
"<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 %s %s %s %s 0 \" in=\"SourceGraphic\" result=\"colormatrix2\" />\n"
"<feFlood flood-color=\"rgb(%s,%s,%s)\" flood-opacity=\"%s\" result=\"flood\" />\n"
@@ -252,8 +253,8 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Color Shift") "</name>\n"
"<id>org.inkscape.effect.filter.ColorShift</id>\n"
- "<param name=\"shift\" gui-text=\"" N_("Shift (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">330</param>\n"
- "<param name=\"sat\" gui-text=\"" N_("Saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1\">0.6</param>\n"
+ "<param name=\"shift\" gui-text=\"" N_("Shift (°)") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">330</param>\n"
+ "<param name=\"sat\" gui-text=\"" N_("Saturation") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1\">0.6</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -317,8 +318,8 @@ public:
"<id>org.inkscape.effect.filter.Colorize</id>\n"
"<param name=\"tab\" type=\"notebook\">\n"
"<page name=\"optionstab\" _gui-text=\"Options\">\n"
- "<param name=\"hlight\" gui-text=\"" N_("Harsh light:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">0</param>\n"
- "<param name=\"nlight\" gui-text=\"" N_("Normal light:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">1</param>\n"
+ "<param name=\"hlight\" gui-text=\"" N_("Harsh light") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">0</param>\n"
+ "<param name=\"nlight\" gui-text=\"" N_("Normal light") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">1</param>\n"
"<param name=\"duotone\" gui-text=\"" N_("Duotone") "\" type=\"boolean\" >false</param>\n"
"<param name=\"blend1\" gui-text=\"" N_("Blend 1:") "\" type=\"enum\">\n"
"<_item value=\"multiply\">" N_("Multiply") "</_item>\n"
@@ -509,7 +510,7 @@ public:
"<id>org.inkscape.effect.filter.Duochrome</id>\n"
"<param name=\"tab\" type=\"notebook\">\n"
"<page name=\"optionstab\" _gui-text=\"Options\">\n"
- "<param name=\"fluo\" gui-text=\"" N_("Fluorescence level:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"2\">0</param>\n"
+ "<param name=\"fluo\" gui-text=\"" N_("Fluorescence level") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"2\">0</param>\n"
"<param name=\"swap\" gui-text=\"" N_("Swap:") "\" type=\"enum\">\n"
"<_item value=\"none\">" N_("No swap") "</_item>\n"
"<_item value=\"full\">" N_("Color and alpha") "</_item>\n"
@@ -615,9 +616,8 @@ Duochrome::get_filter_text (Inkscape::Extension::Extension * ext)
Filter's parameters:
* Channel (enum, all colors, default Red) -> colormatrix (values)
- * Background blend (enum, all blend modes, default Multiply) -> blend (mode)
+ * Background blend (enum, Normal, Multiply, Screen, default Normal) -> blend (mode)
* Channel to alpha (boolean, default false) -> colormatrix (values)
- * Invert (boolean, default false) -> colormatrix (values)
*/
class ExtractChannel : public Inkscape::Extension::Internal::Filter::Filter {
@@ -637,16 +637,16 @@ public:
"<_item value=\"r\">" N_("Red") "</_item>\n"
"<_item value=\"g\">" N_("Green") "</_item>\n"
"<_item value=\"b\">" N_("Blue") "</_item>\n"
+ "<_item value=\"c\">" N_("Cyan") "</_item>\n"
+ "<_item value=\"m\">" N_("Magenta") "</_item>\n"
+ "<_item value=\"y\">" N_("Yellow") "</_item>\n"
"</param>\n"
"<param name=\"blend\" gui-text=\"" N_("Background blend mode:") "\" type=\"enum\">\n"
"<_item value=\"multiply\">" N_("Multiply") "</_item>\n"
"<_item value=\"normal\">" N_("Normal") "</_item>\n"
"<_item value=\"screen\">" N_("Screen") "</_item>\n"
- "<_item value=\"darken\">" N_("Darken") "</_item>\n"
- "<_item value=\"lighten\">" N_("Lighten") "</_item>\n"
"</param>\n"
"<param name=\"alpha\" gui-text=\"" N_("Channel to alpha") "\" type=\"boolean\">false</param>\n"
- "<param name=\"invert\" gui-text=\"" N_("Inverted") "\" type=\"boolean\">false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -667,45 +667,45 @@ ExtractChannel::get_filter_text (Inkscape::Extension::Extension * ext)
std::ostringstream blend;
std::ostringstream colors;
- std::ostringstream alpha;
- std::ostringstream invert;
blend << ext->get_param_enum("blend");
const gchar *channel = ext->get_param_enum("source");
if (ext->get_param_bool("alpha")) {
- colors << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0";
- } else if ((g_ascii_strcasecmp("r", channel) == 0)) {
- colors << "0 0 0 0 1 0 0 0 0 0 0 0 0 0 0";
- } else if ((g_ascii_strcasecmp("g", channel) == 0)) {
- colors << "0 0 0 0 0 0 0 0 0 1 0 0 0 0 0";
- } else {
- colors << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 1";
- }
-
- if (ext->get_param_bool("invert")) {
if ((g_ascii_strcasecmp("r", channel) == 0)) {
- alpha << "-1 0 0 1";
+ colors << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0";
} else if ((g_ascii_strcasecmp("g", channel) == 0)) {
- alpha << "0 -1 0 1";
+ colors << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0";
+ } else if ((g_ascii_strcasecmp("b", channel) == 0)) {
+ colors << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0";
+ } else if ((g_ascii_strcasecmp("c", channel) == 0)) {
+ colors << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0";
+ } else if ((g_ascii_strcasecmp("m", channel) == 0)) {
+ colors << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0";
} else {
- alpha << "0 0 -1 1";
+ colors << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0";
}
} else {
if ((g_ascii_strcasecmp("r", channel) == 0)) {
- alpha << "1 0 0 0";
+ colors << "0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0";
} else if ((g_ascii_strcasecmp("g", channel) == 0)) {
- alpha << "0 1 0 0";
+ colors << "0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0";
+ } else if ((g_ascii_strcasecmp("b", channel) == 0)) {
+ colors << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0";
+ } else if ((g_ascii_strcasecmp("c", channel) == 0)) {
+ colors << "0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 -1 0 0 1 0";
+ } else if ((g_ascii_strcasecmp("m", channel) == 0)) {
+ colors << "0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 -1 0 1 0";
} else {
- alpha << "0 0 1 0";
+ colors << "0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 -1 1 0";
}
}
_filter = g_strdup_printf(
"<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" style=\"color-interpolation-filters:sRGB;\" inkscape:label=\"Extract Channel\">\n"
- "<feColorMatrix in=\"SourceGraphic\" values=\"%s %s %s 0 \" result=\"colormatrix\" />\n"
+ "<feColorMatrix in=\"SourceGraphic\" values=\"%s 0 \" result=\"colormatrix\" />\n"
"<feBlend in2=\"BackgroundImage\" mode=\"%s\" result=\"blend\" />\n"
- "</filter>\n", colors.str().c_str(), alpha.str().c_str(), invert.str().c_str(), blend.str().c_str() );
+ "</filter>\n", colors.str().c_str(), blend.str().c_str() );
return _filter;
}; /* ExtractChannel filter */
@@ -739,7 +739,7 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Fade to Black or White") "</name>\n"
"<id>org.inkscape.effect.filter.FadeToBW</id>\n"
- "<param name=\"level\" gui-text=\"" N_("Level:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1\">1</param>\n"
+ "<param name=\"level\" gui-text=\"" N_("Level") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1\">1</param>\n"
"<param name=\"fadeto\" gui-text=\"" N_("Fade to:") "\" type=\"enum\">\n"
"<_item value=\"black\">" N_("Black") "</_item>\n"
"<_item value=\"white\">" N_("White") "</_item>\n"
@@ -818,10 +818,10 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Greyscale") "</name>\n"
"<id>org.inkscape.effect.filter.Greyscale</id>\n"
- "<param name=\"red\" gui-text=\"" N_("Red:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0.21</param>\n"
- "<param name=\"green\" gui-text=\"" N_("Green:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0.72</param>\n"
- "<param name=\"blue\" gui-text=\"" N_("Blue:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0.072</param>\n"
- "<param name=\"strength\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0</param>\n"
+ "<param name=\"red\" gui-text=\"" N_("Red") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0.21</param>\n"
+ "<param name=\"green\" gui-text=\"" N_("Green") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0.72</param>\n"
+ "<param name=\"blue\" gui-text=\"" N_("Blue") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0.072</param>\n"
+ "<param name=\"strength\" gui-text=\"" N_("Lightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0</param>\n"
"<param name=\"transparent\" gui-text=\"" N_("Transparent") "\" type=\"boolean\" >false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -910,7 +910,7 @@ public:
"<_item value=\"2\">" N_("Red and green") "</_item>\n"
"<_item value=\"3\">" N_("Green and blue") "</_item>\n"
"</param>\n"
- "<param name=\"opacify\" gui-text=\"" N_("Light transparency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1\">0</param>\n"
+ "<param name=\"opacify\" gui-text=\"" N_("Light transparency") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1\">0</param>\n"
"<param name=\"hue\" gui-text=\"" N_("Invert hue") "\" type=\"boolean\" >false</param>\n"
"<param name=\"lightness\" gui-text=\"" N_("Invert lightness") "\" type=\"boolean\" >false</param>\n"
"<param name=\"transparency\" gui-text=\"" N_("Invert transparency") "\" type=\"boolean\" >false</param>\n"
@@ -1039,9 +1039,9 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Lighting") "</name>\n"
"<id>org.inkscape.effect.filter.Lighting</id>\n"
- "<param name=\"amplitude\" gui-text=\"" N_("Lights:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"20.00\">1</param>\n"
- "<param name=\"exponent\" gui-text=\"" N_("Shadows:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"20.00\">1</param>\n"
- "<param name=\"offset\" gui-text=\"" N_("Offset:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-1.00\" max=\"1.00\">0</param>\n"
+ "<param name=\"amplitude\" gui-text=\"" N_("Lights") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"20.00\">1</param>\n"
+ "<param name=\"exponent\" gui-text=\"" N_("Shadows") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"20.00\">1</param>\n"
+ "<param name=\"offset\" gui-text=\"" N_("Offset") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-1.00\" max=\"1.00\">0</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -1110,8 +1110,8 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Lightness-Contrast") "</name>\n"
"<id>org.inkscape.effect.filter.LightnessContrast</id>\n"
- "<param name=\"lightness\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-100\" max=\"100\">0</param>\n"
- "<param name=\"contrast\" gui-text=\"" N_("Contrast:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-100\" max=\"100\">0</param>\n"
+ "<param name=\"lightness\" gui-text=\"" N_("Lightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-100\" max=\"100\">0</param>\n"
+ "<param name=\"contrast\" gui-text=\"" N_("Contrast") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-100\" max=\"100\">0</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -1157,72 +1157,52 @@ LightnessContrast::get_filter_text (Inkscape::Extension::Extension * ext)
}; /* Lightness-Contrast filter */
/**
- \brief Custom predefined Nudge filter.
+ \brief Custom predefined Nudge RGB filter.
- Nudge separately RGB channels and blend them to different types of backgrounds
+ Nudge RGB channels separately and blend them to different types of backgrounds
Filter's parameters:
Offsets
* Red
- * x (-100.->100., default -7) -> offset1 (dx)
- * y (-100.->100., default 5) -> offset1 (dy)
+ * x (-100.->100., default -6) -> offset1 (dx)
+ * y (-100.->100., default -6) -> offset1 (dy)
* Green
- * x (-100.->100., default 0) -> offset2 (dx)
- * y (-100.->100., default 10) -> offset2 (dy)
+ * x (-100.->100., default 6) -> offset2 (dx)
+ * y (-100.->100., default 7) -> offset2 (dy)
* Blue
- * x (-100.->100., default 3) -> offset3 (dx)
- * y (-100.->100., default -9) -> offset3 (dy)
+ * x (-100.->100., default 1) -> offset3 (dx)
+ * y (-100.->100., default -16) -> offset3 (dy)
Color
- * Background color (guint, default -1)-> flood (flood-color, flood-opacity)
- * Blend type (enum [normal,multiply and screen], default screen) -> blend1,2,3 (mode)
- * Blend source (enum, default color) ->
- * color: blend1 (in="flood")
- * image: blend1 (in="SourceGraphic")
- * background: blend1 (in="BackgroundImage")
- * Composite (enum [in,over], default over) -> composite (operator)
+ * Background color (guint, default 255)-> flood (flood-color, flood-opacity)
*/
-class Nudge : public Inkscape::Extension::Internal::Filter::Filter {
+class NudgeRGB : public Inkscape::Extension::Internal::Filter::Filter {
protected:
virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext);
public:
- Nudge ( ) : Filter() { };
- virtual ~Nudge ( ) { if (_filter != NULL) g_free((void *)_filter); return; }
+ NudgeRGB ( ) : Filter() { };
+ virtual ~NudgeRGB ( ) { if (_filter != NULL) g_free((void *)_filter); return; }
static void init (void) {
Inkscape::Extension::build_from_mem(
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
- "<name>" N_("Nudge") "</name>\n"
- "<id>org.inkscape.effect.filter.Nudge</id>\n"
+ "<name>" N_("Nudge RGB") "</name>\n"
+ "<id>org.inkscape.effect.filter.NudgeRGB</id>\n"
"<param name=\"tab\" type=\"notebook\">\n"
"<page name=\"offsettab\" _gui-text=\"Offset\">\n"
"<_param name=\"redOffset\" type=\"description\" appearance=\"header\">" N_("Red offset") "</_param>\n"
- "<param name=\"rx\" gui-text=\"" N_("X:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">-7</param>\n"
- "<param name=\"ry\" gui-text=\"" N_("Y:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">5</param>\n"
+ "<param name=\"rx\" gui-text=\"" N_("X") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">-6</param>\n"
+ "<param name=\"ry\" gui-text=\"" N_("Y") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">-6</param>\n"
"<_param name=\"greenOffset\" type=\"description\" appearance=\"header\">" N_("Green offset") "</_param>\n"
- "<param name=\"gx\" gui-text=\"" N_("X:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">0</param>\n"
- "<param name=\"gy\" gui-text=\"" N_("Y:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">10</param>\n"
+ "<param name=\"gx\" gui-text=\"" N_("X") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">6</param>\n"
+ "<param name=\"gy\" gui-text=\"" N_("Y") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">7</param>\n"
"<_param name=\"redOffset\" type=\"description\" appearance=\"header\">" N_("Blue offset") "</_param>\n"
- "<param name=\"bx\" gui-text=\"" N_("X:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">3</param>\n"
- "<param name=\"by\" gui-text=\"" N_("Y:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">-9</param>\n"
+ "<param name=\"bx\" gui-text=\"" N_("X") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">1</param>\n"
+ "<param name=\"by\" gui-text=\"" N_("Y") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">-16</param>\n"
"</page>\n"
"<page name=\"coltab\" _gui-text=\"Color\">\n"
"<param name=\"color\" gui-text=\"" N_("Background color") "\" type=\"color\">255</param>\n"
- "<param name=\"blend\" gui-text=\"" N_("Blend type:") "\" type=\"enum\">\n"
- "<_item value=\"screen\">" N_("Screen") "</_item>\n"
- "<_item value=\"multiply\">" N_("Multiply") "</_item>\n"
- "<_item value=\"normal\">" N_("Normal") "</_item>\n"
- "</param>\n"
- "<param name=\"source\" gui-text=\"" N_("Blend source:") "\" type=\"enum\">\n"
- "<_item value=\"flood\">" N_("Color") "</_item>\n"
- "<_item value=\"SourceGraphic\">" N_("Image") "</_item>\n"
- "<_item value=\"BackgroundImage\">" N_("Background") "</_item>\n"
- "</param>\n"
- "<param name=\"composite\" gui-text=\"" N_("Composite:") "\" type=\"enum\">\n"
- "<_item value=\"over\">" N_("Over") "</_item>\n"
- "<_item value=\"in\">" N_("In") "</_item>\n"
- "</param>\n"
"</page>\n"
"</param>\n"
"<effect>\n"
@@ -1232,14 +1212,14 @@ public:
"<submenu name=\"" N_("Color") "\"/>\n"
"</submenu>\n"
"</effects-menu>\n"
- "<menu-tip>" N_("Nudge separately RGB channels and blend them to different types of backgrounds") "</menu-tip>\n"
+ "<menu-tip>" N_("Nudge RGB channels separately and blend them to different types of backgrounds") "</menu-tip>\n"
"</effect>\n"
- "</inkscape-extension>\n", new Nudge());
+ "</inkscape-extension>\n", new NudgeRGB());
};
};
gchar const *
-Nudge::get_filter_text (Inkscape::Extension::Extension * ext)
+NudgeRGB::get_filter_text (Inkscape::Extension::Extension * ext)
{
if (_filter != NULL) g_free((void *)_filter);
@@ -1250,10 +1230,6 @@ Nudge::get_filter_text (Inkscape::Extension::Extension * ext)
std::ostringstream bx;
std::ostringstream by;
- std::ostringstream blend;
- std::ostringstream source;
- std::ostringstream composite;
-
std::ostringstream a;
std::ostringstream r;
std::ostringstream g;
@@ -1266,10 +1242,6 @@ Nudge::get_filter_text (Inkscape::Extension::Extension * ext)
bx << ext->get_param_float("bx");
by << ext->get_param_float("by");
- blend << ext->get_param_enum("blend");
- source << ext->get_param_enum("source");
- composite << ext->get_param_enum("composite");
-
guint32 color = ext->get_param_color("color");
r << ((color >> 24) & 0xff);
g << ((color >> 16) & 0xff);
@@ -1277,27 +1249,137 @@ Nudge::get_filter_text (Inkscape::Extension::Extension * ext)
a << (color & 0xff) / 255.0F;
_filter = g_strdup_printf(
- "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" style=\"color-interpolation-filters:sRGB;\" inkscape:label=\"Nudge\">\n"
+ "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" style=\"color-interpolation-filters:sRGB;\" inkscape:label=\"Nudge RGB\">\n"
"<feFlood flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood\" />\n"
"<feColorMatrix in=\"SourceGraphic\" values=\"0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 \" result=\"colormatrix1\" />\n"
"<feOffset dy=\"%s\" dx=\"%s\" result=\"offset1\" />\n"
- "<feBlend in2=\"%s\" mode=\"%s\" result=\"blend1\" />\n"
+ "<feBlend in2=\"flood\" mode=\"screen\" result=\"blend1\" />\n"
"<feColorMatrix in=\"SourceGraphic\" values=\"0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 \" result=\"colormatrix2\" />\n"
"<feOffset dy=\"%s\" dx=\"%s\" result=\"offset2\" />\n"
- "<feBlend in2=\"blend1\" mode=\"%s\" result=\"blend2\" />\n"
+ "<feBlend in2=\"blend1\" mode=\"screen\" result=\"blend2\" />\n"
"<feOffset dy=\"%s\" dx=\"%s\" result=\"offset3\" />\n"
"<feColorMatrix in=\"SourceGraphic\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 \" result=\"colormatrix3\" />\n"
- "<feBlend in2=\"offset3\" mode=\"%s\" result=\"blend3\" />\n"
- "<feComposite in2=\"SourceGraphic\" operator=\"%s\" />\n"
+ "<feBlend in2=\"offset3\" mode=\"screen\" result=\"blend3\" />\n"
+ "</filter>\n", a.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(),
+ rx.str().c_str(), ry.str().c_str(),
+ gx.str().c_str(), gy.str().c_str(),
+ bx.str().c_str(), by.str().c_str() );
+
+ return _filter;
+
+}; /* Nudge RGB filter */
+
+/**
+ \brief Custom predefined Nudge CMY filter.
+
+ Nudge CMY channels separately and blend them to different types of backgrounds
+
+ Filter's parameters:
+ Offsets
+ * Cyan
+ * x (-100.->100., default -6) -> offset1 (dx)
+ * y (-100.->100., default -6) -> offset1 (dy)
+ * Magenta
+ * x (-100.->100., default 6) -> offset2 (dx)
+ * y (-100.->100., default 7) -> offset2 (dy)
+ * Yellow
+ * x (-100.->100., default 1) -> offset3 (dx)
+ * y (-100.->100., default -16) -> offset3 (dy)
+ Color
+ * Background color (guint, default -1)-> flood (flood-color, flood-opacity)
+*/
+class NudgeCMY : public Inkscape::Extension::Internal::Filter::Filter {
+protected:
+ virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext);
+
+public:
+ NudgeCMY ( ) : Filter() { };
+ virtual ~NudgeCMY ( ) { if (_filter != NULL) g_free((void *)_filter); return; }
+
+ static void init (void) {
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("Nudge CMY") "</name>\n"
+ "<id>org.inkscape.effect.filter.NudgeCMY</id>\n"
+ "<param name=\"tab\" type=\"notebook\">\n"
+ "<page name=\"offsettab\" _gui-text=\"Offset\">\n"
+ "<_param name=\"cyanOffset\" type=\"description\" appearance=\"header\">" N_("Cyan offset") "</_param>\n"
+ "<param name=\"cx\" gui-text=\"" N_("X") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">-6</param>\n"
+ "<param name=\"cy\" gui-text=\"" N_("Y") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">-6</param>\n"
+ "<_param name=\"magentaOffset\" type=\"description\" appearance=\"header\">" N_("Magenta offset") "</_param>\n"
+ "<param name=\"mx\" gui-text=\"" N_("X") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">6</param>\n"
+ "<param name=\"my\" gui-text=\"" N_("Y") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">7</param>\n"
+ "<_param name=\"yellowOffset\" type=\"description\" appearance=\"header\">" N_("Yellow offset") "</_param>\n"
+ "<param name=\"yx\" gui-text=\"" N_("X") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">1</param>\n"
+ "<param name=\"yy\" gui-text=\"" N_("Y") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"-100.\" max=\"100.\">-16</param>\n"
+ "</page>\n"
+ "<page name=\"coltab\" _gui-text=\"Color\">\n"
+ "<param name=\"color\" gui-text=\"" N_("Background color") "\" type=\"color\">-1</param>\n"
+ "</page>\n"
+ "</param>\n"
+ "<effect>\n"
+ "<object-type>all</object-type>\n"
+ "<effects-menu>\n"
+ "<submenu name=\"" N_("Filters") "\">\n"
+ "<submenu name=\"" N_("Color") "\"/>\n"
+ "</submenu>\n"
+ "</effects-menu>\n"
+ "<menu-tip>" N_("Nudge CMY channels separately and blend them to different types of backgrounds") "</menu-tip>\n"
+ "</effect>\n"
+ "</inkscape-extension>\n", new NudgeCMY());
+ };
+};
+
+gchar const *
+NudgeCMY::get_filter_text (Inkscape::Extension::Extension * ext)
+{
+ if (_filter != NULL) g_free((void *)_filter);
+
+ std::ostringstream cx;
+ std::ostringstream cy;
+ std::ostringstream mx;
+ std::ostringstream my;
+ std::ostringstream yx;
+ std::ostringstream yy;
+
+ std::ostringstream a;
+ std::ostringstream r;
+ std::ostringstream g;
+ std::ostringstream b;
+
+ cx << ext->get_param_float("cx");
+ cy << ext->get_param_float("cy");
+ mx << ext->get_param_float("mx");
+ my << ext->get_param_float("my");
+ yx << ext->get_param_float("yx");
+ yy << ext->get_param_float("yy");
+
+ guint32 color = ext->get_param_color("color");
+ r << ((color >> 24) & 0xff);
+ g << ((color >> 16) & 0xff);
+ b << ((color >> 8) & 0xff);
+ a << (color & 0xff) / 255.0F;
+
+ _filter = g_strdup_printf(
+ "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" style=\"color-interpolation-filters:sRGB;\" inkscape:label=\"Nudge CMY\">\n"
+ "<feFlood flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood\" />\n"
+ "<feColorMatrix in=\"SourceGraphic\" values=\"0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 -1 0 0 1 0 \" result=\"colormatrix1\" />\n"
+ "<feOffset dy=\"%s\" dx=\"%s\" result=\"offset1\" />\n"
+ "<feBlend in2=\"flood\" mode=\"multiply\" result=\"blend1\" />\n"
+ "<feColorMatrix in=\"SourceGraphic\" values=\"0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 -1 0 1 0 \" result=\"colormatrix2\" />\n"
+ "<feOffset dy=\"%s\" dx=\"%s\" result=\"offset2\" />\n"
+ "<feBlend in2=\"blend1\" mode=\"multiply\" result=\"blend2\" />\n"
+ "<feOffset dy=\"%s\" dx=\"%s\" result=\"offset3\" />\n"
+ "<feColorMatrix in=\"SourceGraphic\" values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 -1 1 0 \" result=\"colormatrix3\" />\n"
+ "<feBlend in2=\"offset3\" mode=\"multiply\" result=\"blend3\" />\n"
"</filter>\n", a.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(),
- rx.str().c_str(), ry.str().c_str(), source.str().c_str(), blend.str().c_str(),
- gx.str().c_str(), gy.str().c_str(), blend.str().c_str(),
- bx.str().c_str(), by.str().c_str(), blend.str().c_str(),
- composite.str().c_str() );
+ cx.str().c_str(), cy.str().c_str(),
+ mx.str().c_str(), my.str().c_str(),
+ yx.str().c_str(), yy.str().c_str() );
return _filter;
-}; /* Nudge filter */
+}; /* Nudge CMY filter */
/**
\brief Custom predefined Quadritone filter.
@@ -1325,14 +1407,14 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Quadritone fantasy") "</name>\n"
"<id>org.inkscape.effect.filter.Quadritone</id>\n"
- "<param name=\"dist\" gui-text=\"" N_("Hue distribution (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">280</param>\n"
- "<param name=\"colors\" gui-text=\"" N_("Colors:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">100</param>\n"
+ "<param name=\"dist\" gui-text=\"" N_("Hue distribution (°)") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">280</param>\n"
+ "<param name=\"colors\" gui-text=\"" N_("Colors") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">100</param>\n"
"<param name=\"blend1\" gui-text=\"" N_("Blend 1:") "\" type=\"enum\">\n"
"<_item value=\"normal\">" N_("Normal") "</_item>\n"
"<_item value=\"multiply\">" N_("Multiply") "</_item>\n"
"<_item value=\"screen\">" N_("Screen") "</_item>\n"
"</param>\n"
- "<param name=\"sat\" gui-text=\"" N_("Over-saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"1.00\">0</param>\n"
+ "<param name=\"sat\" gui-text=\"" N_("Over-saturation") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"1.00\">0</param>\n"
"<param name=\"blend2\" gui-text=\"" N_("Blend 2:") "\" type=\"enum\">\n"
"<_item value=\"normal\">" N_("Normal") "</_item>\n"
"<_item value=\"screen\">" N_("Screen") "</_item>\n"
@@ -1411,7 +1493,7 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Solarize") "</name>\n"
"<id>org.inkscape.effect.filter.Solarize</id>\n"
- "<param name=\"rotate\" gui-text=\"" N_("Hue rotation (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">0</param>\n"
+ "<param name=\"rotate\" gui-text=\"" N_("Hue rotation (°)") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">0</param>\n"
"<param name=\"type\" gui-text=\"" N_("Type:") "\" type=\"enum\">\n"
"<_item value=\"solarize\">" N_("Solarize") "</_item>\n"
"<_item value=\"moonarize\">" N_("Moonarize") "</_item>\n"
@@ -1513,14 +1595,14 @@ public:
"<_item value=\"multiply\">" N_("Multiply") "</_item>\n"
"<_item value=\"darken\">" N_("Darken") "</_item>\n"
"</param>\n"
- "<param name=\"glow\" gui-text=\"" N_("Glow:") "\" type=\"float\" appearance=\"full\" min=\"0.01\" max=\"10\">0.01</param>\n"
+ "<param name=\"glow\" gui-text=\"" N_("Glow") "\" type=\"float\" appearance=\"full\" min=\"0.01\" max=\"10\">0.01</param>\n"
"<param name=\"glowblend\" gui-text=\"" N_("Glow blend:") "\" type=\"enum\">\n"
"<_item value=\"normal\">" N_("Normal") "</_item>\n"
"<_item value=\"multiply\">" N_("Multiply") "</_item>\n"
"<_item value=\"darken\">" N_("Darken") "</_item>\n"
"</param>\n"
- "<param name=\"llight\" gui-text=\"" N_("Local light:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">0</param>\n"
- "<param name=\"glight\" gui-text=\"" N_("Global light:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">1</param>\n"
+ "<param name=\"llight\" gui-text=\"" N_("Local light") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">0</param>\n"
+ "<param name=\"glight\" gui-text=\"" N_("Global light") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">1</param>\n"
"</page>\n"
"<page name=\"co1tab\" _gui-text=\"Color\">\n"
"<param name=\"dist\" gui-text=\"" N_("Hue distribution (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">0</param>\n"
diff --git a/src/extension/internal/filter/distort.h b/src/extension/internal/filter/distort.h
index 415762466..586d34226 100644
--- a/src/extension/internal/filter/distort.h
+++ b/src/extension/internal/filter/distort.h
@@ -70,10 +70,10 @@ public:
"<_item value=\"in\">" N_("In") "</_item>\n"
"<_item value=\"out\">" N_("Out") "</_item>\n"
"</param>\n"
- "<param name=\"hblur\" gui-text=\"" N_("Horizontal blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"30.00\">15</param>\n"
- "<param name=\"vblur\" gui-text=\"" N_("Vertical blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"30.00\">15</param>\n"
- "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">1</param>\n"
- "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">0</param>\n"
+ "<param name=\"hblur\" gui-text=\"" N_("Horizontal blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"30.00\">15</param>\n"
+ "<param name=\"vblur\" gui-text=\"" N_("Vertical blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"30.00\">15</param>\n"
+ "<param name=\"dilat\" gui-text=\"" N_("Dilatation") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">1</param>\n"
+ "<param name=\"erosion\" gui-text=\"" N_("Erosion") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">0</param>\n"
"<param name=\"stroke\" gui-text=\"" N_("Stroke:") "\" type=\"enum\">\n"
"<_item value=\"atop\">" N_("Normal") "</_item>\n"
"<_item value=\"over\">" N_("Wide") "</_item>\n"
@@ -84,11 +84,11 @@ public:
"<_item value=\"fractalNoise\">" N_("Fractal noise") "</_item>\n"
"<_item value=\"turbulence\">" N_("Turbulence") "</_item>\n"
"</param>\n"
- "<param name=\"hfreq\" gui-text=\"" N_("Horizontal frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.\">5</param>\n"
- "<param name=\"vfreq\" gui-text=\"" N_("Vertical frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.\">5</param>\n"
- "<param name=\"complexity\" gui-text=\"" N_("Complexity:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">3</param>\n"
- "<param name=\"variation\" gui-text=\"" N_("Variation:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"100\">0</param>\n"
- "<param name=\"intensity\" gui-text=\"" N_("Intensity:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"100\">30</param>\n"
+ "<param name=\"hfreq\" gui-text=\"" N_("Horizontal frequency") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.\">5</param>\n"
+ "<param name=\"vfreq\" gui-text=\"" N_("Vertical frequency") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.\">5</param>\n"
+ "<param name=\"complexity\" gui-text=\"" N_("Complexity") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">3</param>\n"
+ "<param name=\"variation\" gui-text=\"" N_("Variation") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"100\">0</param>\n"
+ "<param name=\"intensity\" gui-text=\"" N_("Intensity") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"100\">30</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -193,11 +193,11 @@ public:
"<_item value=\"fractalNoise\">" N_("Fractal noise") "</_item>\n"
"<_item value=\"turbulence\">" N_("Turbulence") "</_item>\n"
"</param>\n"
- "<param name=\"hfreq\" gui-text=\"" N_("Horizontal frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.1\" max=\"1000.00\">1.3</param>\n"
- "<param name=\"vfreq\" gui-text=\"" N_("Vertical frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.1\" max=\"1000.00\">1.3</param>\n"
- "<param name=\"complexity\" gui-text=\"" N_("Complexity:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">5</param>\n"
- "<param name=\"variation\" gui-text=\"" N_("Variation:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"360\">0</param>\n"
- "<param name=\"intensity\" gui-text=\"" N_("Intensity:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"50\">6.6</param>\n"
+ "<param name=\"hfreq\" gui-text=\"" N_("Horizontal frequency") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.1\" max=\"1000.00\">1.3</param>\n"
+ "<param name=\"vfreq\" gui-text=\"" N_("Vertical frequency") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.1\" max=\"1000.00\">1.3</param>\n"
+ "<param name=\"complexity\" gui-text=\"" N_("Complexity") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">5</param>\n"
+ "<param name=\"variation\" gui-text=\"" N_("Variation") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"360\">0</param>\n"
+ "<param name=\"intensity\" gui-text=\"" N_("Intensity") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"50\">6.6</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
diff --git a/src/extension/internal/filter/filter-all.cpp b/src/extension/internal/filter/filter-all.cpp
index b5d47ae45..0273d1669 100755..100644
--- a/src/extension/internal/filter/filter-all.cpp
+++ b/src/extension/internal/filter/filter-all.cpp
@@ -64,7 +64,8 @@ Filter::filters_all (void )
Invert::init();
Lighting::init();
LightnessContrast::init();
- Nudge::init();
+ NudgeRGB::init();
+ NudgeCMY::init();
Quadritone::init();
Solarize::init();
Tritone::init();
diff --git a/src/extension/internal/filter/filter-file.cpp b/src/extension/internal/filter/filter-file.cpp
index d129f590c..48e64f089 100644
--- a/src/extension/internal/filter/filter-file.cpp
+++ b/src/extension/internal/filter/filter-file.cpp
@@ -20,6 +20,7 @@
/* System includes */
#include <glibmm/i18n.h>
+#include <glibmm/fileutils.h>
namespace Inkscape {
namespace Extension {
@@ -43,7 +44,7 @@ void
Filter::filters_load_dir (gchar const * dirname, gchar * menuname)
{
if (!dirname) {
- g_warning(_("Null external module directory name. Filters will not be loaded."));
+ g_warning("%s", _("Null external module directory name. Filters will not be loaded."));
return;
}
diff --git a/src/extension/internal/filter/filter.cpp b/src/extension/internal/filter/filter.cpp
index af597685b..a2c565699 100644
--- a/src/extension/internal/filter/filter.cpp
+++ b/src/extension/internal/filter/filter.cpp
@@ -144,11 +144,11 @@ void Filter::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::Vie
if (filter == NULL) {
Inkscape::XML::Node * newfilterroot = xmldoc->createElement("svg:filter");
+ merge_filters(newfilterroot, filterdoc->root(), xmldoc);
defsrepr->appendChild(newfilterroot);
Glib::ustring url = "url(#"; url += newfilterroot->attribute("id"); url += ")";
- merge_filters(newfilterroot, filterdoc->root(), xmldoc);
Inkscape::GC::release(newfilterroot);
@@ -172,7 +172,7 @@ void Filter::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::Vie
// no filter
if (filternode == NULL) {
- g_warning("no assoziating filter found!");
+ g_warning("no assigned filter found!");
continue;
}
diff --git a/src/extension/internal/filter/filter.h b/src/extension/internal/filter/filter.h
index 1e8a3be0f..9aaa84aec 100644
--- a/src/extension/internal/filter/filter.h
+++ b/src/extension/internal/filter/filter.h
@@ -19,7 +19,7 @@
namespace Inkscape {
namespace XML {
- class Document;
+ struct Document;
}
namespace Extension {
diff --git a/src/extension/internal/filter/image.h b/src/extension/internal/filter/image.h
index 60e1a1665..00cd2cf21 100644
--- a/src/extension/internal/filter/image.h
+++ b/src/extension/internal/filter/image.h
@@ -53,7 +53,7 @@ public:
"<_item value=\"vertical\">" N_("Vertical lines") "</_item>\n"
"<_item value=\"horizontal\">" N_("Horizontal lines") "</_item>\n"
"</param>\n"
- "<param name=\"level\" gui-text=\"" N_("Level:") "\" type=\"float\" appearance=\"full\" min=\"0.1\" max=\"100.0\">1.0</param>\n"
+ "<param name=\"level\" gui-text=\"" N_("Level") "\" type=\"float\" appearance=\"full\" min=\"0.1\" max=\"100.0\">1.0</param>\n"
"<param name=\"inverted\" gui-text=\"" N_("Invert colors") "\" type=\"boolean\" >false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
diff --git a/src/extension/internal/filter/morphology.h b/src/extension/internal/filter/morphology.h
index 123d912b0..7e10884a1 100644
--- a/src/extension/internal/filter/morphology.h
+++ b/src/extension/internal/filter/morphology.h
@@ -62,11 +62,11 @@ public:
"<_item value=\"over\">" N_("Outer") "</_item>\n"
"<_item value=\"xor\">" N_("Open") "</_item>\n"
"</param>\n"
- "<param name=\"width\" gui-text=\"" N_("Width:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"30.\">10</param>\n"
- "<param name=\"level\" gui-text=\"" N_("Level:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.2\" max=\"2\">1</param>\n"
- "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"100\">10</param>\n"
- "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"100\">1</param>\n"
- "<param name=\"antialias\" gui-text=\"" N_("Antialiasing:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"1\">1</param>\n"
+ "<param name=\"width\" gui-text=\"" N_("Width") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"30.\">10</param>\n"
+ "<param name=\"level\" gui-text=\"" N_("Level") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.2\" max=\"2\">1</param>\n"
+ "<param name=\"dilat\" gui-text=\"" N_("Dilatation") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"100\">10</param>\n"
+ "<param name=\"erosion\" gui-text=\"" N_("Erosion") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"100\">1</param>\n"
+ "<param name=\"antialias\" gui-text=\"" N_("Antialiasing") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"1\">1</param>\n"
"<param name=\"content\" gui-text=\"" N_("Blur content") "\" type=\"boolean\" >false</param>\n"
"<effect>\n"
@@ -181,13 +181,13 @@ public:
"<_item value=\"outside\">" N_("Outside") "</_item>\n"
"<_item value=\"overlayed\">" N_("Overlayed") "</_item>\n"
"</param>\n"
- "<param name=\"width1\" gui-text=\"" N_("Width 1:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">4</param>\n"
- "<param name=\"dilat1\" gui-text=\"" N_("Dilatation 1:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"100\">100</param>\n"
- "<param name=\"erosion1\" gui-text=\"" N_("Erosion 1:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">1</param>\n"
- "<param name=\"width2\" gui-text=\"" N_("Width 2:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">0.5</param>\n"
- "<param name=\"dilat2\" gui-text=\"" N_("Dilatation 2:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"100\">50</param>\n"
- "<param name=\"erosion2\" gui-text=\"" N_("Erosion 2:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">5</param>\n"
- "<param name=\"antialias\" gui-text=\"" N_("Antialiasing:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"1\">1</param>\n"
+ "<param name=\"width1\" gui-text=\"" N_("Width 1") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">4</param>\n"
+ "<param name=\"dilat1\" gui-text=\"" N_("Dilatation 1") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"100\">100</param>\n"
+ "<param name=\"erosion1\" gui-text=\"" N_("Erosion 1") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">1</param>\n"
+ "<param name=\"width2\" gui-text=\"" N_("Width 2") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">0.5</param>\n"
+ "<param name=\"dilat2\" gui-text=\"" N_("Dilatation 2") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"100\">50</param>\n"
+ "<param name=\"erosion2\" gui-text=\"" N_("Erosion 2") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"100\">5</param>\n"
+ "<param name=\"antialias\" gui-text=\"" N_("Antialiasing") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"1\">1</param>\n"
"<param name=\"smooth\" gui-text=\"" N_("Smooth") "\" type=\"boolean\" >false</param>\n"
"</page>\n"
"<page name=\"co11tab\" _gui-text=\"Color\">\n"
diff --git a/src/extension/internal/filter/paint.h b/src/extension/internal/filter/paint.h
index debdd7d79..941177f39 100644
--- a/src/extension/internal/filter/paint.h
+++ b/src/extension/internal/filter/paint.h
@@ -3,7 +3,7 @@
/* Change the 'PAINT' above to be your file name */
/*
- * Copyright (C) 2011 Authors:
+ * Copyright (C) 2012 Authors:
* Ivan Louette (filters)
* Nicolas Dufour (UI) <nicoduf@yahoo.fr>
*
@@ -83,19 +83,19 @@ public:
"<param name=\"transparent\" gui-text=\"" N_("Transparent") "\" type=\"boolean\" >false</param>\n"
"<param name=\"dented\" gui-text=\"" N_("Dented") "\" type=\"boolean\" >false</param>\n"
"<param name=\"inverted\" gui-text=\"" N_("Inverted") "\" type=\"boolean\" >false</param>\n"
- "<param name=\"light\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"10\">0</param>\n"
- "<param name=\"saturation\" gui-text=\"" N_("Saturation:") "\" type=\"float\" precision=\"2\" appearance=\"full\" min=\"0\" max=\"1\">1</param>\n"
- "<param name=\"noise\" gui-text=\"" N_("Noise reduction:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"1000\">10</param>\n"
- "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">1</param>\n"
+ "<param name=\"light\" gui-text=\"" N_("Lightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"10\">0</param>\n"
+ "<param name=\"saturation\" gui-text=\"" N_("Saturation") "\" type=\"float\" precision=\"2\" appearance=\"full\" min=\"0\" max=\"1\">1</param>\n"
+ "<param name=\"noise\" gui-text=\"" N_("Noise reduction") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"1000\">10</param>\n"
+ "<param name=\"smooth\" gui-text=\"" N_("Smoothness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">1</param>\n"
"</page>\n"
- "<page name=\"graintab\" _gui-text=\""N_("Grain") "\">\n"
+ "<page name=\"graintab\" _gui-text=\"" N_("Grain") "\">\n"
"<param name=\"grain\" gui-text=\"" N_("Grain mode") "\" type=\"boolean\" >true</param>\n"
- "<param name=\"grainxf\" gui-text=\"" N_("Horizontal frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1000\">1000</param>\n"
- "<param name=\"grainyf\" gui-text=\"" N_("Vertical frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1000\">1000</param>\n"
- "<param name=\"grainc\" gui-text=\"" N_("Complexity:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">1</param>\n"
- "<param name=\"grainv\" gui-text=\"" N_("Variation:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"1000\">0</param>\n"
- "<param name=\"grainexp\" gui-text=\"" N_("Expansion:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"50\">1</param>\n"
- "<param name=\"grainero\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"40\">0</param>\n"
+ "<param name=\"grainxf\" gui-text=\"" N_("Horizontal frequency") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1000\">1000</param>\n"
+ "<param name=\"grainyf\" gui-text=\"" N_("Vertical frequency") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1000\">1000</param>\n"
+ "<param name=\"grainc\" gui-text=\"" N_("Complexity") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">1</param>\n"
+ "<param name=\"grainv\" gui-text=\"" N_("Variation") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"1000\">0</param>\n"
+ "<param name=\"grainexp\" gui-text=\"" N_("Expansion") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"50\">1</param>\n"
+ "<param name=\"grainero\" gui-text=\"" N_("Erosion") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"40\">0</param>\n"
"<param name=\"graincol\" gui-text=\"" N_("Color") "\" type=\"boolean\" >true</param>\n"
"<param name=\"gblend\" gui-text=\"" N_("Grain blend:") "\" type=\"enum\">\n"
"<_item value=\"normal\">Normal</_item>\n"
@@ -133,7 +133,6 @@ Chromolitho::get_filter_text (Inkscape::Extension::Extension * ext)
std::ostringstream noise;
std::ostringstream dblend;
std::ostringstream smooth;
- std::ostringstream grain;
std::ostringstream grainxf;
std::ostringstream grainyf;
std::ostringstream grainc;
@@ -232,11 +231,11 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Cross Engraving") "</name>\n"
"<id>org.inkscape.effect.filter.CrossEngraving</id>\n"
- "<param name=\"clean\" gui-text=\"" N_("Clean-up:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"500\">30</param>\n"
- "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" appearance=\"full\" min=\"1\" max=\"50\">1</param>\n"
- "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"50\">0</param>\n"
- "<param name=\"strength\" gui-text=\"" N_("Strength:") "\" type=\"float\" appearance=\"full\" min=\"0.1\" max=\"10\">0.5</param>\n"
- "<param name=\"length\" gui-text=\"" N_("Length:") "\" type=\"float\" appearance=\"full\" min=\"0.5\" max=\"20\">4</param>\n"
+ "<param name=\"clean\" gui-text=\"" N_("Clean-up") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"500\">30</param>\n"
+ "<param name=\"dilat\" gui-text=\"" N_("Dilatation") "\" type=\"float\" appearance=\"full\" min=\"1\" max=\"50\">1</param>\n"
+ "<param name=\"erosion\" gui-text=\"" N_("Erosion") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"50\">0</param>\n"
+ "<param name=\"strength\" gui-text=\"" N_("Strength") "\" type=\"float\" appearance=\"full\" min=\"0.1\" max=\"10\">0.5</param>\n"
+ "<param name=\"length\" gui-text=\"" N_("Length") "\" type=\"float\" appearance=\"full\" min=\"0.5\" max=\"20\">4</param>\n"
"<param name=\"trans\" gui-text=\"" N_("Transparent") "\" type=\"boolean\" >false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -334,18 +333,18 @@ public:
"<param name=\"tab\" type=\"notebook\">\n"
"<page name=\"optionstab\" _gui-text=\"Options\">\n"
"<_param name=\"simplifyheader\" type=\"description\" appearance=\"header\">" N_("Simplify") "</_param>\n"
- "<param name=\"simply\" gui-text=\"" N_("Strength:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">0.6</param>\n"
- "<param name=\"clean\" gui-text=\"" N_("Clean-up:") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"1\" max=\"500\">10</param>\n"
- "<param name=\"erase\" gui-text=\"" N_("Erase:") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"60\">0</param>\n"
+ "<param name=\"simply\" gui-text=\"" N_("Strength") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">0.6</param>\n"
+ "<param name=\"clean\" gui-text=\"" N_("Clean-up") "\" type=\"int\" indent=\"1\" appearance=\"full\" min=\"1\" max=\"500\">10</param>\n"
+ "<param name=\"erase\" gui-text=\"" N_("Erase") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"60\">0</param>\n"
"<param name=\"translucent\" gui-text=\"" N_("Translucent") "\" indent=\"1\" type=\"boolean\" >false</param>\n"
"<_param name=\"smoothheader\" type=\"description\" appearance=\"header\">" N_("Smoothness") "</_param>\n"
- "<param name=\"smooth\" gui-text=\"" N_("Strength:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">0.6</param>\n"
- "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"1\" max=\"50\">6</param>\n"
- "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"50\">2</param>\n"
+ "<param name=\"smooth\" gui-text=\"" N_("Strength") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">0.6</param>\n"
+ "<param name=\"dilat\" gui-text=\"" N_("Dilatation") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"1\" max=\"50\">6</param>\n"
+ "<param name=\"erosion\" gui-text=\"" N_("Erosion") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"50\">2</param>\n"
"<_param name=\"meltheader\" type=\"description\" appearance=\"header\">" N_("Melt") "</_param>\n"
- "<param name=\"blur\" gui-text=\"" N_("Level:") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">1</param>\n"
- "<param name=\"bdilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"1\" max=\"50\">6</param>\n"
- "<param name=\"berosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"50\">2</param>\n"
+ "<param name=\"blur\" gui-text=\"" N_("Level") "\" type=\"float\" indent=\"1\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">1</param>\n"
+ "<param name=\"bdilat\" gui-text=\"" N_("Dilatation") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"1\" max=\"50\">6</param>\n"
+ "<param name=\"berosion\" gui-text=\"" N_("Erosion") "\" type=\"float\" indent=\"1\" appearance=\"full\" min=\"0\" max=\"50\">2</param>\n"
"</page>\n"
"<page name=\"co11tab\" _gui-text=\"Fill color\">\n"
"<param name=\"fcolor\" gui-text=\"" N_("Fill color") "\" type=\"color\">-1515870721</param>\n"
@@ -354,7 +353,7 @@ public:
"<page name=\"co12tab\" _gui-text=\"Stroke color\">\n"
"<param name=\"scolor\" gui-text=\"" N_("Stroke color") "\" type=\"color\">589505535</param>\n"
"<param name=\"ios\" gui-text=\"" N_("Image on stroke") "\" type=\"boolean\" >false</param>\n"
- "<param name=\"offset\" gui-text=\"" N_("Offset:") "\" type=\"int\" appearance=\"full\" min=\"-100\" max=\"100\">0</param>\n"
+ "<param name=\"offset\" gui-text=\"" N_("Offset") "\" type=\"int\" appearance=\"full\" min=\"-100\" max=\"100\">0</param>\n"
"</page>\n"
"</param>\n"
"<effect>\n"
@@ -494,12 +493,12 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Electrize") "</name>\n"
"<id>org.inkscape.effect.filter.Electrize</id>\n"
- "<param name=\"blur\" gui-text=\"" N_("Simplify:") "\" type=\"float\" appearance=\"full\" min=\"0.01\" max=\"10.0\">2.0</param>\n"
+ "<param name=\"blur\" gui-text=\"" N_("Simplify") "\" type=\"float\" appearance=\"full\" min=\"0.01\" max=\"10.0\">2.0</param>\n"
"<param name=\"type\" gui-text=\"" N_("Effect type:") "\" type=\"enum\">\n"
"<_item value=\"table\">" N_("Table") "</_item>\n"
"<_item value=\"discrete\">" N_("Discrete") "</_item>\n"
"</param>\n"
- "<param name=\"levels\" gui-text=\"" N_("Levels:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"10\">3</param>\n"
+ "<param name=\"levels\" gui-text=\"" N_("Levels") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"10\">3</param>\n"
"<param name=\"invert\" gui-text=\"" N_("Inverted") "\" type=\"boolean\">false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -563,13 +562,13 @@ Electrize::get_filter_text (Inkscape::Extension::Extension * ext)
Filter's parameters:
* Lines type (enum, default smooth) ->
- smooth = component1 (type="table"), component2 (type="table"), composite1 (in2="blur2")
- hard = component1 (type="discrete"), component2 (type="discrete"), composite1 (in2="component1")
- * Simplify (0.01->20., default 1.5) -> blur1 (stdDeviation)
- * Line width (0.01->20., default 1.5) -> blur2 (stdDeviation)
- * Lightness (0.->10., default 0.5) -> composite1 (k3)
+ smooth = component2 (type="table"), composite1 (in2="blur2")
+ hard = component2 (type="discrete"), composite1 (in2="component1")
+ * Simplify (0.01->20., default 3) -> blur1 (stdDeviation)
+ * Line width (0.01->20., default 3) -> blur2 (stdDeviation)
+ * Lightness (0.->10., default 1) -> composite1 (k2)
* Blend (enum [normal, multiply, screen], default normal) -> blend (mode)
- * Dark mode (boolean, default false) -> composite1 (true: in2="component2")
+ * Dark mode (boolean, default false) -> composite2 (true: in2="component2")
*/
class NeonDraw : public Inkscape::Extension::Internal::Filter::Filter {
protected:
@@ -588,15 +587,14 @@ public:
"<_item value=\"table\">" N_("Smoothed") "</_item>\n"
"<_item value=\"discrete\">" N_("Contrasted") "</_item>\n"
"</param>\n"
- "<param name=\"simply\" gui-text=\"" N_("Simplify:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">1.5</param>\n"
- "<param name=\"width\" gui-text=\"" N_("Line width:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">1.5</param>\n"
- "<param name=\"lightness\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"10.00\">0.5</param>\n"
+ "<param name=\"simply\" gui-text=\"" N_("Simplify") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">3</param>\n"
+ "<param name=\"width\" gui-text=\"" N_("Line width") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">3</param>\n"
+ "<param name=\"lightness\" gui-text=\"" N_("Lightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"10.00\">1</param>\n"
"<param name=\"blend\" gui-text=\"" N_("Blend mode:") "\" type=\"enum\">\n"
"<_item value=\"normal\">Normal</_item>\n"
"<_item value=\"multiply\">Multiply</_item>\n"
"<_item value=\"screen\">Screen</_item>\n"
"</param>\n"
- "<param name=\"dark\" gui-text=\"" N_("Dark mode") "\" type=\"boolean\" >false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -620,7 +618,6 @@ NeonDraw::get_filter_text (Inkscape::Extension::Extension * ext)
std::ostringstream width;
std::ostringstream lightness;
std::ostringstream type;
- std::ostringstream dark;
type << ext->get_param_enum("type");
blend << ext->get_param_enum("blend");
@@ -628,33 +625,26 @@ NeonDraw::get_filter_text (Inkscape::Extension::Extension * ext)
width << ext->get_param_float("width");
lightness << ext->get_param_float("lightness");
- const gchar *typestr = ext->get_param_enum("type");
- if (ext->get_param_bool("dark")) {
- dark << "component2";
- } else if ((g_ascii_strcasecmp("table", typestr) == 0)) {
- dark << "blur2";
- } else {
- dark << "component1";
- }
-
_filter = g_strdup_printf(
"<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" style=\"color-interpolation-filters:sRGB;\" inkscape:label=\"Neon Draw\">\n"
"<feBlend mode=\"%s\" result=\"blend\" />\n"
"<feGaussianBlur in=\"blend\" stdDeviation=\"%s\" result=\"blur1\" />\n"
+ "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 50 0\" result=\"color1\" />\n"
"<feComponentTransfer result=\"component1\">\n"
- "<feFuncR type=\"discrete\" tableValues=\"0 0.3 0.6 1 1\" />\n"
- "<feFuncG type=\"discrete\" tableValues=\"0 0.3 0.6 1 1\" />\n"
- "<feFuncB type=\"discrete\" tableValues=\"0 0.3 0.6 1 1\" />\n"
+ "<feFuncR type=\"discrete\" tableValues=\"0 0.3 0.3 0.3 0.3 0.6 0.6 0.6 0.6 1 1\" />\n"
+ "<feFuncG type=\"discrete\" tableValues=\"0 0.3 0.3 0.3 0.3 0.6 0.6 0.6 0.6 1 1\" />\n"
+ "<feFuncB type=\"discrete\" tableValues=\"0 0.3 0.3 0.3 0.3 0.6 0.6 0.6 0.6 1 1\" />\n"
"</feComponentTransfer>\n"
"<feGaussianBlur in=\"component1\" stdDeviation=\"%s\" result=\"blur2\" />\n"
- "<feComponentTransfer in=\"blur2\" result=\"component2\">\n"
- "<feFuncR type=\"%s\" tableValues=\"0 1 0 1 0 1 0 1\" />\n"
- "<feFuncG type=\"%s\" tableValues=\"0 1 0 1 0 1 0 1\" />\n"
- "<feFuncB type=\"%s\" tableValues=\"0 1 0 1 0 1 0 1\" />\n"
+ "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 50 0\" result=\"color2\" />\n"
+ "<feComponentTransfer in=\"color2\" result=\"component2\">\n"
+ "<feFuncR type=\"%s\" tableValues=\"0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1\" />\n"
+ "<feFuncG type=\"%s\" tableValues=\"0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1\" />\n"
+ "<feFuncB type=\"%s\" tableValues=\"0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1\" />\n"
"</feComponentTransfer>\n"
- "<feComposite in=\"component2\" in2=\"%s\" k3=\"%s\" operator=\"arithmetic\" k2=\"1\" result=\"composite1\" />\n"
+ "<feComposite in=\"component2\" in2=\"blur2\" k3=\"%s\" operator=\"arithmetic\" k2=\"1\" result=\"composite1\" />\n"
"<feComposite in=\"composite1\" in2=\"SourceGraphic\" operator=\"in\" result=\"composite2\" />\n"
- "</filter>\n", blend.str().c_str(), simply.str().c_str(), width.str().c_str(), type.str().c_str(), type.str().c_str(), type.str().c_str(), dark.str().c_str(), lightness.str().c_str());
+ "</filter>\n", blend.str().c_str(), simply.str().c_str(), width.str().c_str(), type.str().c_str(), type.str().c_str(), type.str().c_str(), lightness.str().c_str());
return _filter;
}; /* NeonDraw filter */
@@ -702,11 +692,11 @@ public:
"<_item value=\"fractalNoise\">" N_("Fractal noise") "</_item>\n"
"<_item value=\"turbulence\">" N_("Turbulence") "</_item>\n"
"</param>\n"
- "<param name=\"hfreq\" gui-text=\"" N_("Horizontal frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.1\" max=\"100.00\">100</param>\n"
- "<param name=\"vfreq\" gui-text=\"" N_("Vertical frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.1\" max=\"100.00\">100</param>\n"
- "<param name=\"complexity\" gui-text=\"" N_("Complexity:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">1</param>\n"
- "<param name=\"variation\" gui-text=\"" N_("Variation:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"100\">0</param>\n"
- "<param name=\"reduction\" gui-text=\"" N_("Noise reduction:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"500\">45</param>\n"
+ "<param name=\"hfreq\" gui-text=\"" N_("Horizontal frequency") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.1\" max=\"100.00\">100</param>\n"
+ "<param name=\"vfreq\" gui-text=\"" N_("Vertical frequency") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.1\" max=\"100.00\">100</param>\n"
+ "<param name=\"complexity\" gui-text=\"" N_("Complexity") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">1</param>\n"
+ "<param name=\"variation\" gui-text=\"" N_("Variation") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"100\">0</param>\n"
+ "<param name=\"reduction\" gui-text=\"" N_("Noise reduction") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"500\">45</param>\n"
"<param name=\"blend\" gui-text=\"" N_("Noise blend:") "\" type=\"enum\">\n"
"<_item value=\"multiply\">" N_("Multiply") "</_item>\n"
"<_item value=\"normal\">" N_("Normal") "</_item>\n"
@@ -714,10 +704,10 @@ public:
"<_item value=\"lighten\">" N_("Lighten") "</_item>\n"
"<_item value=\"darken\">" N_("Darken") "</_item>\n"
"</param>\n"
- "<param name=\"lightness\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"10\">2.5</param>\n"
- "<param name=\"grain\" gui-text=\"" N_("Grain lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"10\">1.3</param>\n"
- "<param name=\"erase\" gui-text=\"" N_("Erase:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1\">0</param>\n"
- "<param name=\"blur\" gui-text=\"" N_("Blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"2\">0.5</param>\n"
+ "<param name=\"lightness\" gui-text=\"" N_("Lightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"10\">2.5</param>\n"
+ "<param name=\"grain\" gui-text=\"" N_("Grain lightness") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"10\">1.3</param>\n"
+ "<param name=\"erase\" gui-text=\"" N_("Erase") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1\">0</param>\n"
+ "<param name=\"blur\" gui-text=\"" N_("Blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"2\">0.5</param>\n"
"</page>\n"
"<page name=\"fcolortab\" _gui-text=\"" N_("Fill color") "\">\n"
"<param name=\"fcolor\" gui-text=\"" N_("Color") "\" type=\"color\">-1</param>\n"
@@ -867,7 +857,7 @@ public:
"<_item value=\"discrete\">" N_("Poster") "</_item>\n"
"<_item value=\"table\">" N_("Painting") "</_item>\n"
"</param>\n"
- "<param name=\"levels\" gui-text=\"" N_("Levels:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"15\">5</param>\n"
+ "<param name=\"levels\" gui-text=\"" N_("Levels") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"15\">5</param>\n"
"<param name=\"blend\" gui-text=\"" N_("Blend mode:") "\" type=\"enum\">\n"
"<_item value=\"lighten\">Lighten</_item>\n"
"<_item value=\"normal\">Normal</_item>\n"
@@ -875,10 +865,10 @@ public:
"<_item value=\"multiply\">Multiply</_item>\n"
"<_item value=\"screen\">Screen</_item>\n"
"</param>\n"
- "<param name=\"blur1\" gui-text=\"" N_("Simplify (primary):") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">4.0</param>\n"
- "<param name=\"blur2\" gui-text=\"" N_("Simplify (secondary):") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">0.5</param>\n"
- "<param name=\"presaturation\" gui-text=\"" N_("Pre-saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"1.00\">1.00</param>\n"
- "<param name=\"postsaturation\" gui-text=\"" N_("Post-saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"1.00\">1.00</param>\n"
+ "<param name=\"blur1\" gui-text=\"" N_("Simplify (primary)") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">4.0</param>\n"
+ "<param name=\"blur2\" gui-text=\"" N_("Simplify (secondary)") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">0.5</param>\n"
+ "<param name=\"presaturation\" gui-text=\"" N_("Pre-saturation") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"1.00\">1.00</param>\n"
+ "<param name=\"postsaturation\" gui-text=\"" N_("Post-saturation") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"1.00\">1.00</param>\n"
"<param name=\"antialiasing\" gui-text=\"" N_("Simulate antialiasing") "\" type=\"boolean\">false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -982,8 +972,8 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Posterize Basic") "</name>\n"
"<id>org.inkscape.effect.filter.PosterizeBasic</id>\n"
- "<param name=\"levels\" gui-text=\"" N_("Levels:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"20\">5</param>\n"
- "<param name=\"blur\" gui-text=\"" N_("Simplify:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">4.0</param>\n"
+ "<param name=\"levels\" gui-text=\"" N_("Levels") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"20\">5</param>\n"
+ "<param name=\"blur\" gui-text=\"" N_("Simplify") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">4.0</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -1009,9 +999,8 @@ PosterizeBasic::get_filter_text (Inkscape::Extension::Extension * ext)
transf << "0";
int levels = ext->get_param_int("levels") + 1;
- float val = 0.0;
for ( int step = 1 ; step <= levels ; step++ ) {
- val = (float) step / levels;
+ const float val = (float) step / levels;
transf << " " << val;
}
transf << " 1";
diff --git a/src/extension/internal/filter/protrusions.h b/src/extension/internal/filter/protrusions.h
index 8ba35db62..965a1bdc5 100644
--- a/src/extension/internal/filter/protrusions.h
+++ b/src/extension/internal/filter/protrusions.h
@@ -47,7 +47,7 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Snow crest") "</name>\n"
"<id>org.inkscape.effect.filter.snow</id>\n"
- "<param name=\"drift\" gui-text=\"" N_("Drift Size:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"20.0\">3.5</param>\n"
+ "<param name=\"drift\" gui-text=\"" N_("Drift Size") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"20.0\">3.5</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
diff --git a/src/extension/internal/filter/shadows.h b/src/extension/internal/filter/shadows.h
index d76358a96..0d54950bf 100644
--- a/src/extension/internal/filter/shadows.h
+++ b/src/extension/internal/filter/shadows.h
@@ -3,7 +3,7 @@
/* Change the 'SHADOWS' above to be your file name */
/*
- * Copyright (C) 2011 Authors:
+ * Copyright (C) 2013 Authors:
* Ivan Louette (filters)
* Nicolas Dufour (UI) <nicoduf@yahoo.fr>
*
@@ -39,6 +39,7 @@ namespace Filter {
inner = composite1 (operator="out"), composite2 (operator="atop", in1="offset", in2="SourceGraphic")
innercut = composite1 (operator="in"), composite2 (operator="out", in1="offset", in2="SourceGraphic")
outercut = composite1 (operator="out"), composite2 (operator="in", in1="SourceGraphic", in2="offset")
+ shadow = composite1 (operator="out"), composite2 (operator="atop", in1="offset", in2="offset")
* Color (guint, default 0,0,0,127) -> flood (flood-opacity, flood-color)
* Use object's color (boolean, default false) -> composite1 (in1, in2)
*/
@@ -57,14 +58,15 @@ public:
"<id>org.inkscape.effect.filter.ColorDropShadow</id>\n"
"<param name=\"tab\" type=\"notebook\">\n"
"<page name=\"optionstab\" _gui-text=\"" N_("Options") "\">\n"
- "<param name=\"blur\" gui-text=\"" N_("Blur radius (px):") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"200.0\">3.0</param>\n"
- "<param name=\"xoffset\" gui-text=\"" N_("Horizontal offset (px):") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">6.0</param>\n"
- "<param name=\"yoffset\" gui-text=\"" N_("Vertical offset (px):") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">6.0</param>\n"
- "<param name=\"type\" gui-text=\"" N_("Blur type:") "\" type=\"enum\" >\n"
+ "<param name=\"blur\" gui-text=\"" N_("Blur radius (px)") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"200.0\">3.0</param>\n"
+ "<param name=\"xoffset\" gui-text=\"" N_("Horizontal offset (px)") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">6.0</param>\n"
+ "<param name=\"yoffset\" gui-text=\"" N_("Vertical offset (px)") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">6.0</param>\n"
+ "<param name=\"type\" gui-text=\"" N_("Shadow type:") "\" type=\"enum\" >\n"
"<_item value=\"outer\">" N_("Outer") "</_item>\n"
"<_item value=\"inner\">" N_("Inner") "</_item>\n"
"<_item value=\"outercut\">" N_("Outer cutout") "</_item>\n"
"<_item value=\"innercut\">" N_("Inner cutout") "</_item>\n"
+ "<_item value=\"shadow\">" N_("Shadow only") "</_item>\n"
"</param>\n"
"</page>\n"
"<page name=\"coltab\" _gui-text=\"" N_("Blur color") "\">\n"
@@ -151,11 +153,16 @@ ColorizableDropShadow::get_filter_text (Inkscape::Extension::Extension * ext)
comp2op << "out";
comp2in1 << "offset";
comp2in2 << "SourceGraphic";
- } else { //innercut
+ } else if ((g_ascii_strcasecmp("innercut", type) == 0)){
comp1op << "out";
comp1in1 << "flood";
comp1in2 << "SourceGraphic";
comp2op << "in";
+ } else { //shadow
+ comp1op << "in";
+ comp2op << "atop";
+ comp2in1 << "offset";
+ comp2in2 << "offset";
}
_filter = g_strdup_printf(
diff --git a/src/extension/internal/filter/transparency.h b/src/extension/internal/filter/transparency.h
index b29a0a1b3..dcbae26b5 100644
--- a/src/extension/internal/filter/transparency.h
+++ b/src/extension/internal/filter/transparency.h
@@ -129,10 +129,10 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Channel Transparency") "</name>\n"
"<id>org.inkscape.effect.filter.ChannelTransparency</id>\n"
- "<param name=\"red\" gui-text=\"" N_("Red:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">-1</param>\n"
- "<param name=\"green\" gui-text=\"" N_("Green:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0.5</param>\n"
- "<param name=\"blue\" gui-text=\"" N_("Blue:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0.5</param>\n"
- "<param name=\"alpha\" gui-text=\"" N_("Alpha:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">1</param>\n"
+ "<param name=\"red\" gui-text=\"" N_("Red") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">-1</param>\n"
+ "<param name=\"green\" gui-text=\"" N_("Green") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0.5</param>\n"
+ "<param name=\"blue\" gui-text=\"" N_("Blue") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">0.5</param>\n"
+ "<param name=\"alpha\" gui-text=\"" N_("Alpha") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.\" max=\"10.\">1</param>\n"
"<param name=\"invert\" gui-text=\"" N_("Inverted") "\" type=\"boolean\">false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -204,9 +204,9 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Light Eraser") "</name>\n"
"<id>org.inkscape.effect.filter.LightEraser</id>\n"
- "<param name=\"expand\" gui-text=\"" N_("Expansion:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"1000\">50</param>\n"
- "<param name=\"erode\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" min=\"1\" max=\"1000\">100</param>\n"
- "<param name=\"opacity\" gui-text=\"" N_("Global opacity:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.\">1</param>\n"
+ "<param name=\"expand\" gui-text=\"" N_("Expansion") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"1000\">50</param>\n"
+ "<param name=\"erode\" gui-text=\"" N_("Erosion") "\" type=\"float\" appearance=\"full\" min=\"1\" max=\"1000\">100</param>\n"
+ "<param name=\"opacity\" gui-text=\"" N_("Global opacity") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.\">1</param>\n"
"<param name=\"invert\" gui-text=\"" N_("Inverted") "\" type=\"boolean\">false</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
@@ -278,9 +278,9 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Opacity") "</name>\n"
"<id>org.inkscape.effect.filter.Opacity</id>\n"
- "<param name=\"expand\" gui-text=\"" N_("Expansion:") "\" type=\"float\" appearance=\"full\" min=\"1\" max=\"1000\">5</param>\n"
- "<param name=\"erode\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"1000\">1</param>\n"
- "<param name=\"opacity\" gui-text=\"" N_("Global opacity:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.\">1</param>\n"
+ "<param name=\"expand\" gui-text=\"" N_("Expansion") "\" type=\"float\" appearance=\"full\" min=\"1\" max=\"1000\">5</param>\n"
+ "<param name=\"erode\" gui-text=\"" N_("Erosion") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"1000\">1</param>\n"
+ "<param name=\"opacity\" gui-text=\"" N_("Global opacity") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1.\">1</param>\n"
"<effect>\n"
"<object-type>all</object-type>\n"
"<effects-menu>\n"
@@ -340,7 +340,7 @@ public:
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>" N_("Silhouette") "</name>\n"
"<id>org.inkscape.effect.filter.Silhouette</id>\n"
- "<param name=\"blur\" gui-text=\"" N_("Blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"50.00\">0.01</param>\n"
+ "<param name=\"blur\" gui-text=\"" N_("Blur") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"50.00\">0.01</param>\n"
"<param name=\"cutout\" gui-text=\"" N_("Cutout") "\" type=\"boolean\">false</param>\n"
"<param name=\"color\" gui-text=\"" N_("Color") "\" type=\"color\">255</param>\n"
"<effect>\n"
diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp
index 80be2ecc2..a384c7bde 100644
--- a/src/extension/internal/gdkpixbuf-input.cpp
+++ b/src/extension/internal/gdkpixbuf-input.cpp
@@ -1,6 +1,7 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+#include <boost/scoped_ptr.hpp>
#include <glib/gprintf.h>
#include <glibmm/i18n.h>
#include "document-private.h"
@@ -12,96 +13,111 @@
#include "selection-chemistry.h"
#include "sp-image.h"
#include "document-undo.h"
+#include "util/units.h"
+#include "image-resolution.h"
+#include "display/cairo-utils.h"
#include <set>
namespace Inkscape {
-namespace IO {
-GdkPixbuf* pixbuf_new_from_file( char const *utf8name, GError **error );
-}
-
namespace Extension {
namespace Internal {
-static std::set<Glib::ustring> create_lossy_set()
-{
- std::set<Glib::ustring> lossy;
- lossy.insert(".jpg");
- lossy.insert(".jpeg");
- return lossy;
-}
-
SPDocument *
GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri)
{
- bool embed = false;
+ // Determine whether the image should be embedded
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- Glib::ustring attr = prefs->getString("/dialogs/import/link");
- if (strcmp(attr.c_str(), "embed") == 0) {
- embed = true;
- } else if (strcmp(attr.c_str(), "link") == 0) {
- embed = false;
- } else {
- embed = (strcmp(mod->get_param_optiongroup("link"), "embed") == 0);
- if (mod->get_param_bool("ask")) {
- prefs->setString("/dialogs/import/link", mod->get_param_optiongroup("link"));
- mod->set_param_bool("ask", false);
+ bool ask = prefs->getBool("/dialogs/import/ask");
+ Glib::ustring link = prefs->getString("/dialogs/import/link");
+ bool forcexdpi = prefs->getBool("/dialogs/import/forcexdpi");
+ Glib::ustring scale = prefs->getString("/dialogs/import/scale");
+ // std::cout << "GkdpixbufInput::open: "
+ // << " ask: " << ask
+ // << ", link: " << link
+ // << ", forcexdpi: " << forcexdpi
+ // << ", scale: " << scale << std::endl;
+ // std::cout << " in preferences: "
+ // << " ask: " << !mod->get_param_bool("do_not_ask")
+ // << ", link: " << mod->get_param_optiongroup("link")
+ // << ", mod_dpi: " << mod->get_param_optiongroup("dpi")
+ // << ", scale: " << mod->get_param_optiongroup("scale") << std::endl;
+ if( ask ) {
+ Glib::ustring mod_link = mod->get_param_optiongroup("link");
+ Glib::ustring mod_dpi = mod->get_param_optiongroup("dpi");
+ bool mod_forcexdpi = ( mod_dpi.compare( "from_default" ) == 0 );
+ Glib::ustring mod_scale = mod->get_param_optiongroup("scale");
+ if( link.compare( mod_link ) != 0 ) {
+ link = mod_link;
+ }
+ prefs->setString("/dialogs/import/link", link );
+ if( forcexdpi != mod_forcexdpi ) {
+ forcexdpi = mod_forcexdpi;
+ }
+ prefs->setBool("/dialogs/import/forcexdpi", forcexdpi );
+ if( scale.compare( mod_scale ) != 0 ) {
+ scale = mod_scale;
}
+ prefs->setString("/dialogs/import/scale", scale );
+ prefs->setBool("/dialogs/import/ask", !mod->get_param_bool("do_not_ask") );
}
-
+ bool embed = ( link.compare( "embed" ) == 0 );
+
SPDocument *doc = NULL;
- GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file( uri, NULL );
- static std::set<Glib::ustring> lossy = create_lossy_set();
-
- if (pb) { /* We are readable */
- // TODO revisit: bool is_lossy;
- Glib::ustring mime_type, ext;
- Glib::ustring u = uri;
- std::size_t dotpos = u.rfind('.');
- if (dotpos != Glib::ustring::npos) {
- ext = u.substr(dotpos, Glib::ustring::npos);
- }
+ boost::scoped_ptr<Inkscape::Pixbuf> pb(Inkscape::Pixbuf::create_from_file(uri));
- // HACK: replace with something better based on GIO
- if (!ext.empty() && lossy.find(ext) != lossy.end()) {
- // TODO revisit: is_lossy = true;
- mime_type = "image/jpeg";
- } else {
- // TODO revisit: is_lossy = false;
- mime_type = "image/png";
- }
+ // TODO: the pixbuf is created again from the base64-encoded attribute in SPImage.
+ // Find a way to create the pixbuf only once.
+ if (pb) {
doc = SPDocument::createNewDoc(NULL, TRUE, TRUE);
bool saved = DocumentUndo::getUndoSensitive(doc);
DocumentUndo::setUndoSensitive(doc, false); // no need to undo in this temporary document
- double width = gdk_pixbuf_get_width(pb);
- double height = gdk_pixbuf_get_height(pb);
- gchar const *str = gdk_pixbuf_get_option( pb, "Inkscape::DpiX" );
- if ( str ) {
- gint dpi = atoi(str);
- if ( dpi > 0 && dpi != 72 ) {
- double scale = 72.0 / (double)dpi;
- width *= scale;
- }
+ double width = pb->width();
+ double height = pb->height();
+ double defaultxdpi = prefs->getDouble("/dialogs/import/defaultxdpi/value", Inkscape::Util::Quantity::convert(1, "in", "px"));
+ //bool forcexdpi = prefs->getBool("/dialogs/import/forcexdpi");
+ ImageResolution *ir = 0;
+ double xscale = 1;
+ double yscale = 1;
+
+
+ if (!ir && !forcexdpi) {
+ ir = new ImageResolution(uri);
}
- str = gdk_pixbuf_get_option( pb, "Inkscape::DpiY" );
- if ( str ) {
- gint dpi = atoi(str);
- if ( dpi > 0 && dpi != 72 ) {
- double scale = 72.0 / (double)dpi;
- height *= scale;
- }
+ if (ir && ir->ok()) {
+ xscale = 900.0 / floor(10.*ir->x() + .5); // round-off to 0.1 dpi
+ yscale = 900.0 / floor(10.*ir->y() + .5);
+ } else {
+ xscale = 90.0 / defaultxdpi;
+ yscale = 90.0 / defaultxdpi;
}
+ width *= xscale;
+ height *= yscale;
+
+ delete ir; // deleting NULL is safe
+
// Create image node
Inkscape::XML::Document *xml_doc = doc->getReprDoc();
Inkscape::XML::Node *image_node = xml_doc->createElement("svg:image");
sp_repr_set_svg_double(image_node, "width", width);
sp_repr_set_svg_double(image_node, "height", height);
+ // Added 11 Feb 2014 as we now honor "preserveAspectRatio" and this is
+ // what Inkscaper's expect.
+ image_node->setAttribute("preserveAspectRatio", "none");
+
+ if( scale.compare( "auto" ) != 0 ) {
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property(css, "image-rendering", scale.c_str());
+ sp_repr_css_set(image_node, css, "style");
+ sp_repr_css_attr_unref( css );
+ }
+
if (embed) {
- sp_embed_image(image_node, pb, mime_type);
+ sp_embed_image(image_node, pb.get());
} else {
// convert filename to uri
gchar* _uri = g_filename_to_uri(uri, NULL, NULL);
@@ -113,12 +129,17 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri)
}
}
- g_object_unref(pb);
-
// Add it to the current layer
doc->getRoot()->appendChildRepr(image_node);
Inkscape::GC::release(image_node);
fit_canvas_to_drawing(doc);
+
+ // Set viewBox if it doesn't exist
+ if (!doc->getRoot()->viewBox_set) {
+ std::cout << "Viewbox not set, setting" << std::endl;
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit())));
+ }
+
// restore undo, as now this document may be shown to the user if a bitmap was opened
DocumentUndo::setUndoSensitive(doc, saved);
} else {
@@ -166,12 +187,24 @@ GdkpixbufInput::init(void)
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
"<name>%s</name>\n"
"<id>org.inkscape.input.gdkpixbuf.%s</id>\n"
- "<param name='link' type='optiongroup' appearance='full' _gui-text='" N_("Link or embed image:") "' >\n"
+
+ "<param name='link' type='optiongroup' appearance='full' _gui-text='" N_("Image Import Type:") "' _gui-description='" N_("Embed results in stand-alone, larger SVG files. Link references a file outside this SVG document and all files must be moved together.") "' >\n"
"<_option value='embed' >" N_("Embed") "</_option>\n"
"<_option value='link' >" N_("Link") "</_option>\n"
"</param>\n"
- "<_param name='help' type='description'>" N_("Embed results in stand-alone, larger SVG files. Link references a file outside this SVG document and all files must be moved together.") "</_param>\n"
- "<param name=\"ask\" _gui-description='" N_("Hide the dialog next time and always apply the same action.") "' gui-text=\"" N_("Don't ask again") "\" type=\"boolean\" >false</param>\n"
+
+ "<param name='dpi' type='optiongroup' appearance='full' _gui-text='" N_("Image DPI:") "' _gui-description='" N_("Take information from file or use default bitmap import resolution as defined in the preferences.") "' >\n"
+ "<_option value='from_file' >" N_("From file") "</_option>\n"
+ "<_option value='from_default' >" N_("Default import resolution") "</_option>\n"
+ "</param>\n"
+
+ "<param name='scale' type='optiongroup' appearance='full' _gui-text='" N_("Image Rendering Mode:") "' _gui-description='" N_("When an image is upscaled, apply smoothing or keep blocky (pixelated). (Will not work in all browsers.)") "' >\n"
+ "<_option value='auto' >" N_("None (auto)") "</_option>\n"
+ "<_option value='optimizeQuality' >" N_("Smooth (optimizeQuality)") "</_option>\n"
+ "<_option value='optimizeSpeed' >" N_("Blocky (optimizeSpeed)") "</_option>\n"
+ "</param>\n"
+
+ "<param name=\"do_not_ask\" _gui-description='" N_("Hide the dialog next time and always apply the same actions.") "' gui-text=\"" N_("Don't ask again") "\" type=\"boolean\" >false</param>\n"
"<input>\n"
"<extension>.%s</extension>\n"
"<mimetype>%s</mimetype>\n"
diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp
index 56bce2fe8..0059bbec2 100644
--- a/src/extension/internal/grid.cpp
+++ b/src/extension/internal/grid.cpp
@@ -11,6 +11,14 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/box.h>
#include <gtkmm/adjustment.h>
#include <gtkmm/spinbutton.h>
@@ -21,12 +29,14 @@
#include "selection.h"
#include "sp-object.h"
#include "util/glib-list-iterators.h"
+#include "2geom/geom.h"
#include "svg/path-string.h"
#include "extension/effect.h"
#include "extension/system.h"
+#include "util/units.h"
#include "grid.h"
@@ -49,31 +59,31 @@ Grid::load (Inkscape::Extension::Extension */*module*/)
namespace {
Glib::ustring build_lines(Geom::Rect bounding_area,
- float offset[], float spacing[])
+ Geom::Point const &offset, Geom::Point const &spacing)
{
Geom::Point point_offset(0.0, 0.0);
SVG::PathString path_data;
- for ( int axis = 0 ; axis < 2 ; ++axis ) {
+ for ( int axis = Geom::X ; axis <= Geom::Y ; ++axis ) {
point_offset[axis] = offset[axis];
for (Geom::Point start_point = bounding_area.min();
- start_point[axis] + offset[axis] <= (bounding_area.max())[axis];
- start_point[axis] += spacing[axis]) {
+ start_point[axis] + offset[axis] <= (bounding_area.max())[axis];
+ start_point[axis] += spacing[axis]) {
Geom::Point end_point = start_point;
end_point[1-axis] = (bounding_area.max())[1-axis];
path_data.moveTo(start_point + point_offset)
- .lineTo(end_point + point_offset);
+ .lineTo(end_point + point_offset);
}
}
- // std::cout << "Path data:" << path_data.c_str() << std::endl;
- return path_data;
- }
-
+ // std::cout << "Path data:" << path_data.c_str() << std::endl;
+ return path_data;
}
+} // namespace
+
/**
\brief This actually draws the grid.
\param module The effect that was called (unused)
@@ -89,30 +99,31 @@ Grid::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *doc
/* get page size */
SPDocument * doc = document->doc();
bounding_area = Geom::Rect( Geom::Point(0,0),
- Geom::Point(doc->getWidth(), doc->getHeight()) );
+ Geom::Point(doc->getWidth().value("px"), doc->getHeight().value("px")) );
} else {
Geom::OptRect bounds = selection->visualBounds();
if (bounds) {
bounding_area = *bounds;
}
- gdouble doc_height = (document->doc())->getHeight();
+ gdouble doc_height = (document->doc())->getHeight().value("px");
Geom::Rect temprec = Geom::Rect(Geom::Point(bounding_area.min()[Geom::X], doc_height - bounding_area.min()[Geom::Y]),
Geom::Point(bounding_area.max()[Geom::X], doc_height - bounding_area.max()[Geom::Y]));
bounding_area = temprec;
}
- float spacings[2] = { module->get_param_float("xspacing"),
- module->get_param_float("yspacing") };
- float line_width = module->get_param_float("lineWidth");
- float offsets[2] = { module->get_param_float("xoffset"),
- module->get_param_float("yoffset") };
+ gdouble scale = Inkscape::Util::Quantity::convert(1, "px", (document->doc())->getDefaultUnit());
+ bounding_area *= Geom::Scale(scale);
+ Geom::Point spacings( scale * module->get_param_float("xspacing"),
+ scale * module->get_param_float("yspacing") );
+ gdouble line_width = scale * module->get_param_float("lineWidth");
+ Geom::Point offsets( scale * module->get_param_float("xoffset"),
+ scale * module->get_param_float("yoffset") );
Glib::ustring path_data("");
- path_data = build_lines(bounding_area,
- offsets, spacings);
+ path_data = build_lines(bounding_area, offsets, spacings);
Inkscape::XML::Document * xml_doc = document->doc()->getReprDoc();
//XML Tree being used directly here while it shouldn't be.
@@ -132,9 +143,7 @@ Grid::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *doc
path->setAttribute("style", style.c_str());
current_layer->appendChild(path);
- Inkscape::GC::release(path);
-
- return;
+ Inkscape::GC::release(path);
}
/** \brief A class to make an adjustment that uses Extension params */
diff --git a/src/extension/internal/image-resolution.cpp b/src/extension/internal/image-resolution.cpp
new file mode 100644
index 000000000..18eb97f80
--- /dev/null
+++ b/src/extension/internal/image-resolution.cpp
@@ -0,0 +1,380 @@
+/*
+ * Authors:
+ * Daniel Wagenaar <daw@caltech.edu>
+ *
+ * Copyright (C) 2012 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "util/units.h"
+#include "image-resolution.h"
+
+#define IR_TRY_PNG 1
+#include <png.h>
+
+#ifdef HAVE_EXIF
+#include <math.h>
+#include <libexif/exif-data.h>
+#endif
+
+#define IR_TRY_EXIV 0
+
+#ifdef HAVE_JPEG
+#define IR_TRY_JFIF 1
+#include <jpeglib.h>
+#include <setjmp.h>
+#endif
+
+#ifdef WITH_IMAGE_MAGICK
+#include <Magick++.h>
+#endif
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+ImageResolution::ImageResolution(char const *fn) {
+ ok_ = false;
+
+ readpng(fn);
+ if (!ok_) {
+ readexiv(fn);
+ }
+ if (!ok_) {
+ readjfif(fn);
+ }
+ if (!ok_) {
+ readexif(fn);
+ }
+ if (!ok_) {
+ readmagick(fn);
+ }
+}
+
+bool ImageResolution::ok() const {
+ return ok_;
+}
+
+double ImageResolution::x() const {
+ return x_;
+}
+
+double ImageResolution::y() const {
+ return y_;
+}
+
+
+
+#if IR_TRY_PNG
+
+static bool haspngheader(FILE *fp) {
+ unsigned char header[8];
+ if ( fread(header, 1, 8, fp) != 8 ) {
+ return false;
+ }
+
+ fseek(fp, 0, SEEK_SET);
+
+ if (png_sig_cmp(header, 0, 8)) {
+ return false;
+ }
+
+ return true;
+}
+
+// Implementation using libpng
+void ImageResolution::readpng(char const *fn) {
+ FILE *fp = fopen(fn, "rb");
+ if (!fp)
+ return;
+
+ if (!haspngheader(fp)) {
+ fclose(fp);
+ return;
+ }
+
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ if (!png_ptr)
+ return;
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, 0, 0);
+ return;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, 0);
+ fclose(fp);
+ return;
+ }
+
+ png_init_io(png_ptr, fp);
+ png_read_info(png_ptr, info_ptr);
+
+ png_uint_32 res_x, res_y;
+ int unit_type;
+ png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type);
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, 0);
+ fclose(fp);
+
+ if (unit_type == PNG_RESOLUTION_METER) {
+ ok_ = true;
+ x_ = res_x * 2.54 / 100;
+ y_ = res_y * 2.54 / 100;
+ }
+}
+#else
+
+// Dummy implementation
+void ImageResolution::readpng(char const *) {
+}
+
+#endif
+
+#if IR_TRY_EXIF
+
+static double exifDouble(ExifEntry *entry, ExifByteOrder byte_order) {
+ switch (entry->format) {
+ case EXIF_FORMAT_BYTE: {
+ return double(entry->data[0]);
+ }
+ case EXIF_FORMAT_SHORT: {
+ return double(exif_get_short(entry->data, byte_order));
+ }
+ case EXIF_FORMAT_LONG: {
+ return double(exif_get_long(entry->data, byte_order));
+ }
+ case EXIF_FORMAT_RATIONAL: {
+ ExifRational r = exif_get_rational(entry->data, byte_order);
+ return double(r.numerator) / double(r.denominator);
+ }
+ case EXIF_FORMAT_SBYTE: {
+ return double(*(signed char *)entry->data);
+ }
+ case EXIF_FORMAT_SSHORT: {
+ return double(exif_get_sshort(entry->data, byte_order));
+ }
+ case EXIF_FORMAT_SLONG: {
+ return double(exif_get_slong(entry->data, byte_order));
+ }
+ case EXIF_FORMAT_SRATIONAL: {
+ ExifSRational r = exif_get_srational(entry->data, byte_order);
+ return double(r.numerator) / double(r.denominator);
+ }
+ case EXIF_FORMAT_FLOAT: {
+ return double((reinterpret_cast<float *>(entry->data))[0]);
+ }
+ case EXIF_FORMAT_DOUBLE: {
+ return (reinterpret_cast<double *>(entry->data))[0];
+ }
+ default: {
+ return nan(0);
+ }
+ }
+}
+
+// Implementation using libexif
+void ImageResolution::readexif(char const *fn) {
+ ExifData *ed;
+ ed = exif_data_new_from_file(fn);
+ if (!ed)
+ return;
+
+ ExifByteOrder byte_order = exif_data_get_byte_order(ed);
+
+ ExifEntry *xres = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_X_RESOLUTION);
+ ExifEntry *yres = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_Y_RESOLUTION);
+ ExifEntry *unit = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_RESOLUTION_UNIT);
+
+ if ( xres && yres ) {
+ x_ = exifDouble(xres, byte_order);
+ y_ = exifDouble(yres, byte_order);
+ if (unit) {
+ double u = exifDouble(unit, byte_order);
+ if ( u == 3 ) {
+ x_ *= 2.54;
+ y_ *= 2.54;
+ }
+ }
+ ok_ = true;
+ }
+ exif_data_free(ed);
+}
+
+#else
+
+// Dummy implementation
+void ImageResolution::readexif(char const *) {
+}
+
+#endif
+
+#if IR_TRY_EXIV
+
+void ImageResolution::readexiv(char const *fn) {
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(fn);
+ if (!image.get())
+ return;
+
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty())
+ return;
+
+ Exiv2::ExifData::const_iterator end = exifData.end();
+ bool havex = false;
+ bool havey = false;
+ bool haveunit = false;
+ int unit;
+ for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) {
+ if (ok_)
+ break;
+ if ( i->tag() == 0x011a ) {
+ // X Resolution
+ x_ = i->toFloat();
+ havex = true;
+ } else if ( i->tag() == 0x011b ) {
+ // Y Resolution
+ y_ = i->toFloat();
+ havey = true;
+ } else if ( i->tag() == 0x0128 ) {
+ unit = i->toLong();
+ }
+ ok_ = havex && havey && haveunit;
+ }
+ if (haveunit) {
+ if ( unit == 3 ) {
+ x_ *= 2.54;
+ y_ *= 2.54;
+ }
+ }
+ ok_ = havex && havey;
+}
+
+#else
+
+// Dummy implementation
+void ImageResolution::readexiv(char const *) {
+}
+
+#endif
+
+#if IR_TRY_JFIF
+
+static void irjfif_error_exit(j_common_ptr cinfo) {
+ longjmp(*(jmp_buf*)cinfo->client_data, 1);
+}
+
+static void irjfif_emit_message(j_common_ptr, int) {
+}
+
+static void irjfif_output_message(j_common_ptr) {
+}
+
+static void irjfif_format_message(j_common_ptr, char *) {
+}
+
+static void irjfif_reset(j_common_ptr) {
+}
+
+void ImageResolution::readjfif(char const *fn) {
+ FILE *ifd = fopen(fn, "rb");
+ if (!ifd) {
+ return;
+ }
+
+ struct jpeg_decompress_struct cinfo;
+ jmp_buf jbuf;
+ struct jpeg_error_mgr jerr;
+
+ if (setjmp(jbuf)) {
+ fclose(ifd);
+ jpeg_destroy_decompress(&cinfo);
+ return;
+ }
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+ jerr.error_exit = &irjfif_error_exit;
+ jerr.emit_message = &irjfif_emit_message;
+ jerr.output_message = &irjfif_output_message;
+ jerr.format_message = &irjfif_format_message;
+ jerr.reset_error_mgr = &irjfif_reset;
+ cinfo.client_data = (void*)&jbuf;
+
+ jpeg_stdio_src(&cinfo, ifd);
+ jpeg_read_header(&cinfo, TRUE);
+
+ if (cinfo.saw_JFIF_marker) { // JFIF APP0 marker was seen
+ if ( cinfo.density_unit == 1 ) { // dots/inch
+ x_ = cinfo.X_density;
+ y_ = cinfo.Y_density;
+ ok_ = true;
+ } else if ( cinfo.density_unit == 2 ) { // dots/cm
+ x_ = cinfo.X_density * 2.54;
+ y_ = cinfo.Y_density * 2.54;
+ ok_ = true;
+ }
+ /* According to http://www.jpeg.org/public/jfif.pdf (page 7):
+ * "Xdensity and Ydensity should always be non-zero".
+ * but in some cases, they are (see LP bug #1275443) */
+ if (x_ == 0 or y_ == 0) {
+ ok_ = false;
+ }
+ }
+ jpeg_destroy_decompress(&cinfo);
+ fclose(ifd);
+}
+
+#else
+
+// Dummy implementation
+void ImageResolution::readjfif(char const *) {
+}
+
+#endif
+
+#ifdef WITH_IMAGE_MAGICK
+void ImageResolution::readmagick(char const *fn) {
+ Magick::Image image;
+ try {
+ image.read(fn);
+ } catch (Magick::Error & err) {
+ g_warning("ImageMagick error: %s", err.what());
+ return;
+ } catch (...) {
+ g_warning("ImageResolution::readmagick: Unknown error");
+ return;
+ }
+ Magick::Geometry geo = image.density();
+ std::string type = image.magick();
+
+ if (type == "PNG") { // PNG only supports pixelspercentimeter
+ x_ = Inkscape::Util::Quantity::convert((double)geo.width(), "in", "cm");
+ y_ = Inkscape::Util::Quantity::convert((double)geo.height(), "in", "cm");
+ } else {
+ x_ = (double)geo.width();
+ y_ = (double)geo.height();
+ }
+
+ ok_ = true;
+}
+
+#else
+
+// Dummy implementation
+void ImageResolution::readmagick(char const *) {
+}
+
+#endif /* WITH_IMAGE_MAGICK */
+
+}
+}
+}
diff --git a/src/extension/internal/image-resolution.h b/src/extension/internal/image-resolution.h
new file mode 100644
index 000000000..6c4928a35
--- /dev/null
+++ b/src/extension/internal/image-resolution.h
@@ -0,0 +1,41 @@
+/*
+ * Authors:
+ * Daniel Wagenaar <daw@caltech.edu>
+ *
+ * Copyright (C) 2012 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+
+#ifndef IMAGE_RESOLUTION_H
+
+#define IMAGE_RESOLUTION_H
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class ImageResolution {
+public:
+ ImageResolution(char const *fn);
+ bool ok() const;
+ double x() const;
+ double y() const;
+private:
+ bool ok_;
+ double x_;
+ double y_;
+private:
+ void readpng(char const *fn);
+ void readexif(char const *fn);
+ void readexiv(char const *fn);
+ void readjfif(char const *fn);
+ void readmagick(char const *fn);
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/extension/internal/javafx-out.cpp b/src/extension/internal/javafx-out.cpp
index 67c0fae66..19946022c 100644
--- a/src/extension/internal/javafx-out.cpp
+++ b/src/extension/internal/javafx-out.cpp
@@ -20,6 +20,8 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+
+#include <glibmm/miscutils.h>
#include "javafx-out.h"
#include <inkscape.h>
#include <inkscape-version.h>
@@ -394,12 +396,14 @@ bool JavaFXOutput::doStyle(SPStyle *style)
}
else if (fill.isPaintserver()){
if (fill.value.href && fill.value.href->getURI() ){
- String uri = fill.value.href->getURI()->toString();
+ gchar *str = fill.value.href->getURI()->toString();
+ String uri = (str ? str : "");
/* trim the anchor '#' from the front */
if (uri.size() > 0 && uri[0]=='#') {
uri = uri.substr(1);
}
out(" fill: %s()\n", sanatize(uri).c_str());
+ g_free(str);
}
}
@@ -414,10 +418,8 @@ bool JavaFXOutput::doStyle(SPStyle *style)
* SPIEnum stroke_linecap;
* SPIEnum stroke_linejoin;
* SPIFloat stroke_miterlimit;
- * NRVpathDash stroke_dash;
- * unsigned stroke_dasharray_set : 1;
- * unsigned stroke_dasharray_inherit : 1;
- * unsigned stroke_dashoffset_set : 1;
+ * SPIDashArray stroke_dasharray;
+ * SPILength stroke_dashoffset;
* SPIScale24 stroke_opacity;
*/
if (style->stroke_opacity.value > 0)
@@ -432,16 +434,16 @@ bool JavaFXOutput::doStyle(SPStyle *style)
out(" strokeLineCap: %s\n", getStrokeLineCap(linecap).c_str());
out(" strokeLineJoin: %s\n", getStrokeLineJoin(linejoin).c_str());
out(" strokeMiterLimit: %s\n", DSTR(style->stroke_miterlimit.value));
- if (style->stroke_dasharray_set) {
- if (style->stroke_dashoffset_set) {
- out(" strokeDashOffset: %s\n", DSTR(style->stroke_dash.offset));
+ if (style->stroke_dasharray.set) {
+ if (style->stroke_dashoffset.set) {
+ out(" strokeDashOffset: %s\n", DSTR(style->stroke_dashoffset.value));
}
out(" strokeDashArray: [ ");
- for(int i = 0; i < style->stroke_dash.n_dash; i++ ) {
+ for(unsigned i = 0; i < style->stroke_dasharray.values.size(); i++ ) {
if (i > 0) {
- out(", %.2lf", style->stroke_dash.dash[i]);
+ out(", %.2lf", style->stroke_dasharray.values[i]);
}else {
- out(" %.2lf", style->stroke_dash.dash[i]);
+ out(" %.2lf", style->stroke_dasharray.values[i]);
}
}
out(" ]\n");
diff --git a/src/extension/internal/latex-pstricks.cpp b/src/extension/internal/latex-pstricks.cpp
index c1eddf539..6aaa1bca4 100644
--- a/src/extension/internal/latex-pstricks.cpp
+++ b/src/extension/internal/latex-pstricks.cpp
@@ -21,7 +21,7 @@
#include <2geom/hvlinesegment.h>
#include <errno.h>
#include <signal.h>
-#include <unit-constants.h>
+#include "util/units.h"
#include "helper/geom-curves.h"
#include "extension/print.h"
@@ -117,8 +117,8 @@ unsigned int PrintLatex::begin (Inkscape::Extension::Print *mod, SPDocument *doc
}
// width and height in pt
- _width = doc->getWidth() * PT_PER_PX;
- _height = doc->getHeight() * PT_PER_PX;
+ _width = doc->getWidth().value("pt");
+ _height = doc->getHeight().value("pt");
if (res >= 0) {
@@ -128,10 +128,10 @@ unsigned int PrintLatex::begin (Inkscape::Extension::Print *mod, SPDocument *doc
os << "\\psset{xunit=.5pt,yunit=.5pt,runit=.5pt}\n";
// from now on we can output px, but they will be treated as pt
- os << "\\begin{pspicture}(" << doc->getWidth() << "," << doc->getHeight() << ")\n";
+ os << "\\begin{pspicture}(" << doc->getWidth().value("px") << "," << doc->getHeight().value("px") << ")\n";
}
- m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, doc->getHeight())); /// @fixme hardcoded doc2dt transform
+ m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, doc->getHeight().value("px"))); /// @fixme hardcoded doc2dt transform
return fprintf(_stream, "%s", os.str().c_str());
}
@@ -239,16 +239,13 @@ unsigned int PrintLatex::stroke(Inkscape::Extension::Print * /*mod*/,
os<<",strokeopacity="<<stroke_opacity;
}
- if (style->stroke_dasharray_set &&
- style->stroke_dash.n_dash &&
- style->stroke_dash.dash) {
- int i;
+ if (style->stroke_dasharray.set && !style->stroke_dasharray.values.empty()) {
os << ",linestyle=dashed,dash=";
- for (i = 0; i < style->stroke_dash.n_dash; i++) {
+ for (unsigned i = 0; i < style->stroke_dasharray.values.size(); i++) {
if ((i)) {
os << " ";
}
- os << style->stroke_dash.dash[i];
+ os << style->stroke_dasharray.values[i];
}
}
diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp
index ebd73a033..398c9f061 100644
--- a/src/extension/internal/latex-text-renderer.cpp
+++ b/src/extension/internal/latex-text-renderer.cpp
@@ -39,7 +39,7 @@
#include "sp-rect.h"
#include "text-editing.h"
-#include <unit-constants.h>
+#include "util/units.h"
#include "extension/system.h"
@@ -56,7 +56,7 @@ namespace Internal {
*/
bool
latex_render_document_text_to_file( SPDocument *doc, gchar const *filename,
- const gchar * const exportId, bool exportDrawing, bool exportCanvas,
+ const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px,
bool pdflatex)
{
doc->ensureUpToDate();
@@ -84,7 +84,7 @@ latex_render_document_text_to_file( SPDocument *doc, gchar const *filename,
bool ret = renderer->setTargetFile(filename);
if (ret) {
/* Render document */
- bool ret = renderer->setupDocument(doc, pageBoundingBox, base);
+ bool ret = renderer->setupDocument(doc, pageBoundingBox, bleedmargin_px, base);
if (ret) {
renderer->renderItem(base);
}
@@ -98,7 +98,9 @@ latex_render_document_text_to_file( SPDocument *doc, gchar const *filename,
LaTeXTextRenderer::LaTeXTextRenderer(bool pdflatex)
: _stream(NULL),
_filename(NULL),
- _pdflatex(pdflatex)
+ _pdflatex(pdflatex),
+ _omittext_state(EMPTY),
+ _omittext_page(1)
{
push_transform(Geom::identity());
}
@@ -262,6 +264,11 @@ LaTeXTextRenderer::sp_use_render(SPItem *item)
void
LaTeXTextRenderer::sp_text_render(SPItem *item)
{
+ // Only PDFLaTeX supports importing a single page of a graphics file,
+ // so only PDF backend gets interleaved text/graphics
+ if (_pdflatex && _omittext_state == GRAPHIC_ON_TOP)
+ _omittext_state = NEW_PAGE_ON_GRAPHIC;
+
SPText *textobj = SP_TEXT (item);
SPStyle *style = item->style;
@@ -395,6 +402,11 @@ Flowtext is possible by using a minipage! :)
Flowing in rectangle is possible, not in arb shape.
*/
+ // Only PDFLaTeX supports importing a single page of a graphics file,
+ // so only PDF backend gets interleaved text/graphics
+ if (_pdflatex && _omittext_state == GRAPHIC_ON_TOP)
+ _omittext_state = NEW_PAGE_ON_GRAPHIC;
+
SPFlowtext *flowtext = SP_FLOWTEXT(item);
SPStyle *style = item->style;
@@ -405,7 +417,7 @@ Flowing in rectangle is possible, not in arb shape.
}
SPRect *frame = SP_RECT(frame_item);
- Geom::Rect framebox = sp_rect_get_rect(frame) * transform();
+ Geom::Rect framebox = frame->getRect() * transform();
// get position and alignment
// Align on topleft corner.
@@ -556,8 +568,13 @@ LaTeXTextRenderer::sp_item_invoke_render(SPItem *item)
return sp_text_render(item);
} else if (SP_IS_FLOWTEXT(item)) {
return sp_flowtext_render(item);
+ } else {
+ // Only PDFLaTeX supports importing a single page of a graphics file,
+ // so only PDF backend gets interleaved text/graphics
+ if (_pdflatex && (_omittext_state == EMPTY || _omittext_state == NEW_PAGE_ON_GRAPHIC))
+ writeGraphicPage();
+ _omittext_state = GRAPHIC_ON_TOP;
}
- // We are not interested in writing the other SPItem types to LaTeX
}
void
@@ -568,8 +585,22 @@ LaTeXTextRenderer::renderItem(SPItem *item)
pop_transform();
}
+void
+LaTeXTextRenderer::writeGraphicPage(void) {
+ Inkscape::SVGOStringStream os;
+ os.setf(std::ios::fixed); // no scientific notation
+
+ // strip pathname, as it is probably desired. Having a specific path in the TeX file is not convenient.
+ if (_pdflatex)
+ os << " \\put(0,0){\\includegraphics[width=\\unitlength,page=" << _omittext_page++ << "]{" << _filename << "}}%\n";
+ else
+ os << " \\put(0,0){\\includegraphics[width=\\unitlength]{" << _filename << "}}%\n";
+
+ fprintf(_stream, "%s", os.str().c_str());
+}
+
bool
-LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *base)
+LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, float bleedmargin_px, SPItem *base)
{
// The boundingbox calculation here should be exactly the same as the one by CairoRenderer::setupDocument !
@@ -588,6 +619,7 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *
}
d = *bbox;
}
+ d.expandBy(bleedmargin_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.width());
@@ -601,7 +633,7 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *
}
// flip y-axis
- push_transform( Geom::Scale(1,-1) * Geom::Translate(0, doc->getHeight()) ); /// @fixme hardcoded desktop transform!
+ push_transform( Geom::Scale(1,-1) * Geom::Translate(0, doc->getHeight().value("px")) ); /// @fixme hardcoded desktop transform!
// write the info to LaTeX
Inkscape::SVGOStringStream os;
@@ -610,7 +642,7 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *
// scaling of the image when including it in LaTeX
os << " \\ifx\\svgwidth\\undefined%\n";
- os << " \\setlength{\\unitlength}{" << d.width() * PT_PER_PX << "bp}%\n"; // note: 'bp' is the Postscript pt unit in LaTeX, see LP bug #792384
+ os << " \\setlength{\\unitlength}{" << Inkscape::Util::Quantity::convert(d.width(), "px", "pt") << "bp}%\n"; // note: 'bp' is the Postscript pt unit in LaTeX, see LP bug #792384
os << " \\ifx\\svgscale\\undefined%\n";
os << " \\relax%\n";
os << " \\else%\n";
@@ -624,11 +656,12 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem *
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.
- os << " \\put(0,0){\\includegraphics[width=\\unitlength]{" << _filename << "}}%\n";
fprintf(_stream, "%s", os.str().c_str());
+ if (!_pdflatex)
+ writeGraphicPage();
+
return true;
}
diff --git a/src/extension/internal/latex-text-renderer.h b/src/extension/internal/latex-text-renderer.h
index 66055a3bc..77d12bc61 100644
--- a/src/extension/internal/latex-text-renderer.h
+++ b/src/extension/internal/latex-text-renderer.h
@@ -22,14 +22,14 @@
#include <stack>
class SPItem;
-struct SPRoot;
+class SPRoot;
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,
+ const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px,
bool pdflatex);
class LaTeXTextRenderer {
@@ -41,17 +41,26 @@ public:
/** 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);
+ bool setupDocument(SPDocument *doc, bool pageBoundingBox, float bleedmargin_px, SPItem *base);
/** Traverses the object tree and invokes the render methods. */
void renderItem(SPItem *item);
protected:
+ enum LaTeXOmitTextPageState {
+ EMPTY,
+ GRAPHIC_ON_TOP,
+ NEW_PAGE_ON_GRAPHIC
+ };
+
FILE * _stream;
gchar * _filename;
bool _pdflatex; /** true if ouputting for pdfLaTeX*/
+ LaTeXOmitTextPageState _omittext_state;
+ gulong _omittext_page;
+
void push_transform(Geom::Affine const &transform);
Geom::Affine const & transform();
void pop_transform();
@@ -60,6 +69,8 @@ protected:
void writePreamble();
void writePostamble();
+ void writeGraphicPage();
+
void sp_item_invoke_render(SPItem *item);
void sp_root_render(SPRoot *item);
void sp_group_render(SPItem *item);
diff --git a/src/extension/internal/metafile-inout.cpp b/src/extension/internal/metafile-inout.cpp
new file mode 100644
index 000000000..1d419a6a0
--- /dev/null
+++ b/src/extension/internal/metafile-inout.cpp
@@ -0,0 +1,211 @@
+/** @file
+ * @brief Metafile input - common routines
+ *//*
+ * Authors:
+ * David Mathog
+ *
+ * Copyright (C) 2013 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <cstring>
+#include <fstream>
+#include <glib.h>
+#include <glibmm/miscutils.h>
+
+#include "display/curve.h"
+#include "extension/internal/metafile-inout.h" // picks up PNG
+#include "extension/print.h"
+#include "path-prefix.h"
+#include "sp-gradient.h"
+#include "sp-image.h"
+#include "sp-linear-gradient.h"
+#include "sp-pattern.h"
+#include "sp-radial-gradient.h"
+#include "style.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+Metafile::~Metafile()
+{
+ return;
+}
+
+/** Construct a PNG in memory from an RGB from the EMF file
+
+from:
+http://www.lemoda.net/c/write-png/
+
+which was based on:
+http://stackoverflow.com/questions/1821806/how-to-encode-png-to-buffer-using-libpng
+
+gcc -Wall -o testpng testpng.c -lpng
+
+Originally here, but moved up
+
+#include <png.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+*/
+
+
+/* Given "bitmap", this returns the pixel of bitmap at the point
+ ("x", "y"). */
+
+pixel_t * Metafile::pixel_at (bitmap_t * bitmap, int x, int y)
+{
+ return bitmap->pixels + bitmap->width * y + x;
+}
+
+
+/* Write "bitmap" to a PNG file specified by "path"; returns 0 on
+ success, non-zero on error. */
+
+void
+Metafile::my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ PMEMPNG p=(PMEMPNG)png_get_io_ptr(png_ptr);
+
+ size_t nsize = p->size + length;
+
+ /* allocate or grow buffer */
+ if(p->buffer){ p->buffer = (char *) realloc(p->buffer, nsize); }
+ else{ p->buffer = (char *) malloc(nsize); }
+
+ if(!p->buffer){ png_error(png_ptr, "Write Error"); }
+
+ /* copy new bytes to end of buffer */
+ memcpy(p->buffer + p->size, data, length);
+ p->size += length;
+}
+
+void Metafile::toPNG(PMEMPNG accum, int width, int height, const char *px){
+ bitmap_t bmStore;
+ bitmap_t *bitmap = &bmStore;
+ accum->buffer=NULL; // PNG constructed in memory will end up here, caller must free().
+ accum->size=0;
+ bitmap->pixels=(pixel_t *)px;
+ bitmap->width = width;
+ bitmap->height = height;
+
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ size_t x, y;
+ png_byte ** row_pointers = NULL;
+ /* The following number is set by trial and error only. I cannot
+ see where it it is documented in the libpng manual.
+ */
+ int pixel_size = 3;
+ int depth = 8;
+
+ png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL){
+ accum->buffer=NULL;
+ return;
+ }
+
+ info_ptr = png_create_info_struct (png_ptr);
+ if (info_ptr == NULL){
+ png_destroy_write_struct (&png_ptr, &info_ptr);
+ accum->buffer=NULL;
+ return;
+ }
+
+ /* Set up error handling. */
+
+ if (setjmp (png_jmpbuf (png_ptr))) {
+ png_destroy_write_struct (&png_ptr, &info_ptr);
+ accum->buffer=NULL;
+ return;
+ }
+
+ /* Set image attributes. */
+
+ png_set_IHDR (
+ png_ptr,
+ info_ptr,
+ bitmap->width,
+ bitmap->height,
+ depth,
+ PNG_COLOR_TYPE_RGB,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT
+ );
+
+ /* Initialize rows of PNG. */
+
+ row_pointers = (png_byte **) png_malloc (png_ptr, bitmap->height * sizeof (png_byte *));
+ for (y = 0; y < bitmap->height; ++y) {
+ png_byte *row =
+ (png_byte *) png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width * pixel_size);
+ row_pointers[bitmap->height - y - 1] = row; // Row order in EMF is reversed.
+ for (x = 0; x < bitmap->width; ++x) {
+ pixel_t * pixel = pixel_at (bitmap, x, y);
+ *row++ = pixel->red; // R & B channels were set correctly by DIB_to_RGB
+ *row++ = pixel->green;
+ *row++ = pixel->blue;
+ }
+ }
+
+ /* Write the image data to memory */
+
+ png_set_rows (png_ptr, info_ptr, row_pointers);
+
+ png_set_write_fn(png_ptr, accum, my_png_write_data, NULL);
+
+ png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+
+ for (y = 0; y < bitmap->height; y++) {
+ png_free (png_ptr, row_pointers[y]);
+ }
+ png_free (png_ptr, row_pointers);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+}
+
+
+/* convert an EMF RGB(A) color to 0RGB
+inverse of gethexcolor() in emf-print.cpp
+*/
+uint32_t Metafile::sethexcolor(U_COLORREF color){
+
+ uint32_t out;
+ out = (U_RGBAGetR(color) << 16) +
+ (U_RGBAGetG(color) << 8 ) +
+ (U_RGBAGetB(color) );
+ return(out);
+}
+
+/* Return the base64 encoded png which is shown for all bad images.
+Currently a random 3x4 blotch.
+Caller must free.
+*/
+gchar *Metafile::bad_image_png(void){
+ gchar *gstring = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=");
+ return(gstring);
+}
+
+
+
+} // namespace Internal
+} // namespace Extension
+} // namespace Inkscape
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/metafile-inout.h b/src/extension/internal/metafile-inout.h
new file mode 100644
index 000000000..968773a3a
--- /dev/null
+++ b/src/extension/internal/metafile-inout.h
@@ -0,0 +1,93 @@
+/** @file
+ * @brief Metafile input - common functions
+ *//*
+ * Authors:
+ * David Mathog
+ *
+ * Copyright (C) 2013 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_INOUT_H
+#define SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_INOUT_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#define PNG_SKIP_SETJMP_CHECK // else any further png.h include blows up in the compiler
+#include <png.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <map>
+#include <stack>
+#include <glibmm/ustring.h>
+#include <libuemf/uemf.h>
+#include <2geom/affine.h>
+#include <2geom/pathvector.h>
+
+#include "extension/implementation/implementation.h"
+
+class SPObject;
+
+namespace Inkscape {
+class Pixbuf;
+
+namespace Extension {
+namespace Internal {
+
+/* A coloured pixel. */
+typedef struct {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+ uint8_t opacity;
+} pixel_t;
+
+/* A picture. */
+ typedef struct {
+ pixel_t *pixels;
+ size_t width;
+ size_t height;
+} bitmap_t;
+
+/* structure to store PNG image bytes */
+typedef struct {
+ char *buffer;
+ size_t size;
+} MEMPNG, *PMEMPNG;
+
+class Metafile
+ : public Inkscape::Extension::Implementation::Implementation
+{
+public:
+ Metafile() {}
+ ~Metafile();
+
+protected:
+ static uint32_t sethexcolor(U_COLORREF color);
+ static pixel_t *pixel_at (bitmap_t * bitmap, int x, int y);
+ static void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length);
+ static void toPNG(PMEMPNG accum, int width, int height, const char *px);
+ static gchar *bad_image_png(void);
+
+
+private:
+};
+
+} // namespace Internal
+} // namespace Extension
+} // namespace Inkscape
+
+#endif // SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_INOUT_H
+
+/*
+ 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:
+*/
diff --git a/src/extension/internal/metafile-print.cpp b/src/extension/internal/metafile-print.cpp
new file mode 100644
index 000000000..73d63f27d
--- /dev/null
+++ b/src/extension/internal/metafile-print.cpp
@@ -0,0 +1,493 @@
+/** @file
+ * @brief Metafile printing - common routines
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2013 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <cstring>
+#include <fstream>
+#include <glib.h>
+#include <glibmm/miscutils.h>
+#include <2geom/rect.h>
+#include <2geom/curves.h>
+#include <2geom/svg-path-parser.h>
+
+#include "extension/internal/metafile-print.h"
+#include "extension/print.h"
+#include "path-prefix.h"
+#include "sp-gradient.h"
+#include "sp-image.h"
+#include "sp-linear-gradient.h"
+#include "sp-pattern.h"
+#include "sp-radial-gradient.h"
+#include "style.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+bool PrintMetafile::_ppt_fontfix_read = false;
+PrintMetafile::FontfixMap PrintMetafile::_ppt_fixable_fonts;
+
+PrintMetafile::~PrintMetafile()
+{
+#ifndef G_OS_WIN32
+ // restore default signal handling for SIGPIPE
+ (void) signal(SIGPIPE, SIG_DFL);
+#endif
+ return;
+}
+
+bool PrintMetafile::textToPath(Inkscape::Extension::Print *ext)
+{
+ return ext->get_param_bool("textToPath");
+}
+
+unsigned int PrintMetafile::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/)
+{
+ if (!m_tr_stack.empty()) {
+ Geom::Affine tr_top = m_tr_stack.top();
+ m_tr_stack.push(transform * tr_top);
+ } else {
+ m_tr_stack.push(transform);
+ }
+
+ return 1;
+}
+
+unsigned int PrintMetafile::release(Inkscape::Extension::Print * /*mod*/)
+{
+ m_tr_stack.pop();
+ return 1;
+}
+
+bool PrintMetafile::_load_ppt_fontfix_data() //this is not called by any other source files
+{
+ static bool ppt_fontfix_available = false;
+
+ if (_ppt_fontfix_read) return ppt_fontfix_available;
+ _ppt_fontfix_read = true;
+
+ // add default entry
+ _ppt_fixable_fonts.insert(std::make_pair(Glib::ustring(""), FontfixParams()));
+
+ std::string fontfix_path = Glib::build_filename(INKSCAPE_EXTENSIONDIR, "fontfix.conf");
+ std::ifstream fontfix_file(fontfix_path.c_str(), std::ios::in);
+
+ if (!fontfix_file.is_open()) {
+ g_warning("Unable to open PowerPoint fontfix file: %s\n"
+ "PowerPoint ungrouping compensation in WMF/EMF export will not be available.",
+ fontfix_path.c_str());
+ return (ppt_fontfix_available = false);
+ }
+
+ char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL));
+ setlocale(LC_NUMERIC, "C");
+
+ std::string instr;
+ while (std::getline(fontfix_file, instr)) {
+ if (instr[0] == '#') {
+ continue;
+ }
+ // not a comment, get the 4 values from the line
+ FontfixParams params;
+ char fontname[128];
+ int elements = sscanf(instr.c_str(), "%lf %lf %lf %127[^\n]",
+ &params.f1, &params.f2, &params.f3, &fontname[0]);
+ if (elements != 4) {
+ g_warning("Malformed line in %s: %s\n", fontfix_path.c_str(), instr.c_str());
+ continue;
+ }
+ _ppt_fixable_fonts.insert(std::make_pair(Glib::ustring(fontname), params));
+ }
+ fontfix_file.close(); // not strictly necessary
+
+ setlocale(LC_NUMERIC, oldlocale);
+ g_free(oldlocale);
+ return (ppt_fontfix_available = true);
+}
+
+// Finds font fix parameters for the given fontname.
+void PrintMetafile::_lookup_ppt_fontfix(Glib::ustring const &fontname, FontfixParams &params)
+{
+ if (!_ppt_fontfix_read) _load_ppt_fontfix_data();
+
+ FontfixMap::iterator f = _ppt_fixable_fonts.find(fontname);
+ if (f != _ppt_fixable_fonts.end()) {
+ params = f->second;
+ }
+}
+
+U_COLORREF PrintMetafile::_gethexcolor(uint32_t color)
+{
+ U_COLORREF out;
+ out = U_RGB(
+ (color >> 16) & 0xFF,
+ (color >> 8) & 0xFF,
+ (color >> 0) & 0xFF
+ );
+ return out;
+}
+
+// Translate Inkscape weights to EMF weights.
+uint32_t PrintMetafile::_translate_weight(unsigned inkweight)
+{
+ switch (inkweight) {
+ // 400 is tested first, as it is the most common case
+ case SP_CSS_FONT_WEIGHT_400: return U_FW_NORMAL;
+ case SP_CSS_FONT_WEIGHT_100: return U_FW_THIN;
+ case SP_CSS_FONT_WEIGHT_200: return U_FW_EXTRALIGHT;
+ case SP_CSS_FONT_WEIGHT_300: return U_FW_LIGHT;
+ case SP_CSS_FONT_WEIGHT_500: return U_FW_MEDIUM;
+ case SP_CSS_FONT_WEIGHT_600: return U_FW_SEMIBOLD;
+ case SP_CSS_FONT_WEIGHT_700: return U_FW_BOLD;
+ case SP_CSS_FONT_WEIGHT_800: return U_FW_EXTRABOLD;
+ case SP_CSS_FONT_WEIGHT_900: return U_FW_HEAVY;
+ default: return U_FW_NORMAL;
+ }
+}
+
+/* opacity weighting of two colors as float. v1 is the color, op is its opacity, v2 is the background color */
+inline float opweight(float v1, float v2, float op)
+{
+ return v1 * op + v2 * (1.0 - op);
+}
+
+U_COLORREF PrintMetafile::avg_stop_color(SPGradient *gr)
+{
+ U_COLORREF cr;
+ int last = gr->vector.stops.size() - 1;
+ if (last >= 1) {
+ float rgbs[3];
+ float rgbe[3];
+ float ops, ope;
+
+ ops = gr->vector.stops[0 ].opacity;
+ ope = gr->vector.stops[last].opacity;
+ sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs);
+ sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe);
+
+ /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */
+ cr = U_RGB(
+ 255 * ((opweight(rgbs[0], gv.rgb[0], ops) + opweight(rgbe[0], gv.rgb[0], ope)) / 2.0),
+ 255 * ((opweight(rgbs[1], gv.rgb[1], ops) + opweight(rgbe[1], gv.rgb[1], ope)) / 2.0),
+ 255 * ((opweight(rgbs[2], gv.rgb[2], ops) + opweight(rgbe[2], gv.rgb[2], ope)) / 2.0)
+ );
+ } else {
+ cr = U_RGB(0, 0, 0); // The default fill
+ }
+ return cr;
+}
+
+U_COLORREF PrintMetafile::weight_opacity(U_COLORREF c1)
+{
+ float opa = c1.Reserved / 255.0;
+ U_COLORREF result = U_RGB(
+ 255 * opweight((float)c1.Red / 255.0, gv.rgb[0], opa),
+ 255 * opweight((float)c1.Green / 255.0, gv.rgb[1], opa),
+ 255 * opweight((float)c1.Blue / 255.0, gv.rgb[2], opa)
+ );
+ return result;
+}
+
+/* t between 0 and 1, values outside that range use the nearest limit */
+U_COLORREF PrintMetafile::weight_colors(U_COLORREF c1, U_COLORREF c2, double t)
+{
+#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b))
+ U_COLORREF result;
+ t = ( t > 1.0 ? 1.0 : ( t < 0.0 ? 0.0 : t));
+ result.Red = clrweight(c1.Red, c2.Red, t);
+ result.Green = clrweight(c1.Green, c2.Green, t);
+ result.Blue = clrweight(c1.Blue, c2.Blue, t);
+ result.Reserved = clrweight(c1.Reserved, c2.Reserved, t);
+
+ // now handle the opacity, mix the RGB with background at the weighted opacity
+
+ if (result.Reserved != 255) {
+ result = weight_opacity(result);
+ }
+
+ return result;
+}
+
+// Extract hatchType, hatchColor from a name like
+// EMFhatch<hatchType>_<hatchColor>
+// Where the first one is a number and the second a color in hex.
+// hatchType and hatchColor have been set with defaults before this is called.
+//
+void PrintMetafile::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor)
+{
+ int val;
+ uint32_t hcolor = 0;
+ uint32_t bcolor = 0;
+
+ // name should be EMFhatch or WMFhatch but *MFhatch will be accepted
+ if (0 != strncmp(&name[1], "MFhatch", 7)) {
+ return; // not anything we can parse
+ }
+ name += 8; // EMFhatch already detected
+ val = 0;
+ while (*name && isdigit(*name)) {
+ val = 10 * val + *name - '0';
+ name++;
+ }
+ *hatchType = val;
+ if (*name != '_' || val > U_HS_DITHEREDBKCLR) { // wrong syntax, cannot classify
+ *hatchType = -1;
+ } else {
+ name++;
+ if (2 != sscanf(name, "%X_%X", &hcolor, &bcolor)) { // not a pattern with background
+ if (1 != sscanf(name, "%X", &hcolor)) {
+ *hatchType = -1; // not a pattern, cannot classify
+ }
+ *hatchColor = _gethexcolor(hcolor);
+ } else {
+ *hatchColor = _gethexcolor(hcolor);
+ *bkColor = _gethexcolor(bcolor);
+ usebk = true;
+ }
+ }
+ /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */
+ if (*hatchType > U_HS_SOLIDCLR) {
+ *hatchType = U_HS_SOLIDCLR;
+ }
+}
+
+//
+// Recurse down from a brush pattern, try to figure out what it is.
+// If an image is found set a pointer to the epixbuf, else set that to NULL
+// If a pattern is found with a name like [EW]MFhatch3_3F7FFF return hatchType=3, hatchColor=3F7FFF (as a uint32_t),
+// otherwise hatchType is set to -1 and hatchColor is not defined.
+//
+
+void PrintMetafile::brush_classify(SPObject *parent, int depth, Inkscape::Pixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor)
+{
+ if (depth == 0) {
+ *epixbuf = NULL;
+ *hatchType = -1;
+ *hatchColor = U_RGB(0, 0, 0);
+ *bkColor = U_RGB(255, 255, 255);
+ }
+ depth++;
+ // first look along the pattern chain, if there is one
+ if (SP_IS_PATTERN(parent)) {
+ for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if (SP_IS_IMAGE(pat_i)) {
+ *epixbuf = ((SPImage *)pat_i)->pixbuf;
+ return;
+ }
+ char temp[32]; // large enough
+ temp[31] = '\0';
+ strncpy(temp, pat_i->getAttribute("id"), 31); // Some names may be longer than [EW]MFhatch#_######
+ hatch_classify(temp, hatchType, hatchColor, bkColor);
+ if (*hatchType != -1) {
+ return;
+ }
+
+ // still looking? Look at this pattern's children, if there are any
+ SPObject *child = pat_i->firstChild();
+ while (child && !(*epixbuf) && (*hatchType == -1)) {
+ brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
+ child = child->getNext();
+ }
+ }
+ } else if (SP_IS_IMAGE(parent)) {
+ *epixbuf = ((SPImage *)parent)->pixbuf;
+ return;
+ } else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either.
+ SPObject *child = parent->firstChild();
+ while (child && !(*epixbuf) && (*hatchType == -1)) {
+ brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
+ child = child->getNext();
+ }
+ }
+}
+
+//swap R/B in 4 byte pixel
+void PrintMetafile::swapRBinRGBA(char *px, int pixels)
+{
+ char tmp;
+ for (int i = 0; i < pixels * 4; px += 4, i += 4) {
+ tmp = px[2];
+ px[2] = px[0];
+ px[0] = tmp;
+ }
+}
+
+int PrintMetafile::hold_gradient(void *gr, int mode)
+{
+ gv.mode = mode;
+ gv.grad = gr;
+ if (mode == DRAW_RADIAL_GRADIENT) {
+ SPRadialGradient *rg = (SPRadialGradient *) gr;
+ gv.r = rg->r.computed; // radius, but of what???
+ gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center
+ gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle
+ gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle
+ if (rg->gradientTransform_set) {
+ gv.p1 = gv.p1 * rg->gradientTransform;
+ gv.p2 = gv.p2 * rg->gradientTransform;
+ gv.p3 = gv.p3 * rg->gradientTransform;
+ }
+ } else if (mode == DRAW_LINEAR_GRADIENT) {
+ SPLinearGradient *lg = (SPLinearGradient *) gr;
+ gv.r = 0; // unused
+ gv.p1 = Geom::Point(lg->x1.computed, lg->y1.computed); // start
+ gv.p2 = Geom::Point(lg->x2.computed, lg->y2.computed); // end
+ gv.p3 = Geom::Point(0, 0); // unused
+ if (lg->gradientTransform_set) {
+ gv.p1 = gv.p1 * lg->gradientTransform;
+ gv.p2 = gv.p2 * lg->gradientTransform;
+ }
+ } else {
+ g_error("Fatal programming error, hold_gradient() in metafile-print.cpp called with invalid draw mode");
+ }
+ return 1;
+}
+
+/* convert from center ellipse to SVGEllipticalArc ellipse
+
+ From:
+ http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
+ A point (x,y) on the arc can be found by:
+
+ {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT}
+
+ where
+ {cx,cy} is the center of the ellipse
+ F is the rotation angle of the X axis of the ellipse from the true X axis
+ T is the rotation angle around the ellipse
+ {,,,} is the rotation matrix
+ rx,ry are the radii of the ellipse's axes
+
+ For SVG parameterization need two points.
+ Arbitrarily we can use T=0 and T=pi
+ Since the sweep is 180 the flags are always 0:
+
+ F is in RADIANS, but the SVGEllipticalArc needs degrees!
+
+*/
+Geom::PathVector PrintMetafile::center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F)
+{
+ using Geom::X;
+ using Geom::Y;
+ double x1, y1, x2, y2;
+ Geom::Path SVGep;
+
+ x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0);
+ y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0);
+ x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI);
+ y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI);
+
+ char text[256];
+ sprintf(text, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", x1, y1, rx, ry, F * 360. / (2.*M_PI), x2, y2, rx, ry, F * 360. / (2.*M_PI), x1, y1);
+ std::vector<Geom::Path> outres = Geom::parse_svg_path(text);
+ return outres;
+}
+
+
+/* rx2,ry2 must be larger than rx1,ry1!
+ angle is in RADIANS
+*/
+Geom::PathVector PrintMetafile::center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F)
+{
+ using Geom::X;
+ using Geom::Y;
+ double x11, y11, x12, y12;
+ double x21, y21, x22, y22;
+ double degrot = F * 360. / (2.*M_PI);
+
+ x11 = ctr[X] + cos(F) * rx1 * cos(0) + sin(-F) * ry1 * sin(0);
+ y11 = ctr[Y] + sin(F) * rx1 * cos(0) + cos(F) * ry1 * sin(0);
+ x12 = ctr[X] + cos(F) * rx1 * cos(M_PI) + sin(-F) * ry1 * sin(M_PI);
+ y12 = ctr[Y] + sin(F) * rx1 * cos(M_PI) + cos(F) * ry1 * sin(M_PI);
+
+ x21 = ctr[X] + cos(F) * rx2 * cos(0) + sin(-F) * ry2 * sin(0);
+ y21 = ctr[Y] + sin(F) * rx2 * cos(0) + cos(F) * ry2 * sin(0);
+ x22 = ctr[X] + cos(F) * rx2 * cos(M_PI) + sin(-F) * ry2 * sin(M_PI);
+ y22 = ctr[Y] + sin(F) * rx2 * cos(M_PI) + cos(F) * ry2 * sin(M_PI);
+
+ char text[512];
+ sprintf(text, " M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z",
+ x11, y11, rx1, ry1, degrot, x12, y12, rx1, ry1, degrot, x11, y11,
+ x21, y21, rx2, ry2, degrot, x22, y22, rx2, ry2, degrot, x21, y21);
+ std::vector<Geom::Path> outres = Geom::parse_svg_path(text);
+
+ return outres;
+}
+
+/* Elliptical hole in a large square extending from -50k to +50k */
+Geom::PathVector PrintMetafile::center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F)
+{
+ using Geom::X;
+ using Geom::Y;
+ double x1, y1, x2, y2;
+ Geom::Path SVGep;
+
+ x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0);
+ y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0);
+ x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI);
+ y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI);
+
+ char text[256];
+ sprintf(text, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z",
+ x1, y1, rx, ry, F * 360. / (2.*M_PI), x2, y2, rx, ry, F * 360. / (2.*M_PI), x1, y1);
+ std::vector<Geom::Path> outres = Geom::parse_svg_path(text);
+ return outres;
+}
+
+/* rectangular cutter.
+ctr "center" of rectangle (might not actually be in the center with respect to leading/trailing edges
+pos vector from center to leading edge
+neg vector from center to trailing edge
+width vector to side edge
+*/
+Geom::PathVector PrintMetafile::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width)
+{
+ std::vector<Geom::Path> outres;
+ Geom::Path cutter;
+ cutter.start(ctr + pos - width);
+ cutter.appendNew<Geom::LineSegment>(ctr + pos + width);
+ cutter.appendNew<Geom::LineSegment>(ctr + neg + width);
+ cutter.appendNew<Geom::LineSegment>(ctr + neg - width);
+ cutter.close();
+ outres.push_back(cutter);
+ return outres;
+}
+
+/* Convert from SPWindRule to livarot's FillRule
+ This is similar to what sp_selected_path_boolop() does
+*/
+FillRule PrintMetafile::SPWR_to_LVFR(SPWindRule wr)
+{
+ FillRule fr;
+ if (wr == SP_WIND_RULE_EVENODD) {
+ fr = fill_oddEven;
+ } else {
+ fr = fill_nonZero;
+ }
+ return fr;
+}
+
+} // namespace Internal
+} // namespace Extension
+} // namespace Inkscape
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/metafile-print.h b/src/extension/internal/metafile-print.h
new file mode 100644
index 000000000..a21f9de58
--- /dev/null
+++ b/src/extension/internal/metafile-print.h
@@ -0,0 +1,134 @@
+/** @file
+ * @brief Metafile printing - common functions
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2013 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_PRINT_H
+#define SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_PRINT_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <map>
+#include <stack>
+#include <glibmm/ustring.h>
+#include <libuemf/uemf.h>
+#include <2geom/affine.h>
+#include <2geom/pathvector.h>
+
+#include "extension/implementation/implementation.h"
+#include "splivarot.h"
+#include "display/canvas-bpath.h"
+
+class SPGradient;
+class SPObject;
+
+namespace Inkscape {
+class Pixbuf;
+
+namespace Extension {
+namespace Internal {
+
+enum MFDrawMode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT};
+
+struct FontfixParams {
+ double f1; //Vertical (rotating) offset factor (* font height)
+ double f2; //Vertical (nonrotating) offset factor (* font height)
+ double f3; //Horizontal (nonrotating) offset factor (* font height)
+ FontfixParams() : f1(0), f2(0), f3(0) {}
+};
+
+class PrintMetafile
+ : public Inkscape::Extension::Implementation::Implementation
+{
+public:
+ PrintMetafile() {}
+ ~PrintMetafile();
+
+ bool textToPath (Inkscape::Extension::Print * ext);
+ unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity);
+ unsigned int release(Inkscape::Extension::Print *module);
+
+protected:
+ struct GRADVALUES {
+ Geom::Point p1; // center or start
+ Geom::Point p2; // xhandle or end
+ Geom::Point p3; // yhandle or unused
+ double r; // radius or unused
+ void *grad; // to access the stops information
+ int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value
+ U_COLORREF bgc; // document background color, this is as good a place as any to keep it
+ float rgb[3]; // also background color, but as 0-1 float.
+ };
+
+ double _width;
+ double _height;
+ U_RECTL rc;
+
+ uint32_t htextalignment;
+ uint32_t hpolyfillmode; // used to minimize redundant records that set this
+ float htextcolor_rgb[3]; // used to minimize redundant records that set this
+
+ std::stack<Geom::Affine> m_tr_stack;
+ Geom::PathVector fill_pathv;
+ Geom::Affine fill_transform;
+ bool use_stroke;
+ bool use_fill;
+ bool simple_shape;
+ bool usebk;
+
+ GRADVALUES gv;
+
+ static bool _load_ppt_fontfix_data();
+ static void _lookup_ppt_fontfix(Glib::ustring const &fontname, FontfixParams &);
+ static U_COLORREF _gethexcolor(uint32_t color);
+ static uint32_t _translate_weight(unsigned inkweight);
+
+ U_COLORREF avg_stop_color(SPGradient *gr);
+ U_COLORREF weight_opacity(U_COLORREF c1);
+ U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t);
+
+ void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor);
+ void brush_classify(SPObject *parent, int depth, Inkscape::Pixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor);
+ static void swapRBinRGBA(char *px, int pixels);
+
+ int hold_gradient(void *gr, int mode);
+ static Geom::PathVector center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F);
+ static Geom::PathVector center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F);
+ static Geom::PathVector center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F);
+ static Geom::PathVector rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width);
+ static FillRule SPWR_to_LVFR(SPWindRule wr);
+
+ virtual int create_brush(SPStyle const *style, PU_COLORREF fcolor) = 0;
+ virtual void destroy_brush() = 0;
+ virtual int create_pen(SPStyle const *style, const Geom::Affine &transform) = 0;
+ virtual void destroy_pen() = 0;
+
+private:
+ typedef std::map<Glib::ustring, FontfixParams> FontfixMap;
+ static FontfixMap _ppt_fixable_fonts;
+ static bool _ppt_fontfix_read;
+};
+
+} // namespace Internal
+} // namespace Extension
+} // namespace Inkscape
+
+#endif
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/odf.cpp b/src/extension/internal/odf.cpp
index 8bb96920d..52fabcf3c 100644
--- a/src/extension/internal/odf.cpp
+++ b/src/extension/internal/odf.cpp
@@ -4,7 +4,7 @@
* This is an an entry in the extensions mechanism to begin to enable
* the inputting and outputting of OpenDocument Format (ODF) files from
* within Inkscape. Although the initial implementations will be very lossy
- * do to the differences in the models of SVG and ODF, they will hopefully
+ * due to the differences in the models of SVG and ODF, they will hopefully
* improve greatly with time. People should consider this to be a framework
* that can be continously upgraded for ever improving fidelity. Potential
* developers should especially look in preprocess() and writeTree() to see how
@@ -15,8 +15,10 @@
* Authors:
* Bob Jamison
* Abhishek Sharma
+ * Kris De Gussem
*
* Copyright (C) 2006, 2007 Bob Jamison
+ * Copyright (C) 2013 Kris De Gussem
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -45,7 +47,7 @@
#include <stdio.h>
#include <time.h>
#include <vector>
-
+#include <math.h>
//# Inkscape includes
#include "clear-n_.h"
@@ -73,37 +75,29 @@
#include "sp-flowtext.h"
#include "svg/svg.h"
#include "text-editing.h"
+#include "util/units.h"
+#include "uri.h"
-//# DOM-specific includes
-#include "dom/dom.h"
-#include "dom/util/ziptool.h"
-#include "dom/io/domstream.h"
-#include "dom/io/bufferstream.h"
-#include "dom/io/stringstream.h"
-
-
+#include "inkscape-version.h"
#include "document.h"
-
#include "extension/extension.h"
-
-
+#include "io/inkscapestream.h"
+#include "io/bufferstream.h"
+#include <util/ziptool.h>
+#include <iomanip>
namespace Inkscape
{
namespace Extension
{
namespace Internal
{
-
-
-
//# Shorthand notation
-typedef org::w3c::dom::DOMString DOMString;
-typedef org::w3c::dom::XMLCh XMLCh;
-typedef org::w3c::dom::io::OutputStreamWriter OutputStreamWriter;
-typedef org::w3c::dom::io::BufferOutputStream BufferOutputStream;
-typedef org::w3c::dom::io::StringOutputStream StringOutputStream;
+typedef Inkscape::IO::BufferOutputStream BufferOutputStream;
+typedef Inkscape::IO::OutputStreamWriter OutputStreamWriter;
+typedef Inkscape::IO::StringOutputStream StringOutputStream;
+
//########################################################################
//# C L A S S SingularValueDecomposition
@@ -211,9 +205,11 @@ public:
SVDMatrix transpose()
{
SVDMatrix result(cols, rows);
- for (unsigned int i=0 ; i<rows ; i++)
- for (unsigned int j=0 ; j<cols ; j++)
+ for (unsigned int i=0 ; i<rows ; i++){
+ for (unsigned int j=0 ; j<cols ; j++){
result(j, i) = d[i*cols + j];
+ }
+ }
return result;
}
@@ -239,9 +235,11 @@ private:
rows = other.rows;
cols = other.cols;
size = other.size;
+ badval = other.badval;
d = new double[size];
- for (unsigned int i=0 ; i<size ; i++)
+ for (unsigned int i=0 ; i<size ; i++){
d[i] = other.d[i];
+ }
}
double badval;
@@ -289,11 +287,13 @@ public:
@return Structure to access U, S and V.
*/
- SingularValueDecomposition (const SVDMatrix &mat)
+ SingularValueDecomposition (const SVDMatrix &mat) :
+ A (mat),
+ U (),
+ s (NULL),
+ s_size (0),
+ V ()
{
- A = mat;
- s = NULL;
- s_size = 0;
calculate();
}
@@ -801,7 +801,6 @@ void SingularValueDecomposition::calculate()
}
-
/**
* Return the left singular vectors
* @return U
@@ -899,7 +898,6 @@ static Glib::ustring getAttribute( Inkscape::XML::Node *node, char const *attrNa
}
-
/**
* Get the extension suffix from the end of a file name
*/
@@ -919,7 +917,6 @@ static Glib::ustring getExtension(const Glib::ustring &fname)
return ext;
}
-
static Glib::ustring formatTransform(Geom::Affine &tf)
{
Glib::ustring str;
@@ -935,9 +932,6 @@ static Glib::ustring formatTransform(Geom::Affine &tf)
}
-
-
-
/**
* Get the general transform from SVG pixels to
* ODF cm
@@ -947,7 +941,7 @@ static Geom::Affine getODFTransform(const SPItem *item)
//### Get SVG-to-ODF transform
Geom::Affine tf (item->i2dt_affine());
//Flip Y into document coordinates
- double doc_height = SP_ACTIVE_DOCUMENT->getHeight();
+ double doc_height = SP_ACTIVE_DOCUMENT->getHeight().value("px");
Geom::Affine doc2dt_tf = Geom::Affine(Geom::Scale(1.0, -1.0)); /// @fixme hardcoded desktop transform
doc2dt_tf = doc2dt_tf * Geom::Affine(Geom::Translate(0, doc_height));
tf = tf * doc2dt_tf;
@@ -956,8 +950,6 @@ static Geom::Affine getODFTransform(const SPItem *item)
}
-
-
/**
* Get the bounding box of an item, as mapped onto
* an ODF document, in cm.
@@ -965,7 +957,7 @@ static Geom::Affine getODFTransform(const SPItem *item)
static Geom::OptRect getODFBoundingBox(const SPItem *item)
{
// TODO: geometric or visual?
- Geom::OptRect bbox = ((SPItem *)item)->documentVisualBounds();
+ Geom::OptRect bbox = item->documentVisualBounds();
if (bbox) {
*bbox *= Geom::Affine(Geom::Scale(pxToCm));
}
@@ -973,7 +965,6 @@ static Geom::OptRect getODFBoundingBox(const SPItem *item)
}
-
/**
* Get the transform for an item, correcting for
* handedness reversal
@@ -987,7 +978,6 @@ static Geom::Affine getODFItemTransform(const SPItem *item)
}
-
/**
* Get some fun facts from the transform
*/
@@ -1011,16 +1001,9 @@ static void analyzeTransform(Geom::Affine &tf,
double s1 = svd.getS(1);
xscale = s0;
yscale = s1;
- //g_message("## s0:%.3f s1:%.3f", s0, s1);
- //g_message("## u:%.3f %.3f %.3f %.3f", U(0,0), U(0,1), U(1,0), U(1,1));
- //g_message("## v:%.3f %.3f %.3f %.3f", V(0,0), V(0,1), V(1,0), V(1,1));
- //g_message("## vt:%.3f %.3f %.3f %.3f", Vt(0,0), Vt(0,1), Vt(1,0), Vt(1,1));
- //g_message("## uvt:%.3f %.3f %.3f %.3f", UVt(0,0), UVt(0,1), UVt(1,0), UVt(1,1));
rotate = UVt(0,0);
}
-
-
static void gatherText(Inkscape::XML::Node *node, Glib::ustring &buf)
{
if (node->type() == Inkscape::XML::TEXT_NODE)
@@ -1038,15 +1021,14 @@ static void gatherText(Inkscape::XML::Node *node, Glib::ustring &buf)
}
+
/**
* FIRST PASS.
* Method descends into the repr tree, converting image, style, and gradient info
* into forms compatible in ODF.
*/
-void
-OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
+void OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
{
-
Glib::ustring nodeName = node->name();
Glib::ustring id = getAttribute(node, "id");
@@ -1074,18 +1056,16 @@ OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
//Now consider items.
SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
if (!reprobj)
+ {
return;
+ }
if (!SP_IS_ITEM(reprobj))
- {
+ {
return;
- }
- SPItem *item = SP_ITEM(reprobj);
- //### Get SVG-to-ODF transform
- Geom::Affine tf = getODFTransform(item);
+ }
if (nodeName == "image" || nodeName == "svg:image")
{
- //g_message("image");
Glib::ustring href = getAttribute(node, "xlink:href");
if (href.size() > 0)
{
@@ -1102,12 +1082,9 @@ OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
imageTable[oldName] = newName;
Glib::ustring comment = "old name was: ";
comment.append(oldName);
- URI oldUri(oldName);
- //g_message("oldpath:%s", oldUri.getNativePath().c_str());
+ Inkscape::URI oldUri(oldName.c_str());
//# if relative to the documentURI, get proper path
- URI resUri = documentUri.resolve(oldUri);
- DOMString pathName = resUri.getNativePath();
- //g_message("native path:%s", pathName.c_str());
+ std::string pathName = documentUri.getFullPath(oldUri.getFullPath(""));
ZipEntry *ze = zf.addFile(pathName, comment);
if (ze)
{
@@ -1127,7 +1104,6 @@ OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node)
}
-
/**
* Writes the manifest. Currently it only changes according to the
* file names of images packed into the zip file.
@@ -1140,25 +1116,25 @@ bool OdfOutput::writeManifest(ZipFile &zf)
time_t tim;
time(&tim);
- outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- outs.printf("<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<!--\n");
- outs.printf("*************************************************************************\n");
- outs.printf(" file: manifest.xml\n");
- outs.printf(" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
- outs.printf(" http://www.inkscape.org\n");
- outs.printf("*************************************************************************\n");
- outs.printf("-->\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
- outs.printf(" <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.graphics\" manifest:full-path=\"/\"/>\n");
- outs.printf(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n");
- outs.printf(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"styles.xml\"/>\n");
- outs.printf(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n");
- outs.printf(" <!--List our images here-->\n");
+ outs.writeString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ outs.writeString("<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n");
+ outs.writeString("\n");
+ outs.writeString("\n");
+ outs.writeString("<!--\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString(" file: manifest.xml\n");
+ outs.printf (" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
+ outs.writeString(" http://www.inkscape.org\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString("-->\n");
+ outs.writeString("\n");
+ outs.writeString("\n");
+ outs.writeString("<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
+ outs.writeString(" <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.graphics\" manifest:full-path=\"/\"/>\n");
+ outs.writeString(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n");
+ outs.writeString(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"styles.xml\"/>\n");
+ outs.writeString(" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n");
+ outs.writeString(" <!--List our images here-->\n");
std::map<Glib::ustring, Glib::ustring>::iterator iter;
for (iter = imageTable.begin() ; iter!=imageTable.end() ; ++iter)
{
@@ -1176,7 +1152,7 @@ bool OdfOutput::writeManifest(ZipFile &zf)
else if (ext == ".jpg")
outs.printf("image/jpeg");
outs.printf("\" manifest:full-path=\"");
- outs.printf(newName.c_str());
+ outs.writeString(newName.c_str());
outs.printf("\"/>\n");
}
outs.printf("</manifest:manifest>\n");
@@ -1204,65 +1180,79 @@ bool OdfOutput::writeMeta(ZipFile &zf)
time(&tim);
std::map<Glib::ustring, Glib::ustring>::iterator iter;
- Glib::ustring creator = "unknown";
+ Glib::ustring InkscapeVersion = Glib::ustring("Inkscape.org - ") + Inkscape::version_string;
+ Glib::ustring creator = InkscapeVersion;
iter = metadata.find("dc:creator");
if (iter != metadata.end())
+ {
creator = iter->second;
- Glib::ustring date = "";
+ }
+
+ Glib::ustring date;
+ Glib::ustring moddate;
+ char buf [80];
+ time_t rawtime;
+ struct tm * timeinfo;
+ time (&rawtime);
+ timeinfo = localtime (&rawtime);
+ strftime (buf,80,"%Y-%m-%d %H:%M:%S",timeinfo);
+ moddate = Glib::ustring(buf);
+
iter = metadata.find("dc:date");
if (iter != metadata.end())
+ {
date = iter->second;
+ }
+ else
+ {
+ date = moddate;
+ }
- outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<!--\n");
- outs.printf("*************************************************************************\n");
- outs.printf(" file: meta.xml\n");
- outs.printf(" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
- outs.printf(" http://www.inkscape.org\n");
- outs.printf("*************************************************************************\n");
- outs.printf("-->\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<office:document-meta\n");
- outs.printf("xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
- outs.printf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
- outs.printf("xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
- outs.printf("xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
- outs.printf("xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
- outs.printf("xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
- outs.printf("xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
- outs.printf("xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
- outs.printf("office:version=\"1.0\">\n");
- outs.printf("<office:meta>\n");
- outs.printf(" <meta:generator>Inkscape.org - 0.45</meta:generator>\n");
- outs.printf(" <meta:initial-creator>%#s</meta:initial-creator>\n",
- creator.c_str());
- outs.printf(" <meta:creation-date>%#s</meta:creation-date>\n", date.c_str());
+ outs.writeString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ outs.writeString("\n");
+ outs.writeString("<!--\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString(" file: meta.xml\n");
+ outs.printf (" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
+ outs.writeString(" http://www.inkscape.org\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString("-->\n");
+ outs.writeString("\n");
+ outs.writeString("<office:document-meta\n");
+ outs.writeString("xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
+ outs.writeString("xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
+ outs.writeString("xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
+ outs.writeString("xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
+ outs.writeString("xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
+ outs.writeString("xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
+ outs.writeString("xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
+ outs.writeString("xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
+ outs.writeString("office:version=\"1.0\">\n");
+ outs.writeString("<office:meta>\n");
+ Glib::ustring tmp = Glib::ustring::compose(" <meta:generator>%1</meta:generator>\n", InkscapeVersion);
+ tmp += Glib::ustring::compose(" <meta:initial-creator>%1</meta:initial-creator>\n", creator);
+ tmp += Glib::ustring::compose(" <meta:creation-date>%1</meta:creation-date>\n", date);
+ tmp += Glib::ustring::compose(" <dc:date>%1</dc:date>\n", moddate);
+ outs.writeUString(tmp);
for (iter = metadata.begin() ; iter != metadata.end() ; ++iter)
- {
+ {
Glib::ustring name = iter->first;
Glib::ustring value = iter->second;
- if (name.size() > 0 && value.size()>0)
- {
- outs.printf(" <%#s>%#s</%#s>\n",
- name.c_str(), value.c_str(), name.c_str());
- }
+ if (!name.empty() && !value.empty())
+ {
+ tmp = Glib::ustring::compose(" <%1>%2</%3>\n", name, value, name);
+ outs.writeUString(tmp);
}
- outs.printf(" <meta:editing-cycles>2</meta:editing-cycles>\n");
- outs.printf(" <meta:editing-duration>PT56S</meta:editing-duration>\n");
- outs.printf(" <meta:user-defined meta:name=\"Info 1\"/>\n");
- outs.printf(" <meta:user-defined meta:name=\"Info 2\"/>\n");
- outs.printf(" <meta:user-defined meta:name=\"Info 3\"/>\n");
- outs.printf(" <meta:user-defined meta:name=\"Info 4\"/>\n");
- outs.printf(" <meta:document-statistic meta:object-count=\"2\"/>\n");
- outs.printf("</office:meta>\n");
- outs.printf("</office:document-meta>\n");
- outs.printf("\n");
- outs.printf("\n");
-
-
+ }
+ // outs.writeString(" <meta:editing-cycles>2</meta:editing-cycles>\n");
+ // outs.writeString(" <meta:editing-duration>PT56S</meta:editing-duration>\n");
+ // outs.writeString(" <meta:user-defined meta:name=\"Info 1\"/>\n");
+ // outs.writeString(" <meta:user-defined meta:name=\"Info 2\"/>\n");
+ // outs.writeString(" <meta:user-defined meta:name=\"Info 3\"/>\n");
+ // outs.writeString(" <meta:user-defined meta:name=\"Info 4\"/>\n");
+ // outs.writeString(" <meta:document-statistic meta:object-count=\"2\"/>\n");
+ outs.writeString("</office:meta>\n");
+ outs.writeString("</office:document-meta>\n");
outs.close();
//Make our entry
@@ -1274,208 +1264,6 @@ bool OdfOutput::writeMeta(ZipFile &zf)
}
-
-
-/**
- * This is called just before writeTree(), since it will write style and
- * gradient information above the <draw> tag in the content.xml file
- */
-bool OdfOutput::writeStyle(ZipFile &zf)
-{
- BufferOutputStream bouts;
- OutputStreamWriter outs(bouts);
-
- /*
- ==========================================================
- Dump our style table. Styles should have a general layout
- something like the following. Look in:
- http://books.evc-cit.info/odbook/ch06.html#draw-style-file-section
- for style and gradient information.
- <style:style style:name="gr13"
- style:family="graphic" style:parent-style-name="standard">
- <style:graphic-properties draw:stroke="solid"
- svg:stroke-width="0.1cm"
- svg:stroke-color="#ff0000"
- draw:fill="solid" draw:fill-color="#e6e6ff"/>
- </style:style>
- ==========================================================
- */
- outs.printf("<!-- ####### Styles from Inkscape document ####### -->\n");
- std::vector<StyleInfo>::iterator iter;
- for (iter = styleTable.begin() ; iter != styleTable.end() ; ++iter)
- {
- outs.printf("<style:style style:name=\"%s\"", iter->name.c_str());
- StyleInfo s(*iter);
- outs.printf(" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
- outs.printf(" <style:graphic-properties");
- outs.printf(" draw:fill=\"%s\" ", s.fill.c_str());
- if (s.fill != "none")
- {
- outs.printf(" draw:fill-color=\"%s\" ", s.fillColor.c_str());
- outs.printf(" draw:fill-opacity=\"%s\" ", s.fillOpacity.c_str());
- }
- outs.printf(" draw:stroke=\"%s\" ", s.stroke.c_str());
- if (s.stroke != "none")
- {
- outs.printf(" svg:stroke-width=\"%s\" ", s.strokeWidth.c_str());
- outs.printf(" svg:stroke-color=\"%s\" ", s.strokeColor.c_str());
- outs.printf(" svg:stroke-opacity=\"%s\" ", s.strokeOpacity.c_str());
- }
- outs.printf("/>\n");
- outs.printf("</style:style>\n");
- }
-
- //## Dump our gradient table
- int gradientCount = 0;
- outs.printf("\n");
- outs.printf("<!-- ####### Gradients from Inkscape document ####### -->\n");
- std::vector<GradientInfo>::iterator giter;
- for (giter = gradientTable.begin() ; giter != gradientTable.end() ; ++giter)
- {
- GradientInfo gi(*giter);
- if (gi.style == "linear")
- {
- /*
- ===================================================================
- LINEAR gradient. We need something that looks like this:
- <draw:gradient draw:name="Gradient_20_7"
- draw:display-name="Gradient 7"
- draw:style="linear"
- draw:start-color="#008080" draw:end-color="#993366"
- draw:start-intensity="100%" draw:end-intensity="100%"
- draw:angle="150" draw:border="0%"/>
- ===================================================================
- */
- if (gi.stops.size() < 2)
- {
- g_warning("Need at least 2 tops for a linear gradient");
- continue;
- }
- outs.printf("<svg:linearGradient ");
- outs.printf("id=\"%#s_g\" ", gi.name.c_str());
- outs.printf("draw:name=\"%#s_g\"\n", gi.name.c_str());
- outs.printf(" draw:display-name=\"imported linear %u\"\n",
- gradientCount);
- outs.printf(" svg:x1=\"%05.3fcm\" svg:y1=\"%05.3fcm\"\n",
- gi.x1, gi.y1);
- outs.printf(" svg:x2=\"%05.3fcm\" svg:y2=\"%05.3fcm\"\n",
- gi.x2, gi.y2);
- outs.printf(" svg:gradientUnits=\"objectBoundingBox\">\n");
- outs.printf(" <svg:stop\n");
- outs.printf(" svg:stop-color=\"#%06lx\"\n",
- gi.stops[0].rgb);
- outs.printf(" svg:stop-opacity=\"%f%%\"\n",
- gi.stops[0].opacity * 100.0);
- outs.printf(" svg:offset=\"0\"/>\n");
- outs.printf(" <svg:stop\n");
- outs.printf(" svg:stop-color=\"#%06lx\"\n",
- gi.stops[1].rgb);
- outs.printf(" svg:stop-opacity=\"%f%%\"\n",
- gi.stops[1].opacity * 100.0);
- outs.printf(" svg:offset=\"1\"/>\n");
- outs.printf("</svg:linearGradient>\n");
- }
- else if (gi.style == "radial")
- {
- /*
- ===================================================================
- RADIAL gradient. We need something that looks like this:
- <!-- radial gradient, light gray to white, centered, 0% border -->
- <draw:gradient draw:name="radial_20_borderless"
- draw:display-name="radial borderless"
- draw:style="radial"
- draw:cx="50%" draw:cy="50%"
- draw:start-color="#999999" draw:end-color="#ffffff"
- draw:border="0%"/>
- ===================================================================
- */
- if (gi.stops.size() < 2)
- {
- g_warning("Need at least 2 tops for a radial gradient");
- continue;
- }
- outs.printf("<svg:radialGradient ");
- outs.printf("id=\"%#s_g\" ", gi.name.c_str());
- outs.printf("draw:name=\"%#s_g\"\n", gi.name.c_str());
- outs.printf(" draw:display-name=\"imported radial %d\"\n",
- gradientCount);
- outs.printf(" svg:cx=\"%05.3f\" svg:cy=\"%05.3f\"\n",
- gi.cx, gi.cy);
- outs.printf(" svg:fx=\"%05.3f\" svg:fy=\"%05.3f\"\n",
- gi.fx, gi.fy);
- outs.printf(" svg:r=\"%05.3f\"\n",
- gi.r);
- outs.printf(" svg:gradientUnits=\"objectBoundingBox\">\n");
- outs.printf(" <svg:stop\n");
- outs.printf(" svg:stop-color=\"#%06lx\"\n",
- gi.stops[0].rgb);
- outs.printf(" svg:stop-opacity=\"%f%%\"\n",
- gi.stops[0].opacity * 100.0);
- outs.printf(" svg:offset=\"0\"/>\n");
- outs.printf(" <svg:stop\n");
- outs.printf(" svg:stop-color=\"#%06lx\"\n",
- gi.stops[1].rgb);
- outs.printf(" svg:stop-opacity=\"%f%%\"\n",
- gi.stops[1].opacity * 100.0);
- outs.printf(" svg:offset=\"1\"/>\n");
- outs.printf("</svg:radialGradient>\n");
- }
- else
- {
- g_warning("unsupported gradient style '%s'", gi.style.c_str());
- }
- outs.printf("<style:style style:name=\"%#s\" style:family=\"graphic\" ",
- gi.name.c_str());
- outs.printf("style:parent-style-name=\"standard\">\n");
- outs.printf(" <style:graphic-properties draw:fill=\"gradient\" ");
- outs.printf("draw:fill-gradient-name=\"%#s_g\"\n",
- gi.name.c_str());
- outs.printf(" draw:textarea-horizontal-align=\"center\" ");
- outs.printf("draw:textarea-vertical-align=\"middle\"/>\n");
- outs.printf("</style:style>\n\n");
-
- gradientCount++;
- }
-
- outs.printf("\n");
- outs.printf("</office:automatic-styles>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<office:master-styles>\n");
- outs.printf("<draw:layer-set>\n");
- outs.printf(" <draw:layer draw:name=\"layout\"/>\n");
- outs.printf(" <draw:layer draw:name=\"background\"/>\n");
- outs.printf(" <draw:layer draw:name=\"backgroundobjects\"/>\n");
- outs.printf(" <draw:layer draw:name=\"controls\"/>\n");
- outs.printf(" <draw:layer draw:name=\"measurelines\"/>\n");
- outs.printf("</draw:layer-set>\n");
- outs.printf("\n");
- outs.printf("<style:master-page style:name=\"Default\"\n");
- outs.printf(" style:page-master-name=\"PM1\" draw:style-name=\"dp1\"/>\n");
- outs.printf("</office:master-styles>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("</office:document-styles>\n");
- outs.printf("\n");
- outs.printf("<!--\n");
- outs.printf("*************************************************************************\n");
- outs.printf(" E N D O F F I L E\n");
- outs.printf(" Have a nice day - ishmal\n");
- outs.printf("*************************************************************************\n");
- outs.printf("-->\n");
- outs.printf("\n");
-
- //Make our entry
- ZipEntry *ze = zf.newEntry("styles.xml", "ODF style file");
- ze->setUncompressedData(bouts.getBuffer());
- ze->finish();
-
- return true;
-}
-
-
-
/**
* Writes an SVG path as an ODF <draw:path> and returns the number of points written
*/
@@ -1533,24 +1321,30 @@ writePath(Writer &outs, Geom::PathVector const &pathv,
return nrPoints;
}
-
-
-bool OdfOutput::processStyle(Writer &outs, SPItem *item,
- const Glib::ustring &id)
+bool OdfOutput::processStyle(SPItem *item, const Glib::ustring &id, const Glib::ustring &gradientNameFill, const Glib::ustring &gradientNameStroke, Glib::ustring& output)
{
+ output.clear();
+ if (!item)
+ {
+ return false;
+ }
+
SPStyle *style = item->style;
-
+ if (!style)
+ {
+ return false;
+ }
+
StyleInfo si;
- //## FILL
+ // FILL
if (style->fill.isColor())
- {
+ {
guint32 fillCol = style->fill.value.color.toRGBA32( 0 );
char buf[16];
int r = (fillCol >> 24) & 0xff;
int g = (fillCol >> 16) & 0xff;
int b = (fillCol >> 8) & 0xff;
- //g_message("## %s %lx", id.c_str(), (unsigned int)fillCol);
snprintf(buf, 15, "#%02x%02x%02x", r, g, b);
si.fillColor = buf;
si.fill = "solid";
@@ -1558,11 +1352,19 @@ bool OdfOutput::processStyle(Writer &outs, SPItem *item,
(SP_SCALE24_TO_FLOAT(style->fill_opacity.value));
snprintf(buf, 15, "%.3f%%", opacityPercent);
si.fillOpacity = buf;
+ }
+ else if (style->fill.isPaintserver())
+ {
+ SPGradient *gradient = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));
+ if (gradient)
+ {
+ si.fill = "gradient";
}
+ }
- //## STROKE
+ // STROKE
if (style->stroke.isColor())
- {
+ {
guint32 strokeCol = style->stroke.value.color.toRGBA32( 0 );
char buf[16];
int r = (strokeCol >> 24) & 0xff;
@@ -1577,157 +1379,170 @@ bool OdfOutput::processStyle(Writer &outs, SPItem *item,
(SP_SCALE24_TO_FLOAT(style->stroke_opacity.value));
snprintf(buf, 15, "%.3f%%", opacityPercent);
si.strokeOpacity = buf;
+ }
+ else if (style->stroke.isPaintserver())
+ {
+ SPGradient *gradient = SP_GRADIENT(SP_STYLE_STROKE_SERVER(style));
+ if (gradient)
+ {
+ si.stroke = "gradient";
}
+ }
//Look for existing identical style;
bool styleMatch = false;
std::vector<StyleInfo>::iterator iter;
for (iter=styleTable.begin() ; iter!=styleTable.end() ; ++iter)
- {
+ {
if (si.equals(*iter))
- {
+ {
//map to existing styleTable entry
Glib::ustring styleName = iter->name;
- //g_message("found duplicate style:%s", styleName.c_str());
styleLookupTable[id] = styleName;
styleMatch = true;
break;
- }
}
+ }
- //## Dont need a new style
+ // Dont need a new style
if (styleMatch)
+ {
return false;
+ }
- char buf[16];
- snprintf(buf, 15, "style%d", (int)styleTable.size());
- Glib::ustring styleName = buf;
+ Glib::ustring styleName = Glib::ustring::compose("style%1", styleTable.size());
si.name = styleName;
styleTable.push_back(si);
styleLookupTable[id] = styleName;
- outs.printf("<style:style style:name=\"%s\"", si.name.c_str());
- outs.printf(" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
- outs.printf(" <style:graphic-properties");
- outs.printf(" draw:fill=\"%s\" ", si.fill.c_str());
- if (si.fill != "none")
+ output = Glib::ustring::compose ("<style:style style:name=\"%1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n", si.name);
+ output += "<style:graphic-properties";
+ if (si.fill == "gradient")
+ {
+ output += Glib::ustring::compose (" draw:fill=\"gradient\" draw:fill-gradient-name=\"%1\"", gradientNameFill);
+ }
+ else
+ {
+ output += Glib::ustring(" draw:fill=\"") + si.fill + "\"";
+ if(si.fill != "none")
{
- outs.printf(" draw:fill-color=\"%s\" ", si.fillColor.c_str());
- outs.printf(" draw:fill-opacity=\"%s\" ", si.fillOpacity.c_str());
+ output += Glib::ustring::compose(" draw:fill-color=\"%1\"", si.fillColor);
}
- outs.printf(" draw:stroke=\"%s\" ", si.stroke.c_str());
- if (si.stroke != "none")
+ }
+ if (si.stroke == "gradient")
+ {
+ //does not seem to be supported by Open Office.org
+ output += Glib::ustring::compose (" draw:stroke=\"gradient\" draw:stroke-gradient-name=\"%1\"", gradientNameStroke);
+ }
+ else
+ {
+ output += Glib::ustring(" draw:stroke=\"") + si.stroke + "\"";
+ if (si.stroke != "none")
{
- outs.printf(" svg:stroke-width=\"%s\" ", si.strokeWidth.c_str());
- outs.printf(" svg:stroke-color=\"%s\" ", si.strokeColor.c_str());
- outs.printf(" svg:stroke-opacity=\"%s\" ", si.strokeOpacity.c_str());
+ output += Glib::ustring::compose (" svg:stroke-width=\"%1\" svg:stroke-color=\"%2\" ", si.strokeWidth, si.strokeColor);
}
- outs.printf("/>\n");
- outs.printf("</style:style>\n");
+ }
+ output += "/>\n</style:style>\n";
return true;
}
-
-
-
-bool OdfOutput::processGradient(Writer &outs, SPItem *item,
- const Glib::ustring &id, Geom::Affine &/*tf*/)
+bool OdfOutput::processGradient(SPItem *item,
+ const Glib::ustring &id, Geom::Affine &/*tf*/,
+ Glib::ustring& gradientName, Glib::ustring& output, bool checkFillGradient)
{
+ output.clear();
if (!item)
+ {
return false;
+ }
SPStyle *style = item->style;
-
if (!style)
+ {
return false;
+ }
- if (!style->fill.isPaintserver())
- return false;
-
- //## Gradient. Look in writeStyle() below to see what info
- // we need to read into GradientInfo.
- if (!SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)))
+ if ((checkFillGradient? (!style->fill.isPaintserver()) : (!style->stroke.isPaintserver())))
+ {
return false;
+ }
- SPGradient *gradient = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));
+ //## Gradient
+ SPGradient *gradient = SP_GRADIENT((checkFillGradient?(SP_STYLE_FILL_SERVER(style)) :(SP_STYLE_STROKE_SERVER(style))));
+ if (gradient == NULL)
+ {
+ return false;
+ }
GradientInfo gi;
-
SPGradient *grvec = gradient->getVector(FALSE);
- for (SPStop *stop = grvec->getFirstStop() ;
+ for (SPStop *stop = grvec->getFirstStop();
stop ; stop = stop->getNextStop())
- {
- unsigned long rgba = sp_stop_get_rgba32(stop);
+ {
+ unsigned long rgba = stop->get_rgba32();
unsigned long rgb = (rgba >> 8) & 0xffffff;
- double opacity = ((double)(rgba & 0xff)) / 256.0;
+ double opacity = (static_cast<double>(rgba & 0xff)) / 256.0;
GradientStop gs(rgb, opacity);
gi.stops.push_back(gs);
- }
+ }
+ Glib::ustring gradientName2;
if (SP_IS_LINEARGRADIENT(gradient))
- {
+ {
gi.style = "linear";
SPLinearGradient *linGrad = SP_LINEARGRADIENT(gradient);
- /*
- Geom::Point p1(linGrad->x1.value, linGrad->y1.value);
- p1 = p1 * tf;
- gi.x1 = p1[Geom::X];
- gi.y1 = p1[Geom::Y];
- Geom::Point p2(linGrad->x2.value, linGrad->y2.value);
- p2 = p2 * tf;
- gi.x2 = p2[Geom::X];
- gi.y2 = p2[Geom::Y];
- */
gi.x1 = linGrad->x1.value;
gi.y1 = linGrad->y1.value;
gi.x2 = linGrad->x2.value;
gi.y2 = linGrad->y2.value;
- }
+ gradientName2 = Glib::ustring::compose("ImportedLinearGradient%1", gradientTable.size());
+ }
else if (SP_IS_RADIALGRADIENT(gradient))
- {
+ {
gi.style = "radial";
SPRadialGradient *radGrad = SP_RADIALGRADIENT(gradient);
- gi.cx = radGrad->cx.computed * 100.0;//ODG cx is percentages
- gi.cy = radGrad->cy.computed * 100.0;
- }
+ Geom::OptRect bbox = item->documentVisualBounds();
+ gi.cx = (radGrad->cx.value-bbox->left())/bbox->width();
+ gi.cy = (radGrad->cy.value-bbox->top())/bbox->height();
+ gradientName2 = Glib::ustring::compose("ImportedRadialGradient%1", gradientTable.size());
+ }
else
- {
+ {
g_warning("not a supported gradient type");
return false;
- }
+ }
//Look for existing identical style;
bool gradientMatch = false;
std::vector<GradientInfo>::iterator iter;
for (iter=gradientTable.begin() ; iter!=gradientTable.end() ; ++iter)
- {
+ {
if (gi.equals(*iter))
- {
+ {
//map to existing gradientTable entry
- Glib::ustring gradientName = iter->name;
- //g_message("found duplicate style:%s", gradientName.c_str());
+ gradientName = iter->name;
gradientLookupTable[id] = gradientName;
gradientMatch = true;
break;
- }
}
+ }
if (gradientMatch)
+ {
return true;
+ }
- //## No match, let us write a new entry
- char buf[16];
- snprintf(buf, 15, "gradient%d", (int)gradientTable.size());
- Glib::ustring gradientName = buf;
+ // No match, let us write a new entry
+ gradientName = gradientName2;
gi.name = gradientName;
gradientTable.push_back(gi);
gradientLookupTable[id] = gradientName;
- int gradientCount = gradientTable.size();
-
+ // int gradientCount = gradientTable.size();
+ char buf[128];
if (gi.style == "linear")
- {
+ {
/*
===================================================================
LINEAR gradient. We need something that looks like this:
@@ -1740,36 +1555,25 @@ bool OdfOutput::processGradient(Writer &outs, SPItem *item,
===================================================================
*/
if (gi.stops.size() < 2)
- {
+ {
g_warning("Need at least 2 stops for a linear gradient");
- return false;;
- }
- outs.printf("<svg:linearGradient ");
- outs.printf("id=\"%#s_g\" ", gi.name.c_str());
- outs.printf("draw:name=\"%#s_g\"\n", gi.name.c_str());
- outs.printf(" draw:display-name=\"imported linear %d\"\n",
- gradientCount);
- outs.printf(" svg:gradientUnits=\"objectBoundingBox\"\n");
- outs.printf(" svg:x1=\"%05.3fcm\" svg:y1=\"%05.3fcm\"\n",
- gi.x1 * pxToCm, gi.y1 * pxToCm);
- outs.printf(" svg:x2=\"%05.3fcm\" svg:y2=\"%05.3fcm\">\n",
- gi.x2 * pxToCm, gi.y2 * pxToCm);
- outs.printf(" <svg:stop\n");
- outs.printf(" svg:stop-color=\"#%06lx\"\n",
- gi.stops[0].rgb);
- outs.printf(" svg:stop-opacity=\"%f%%\"\n",
- gi.stops[0].opacity * 100.0);
- outs.printf(" svg:offset=\"0\"/>\n");
- outs.printf(" <svg:stop\n");
- outs.printf(" svg:stop-color=\"#%06lx\"\n",
- gi.stops[1].rgb);
- outs.printf(" svg:stop-opacity=\"%f%%\"\n",
- gi.stops[1].opacity * 100.0);
- outs.printf(" svg:offset=\"1\"/>\n");
- outs.printf("</svg:linearGradient>\n");
+ return false;
}
+ output += Glib::ustring::compose("<draw:gradient draw:name=\"%1\"", gi.name);
+ output += Glib::ustring::compose(" draw:display-name=\"%1\"", gi.name);
+ output += " draw:style=\"linear\"";
+ snprintf(buf, 127, " draw:start-color=\"#%06lx\" draw:end-color=\"#%06lx\"", gi.stops[0].rgb, gi.stops[1].rgb);
+ output += buf;
+ //TODO: apply maths, to define begin of gradient, taking gradient begin and end, as well as object boundary into account
+ double angle = (gi.y2-gi.y1);
+ angle = (angle != 0.) ? (atan((gi.x2-gi.x1)/(gi.y2-gi.y1))* 180. / pi) : 90;
+ angle = (angle < 0)?(180+angle):angle;
+ angle = angle * 10; //why do we need this: precision?????????????
+ output += Glib::ustring::compose(" draw:start-intensity=\"%1\" draw:end-intensity=\"%2\" draw:angle=\"%3\"/>\n",
+ gi.stops[0].opacity * 100.0, gi.stops[1].opacity * 100.0, angle);// draw:border=\"0%%\"
+ }
else if (gi.style == "radial")
- {
+ {
/*
===================================================================
RADIAL gradient. We need something that looks like this:
@@ -1783,62 +1587,31 @@ bool OdfOutput::processGradient(Writer &outs, SPItem *item,
===================================================================
*/
if (gi.stops.size() < 2)
- {
+ {
g_warning("Need at least 2 stops for a radial gradient");
return false;
- }
- outs.printf("<svg:radialGradient ");
- outs.printf("id=\"%#s_g\" ", gi.name.c_str());
- outs.printf("draw:name=\"%#s_g\"\n", gi.name.c_str());
- outs.printf(" draw:display-name=\"imported radial %d\"\n",
- gradientCount);
- outs.printf(" svg:gradientUnits=\"objectBoundingBox\"\n");
- outs.printf(" svg:cx=\"%05.3f\" svg:cy=\"%05.3f\"\n",
- gi.cx, gi.cy);
- outs.printf(" svg:fx=\"%05.3f\" svg:fy=\"%05.3f\"\n",
- gi.fx, gi.fy);
- outs.printf(" svg:r=\"%05.3f\">\n",
- gi.r);
- outs.printf(" <svg:stop\n");
- outs.printf(" svg:stop-color=\"#%06lx\"\n",
- gi.stops[0].rgb);
- outs.printf(" svg:stop-opacity=\"%f%%\"\n",
- gi.stops[0].opacity * 100.0);
- outs.printf(" svg:offset=\"0\"/>\n");
- outs.printf(" <svg:stop\n");
- outs.printf(" svg:stop-color=\"#%06lx\"\n",
- gi.stops[1].rgb);
- outs.printf(" svg:stop-opacity=\"%f%%\"\n",
- gi.stops[1].opacity * 100.0);
- outs.printf(" svg:offset=\"1\"/>\n");
- outs.printf("</svg:radialGradient>\n");
}
+ output += Glib::ustring::compose("<draw:gradient draw:name=\"%1\" draw:display-name=\"%1\" ", gi.name);
+ snprintf(buf, 127, "draw:cx=\"%05.3f\" draw:cy=\"%05.3f\" ", gi.cx*100, gi.cy*100);
+ output += Glib::ustring("draw:style=\"radial\" ") + buf;
+ snprintf(buf, 127, "draw:start-color=\"#%06lx\" draw:end-color=\"#%06lx\" ", gi.stops[0].rgb, gi.stops[1].rgb);
+ output += buf;
+ snprintf(buf, 127, "draw:start-intensity=\"%f%%\" draw:end-intensity=\"%f%%\" ", gi.stops[0].opacity*100.0, gi.stops[1].opacity*100.0);
+ output += buf;
+ output += "/>\n";//draw:border=\"0%\"
+ }
else
- {
+ {
g_warning("unsupported gradient style '%s'", gi.style.c_str());
return false;
- }
- outs.printf("<style:style style:name=\"%#s\" style:family=\"graphic\" ",
- gi.name.c_str());
- outs.printf("style:parent-style-name=\"standard\">\n");
- outs.printf(" <style:graphic-properties draw:fill=\"gradient\" ");
- outs.printf("draw:fill-gradient-name=\"%#s_g\"\n",
- gi.name.c_str());
- outs.printf(" draw:textarea-horizontal-align=\"center\" ");
- outs.printf("draw:textarea-vertical-align=\"middle\"/>\n");
- outs.printf("</style:style>\n\n");
-
+ }
return true;
}
-
-
/**
* SECOND PASS.
- * This is the main SPObject tree output to ODF. preprocess()
- * must be called prior to this, as elements will often reference
- * data parsed and tabled in preprocess().
+ * This is the main SPObject tree output to ODF.
*/
bool OdfOutput::writeTree(Writer &couts, Writer &souts,
Inkscape::XML::Node *node)
@@ -1846,22 +1619,19 @@ bool OdfOutput::writeTree(Writer &couts, Writer &souts,
//# Get the SPItem, if applicable
SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node);
if (!reprobj)
+ {
return true;
+ }
if (!SP_IS_ITEM(reprobj))
- {
+ {
return true;
- }
+ }
SPItem *item = SP_ITEM(reprobj);
-
Glib::ustring nodeName = node->name();
Glib::ustring id = getAttribute(node, "id");
-
- //### Get SVG-to-ODF transform
- Geom::Affine tf = getODFTransform(item);
-
- //### Get ODF bounding box params for item
- Geom::OptRect bbox = getODFBoundingBox(item);
+ Geom::Affine tf = getODFTransform(item);//Get SVG-to-ODF transform
+ Geom::OptRect bbox = getODFBoundingBox(item);//Get ODF bounding box params for item
if (!bbox) {
return true;
}
@@ -1881,63 +1651,73 @@ bool OdfOutput::writeTree(Writer &couts, Writer &souts,
//# Do our stuff
SPCurve *curve = NULL;
-
-
if (nodeName == "svg" || nodeName == "svg:svg")
- {
+ {
//# Iterate through the children
for (Inkscape::XML::Node *child = node->firstChild() ;
child ; child = child->next())
- {
+ {
if (!writeTree(couts, souts, child))
+ {
return false;
}
- return true;
}
+ return true;
+ }
else if (nodeName == "g" || nodeName == "svg:g")
+ {
+ if (!id.empty())
{
- if (id.size() > 0)
couts.printf("<draw:g id=\"%s\">\n", id.c_str());
+ }
else
+ {
couts.printf("<draw:g>\n");
+ }
//# Iterate through the children
for (Inkscape::XML::Node *child = node->firstChild() ;
child ; child = child->next())
- {
+ {
if (!writeTree(couts, souts, child))
+ {
return false;
}
- if (id.size() > 0)
+ }
+ if (!id.empty())
+ {
couts.printf("</draw:g> <!-- id=\"%s\" -->\n", id.c_str());
+ }
else
+ {
couts.printf("</draw:g>\n");
- return true;
}
+ return true;
+ }
- //######################################
- //# S T Y L E
- //######################################
- processStyle(souts, item, id);
-
- //######################################
- //# G R A D I E N T
- //######################################
- processGradient(souts, item, id, tf);
-
-
-
-
- //######################################
- //# I T E M D A T A
- //######################################
- //g_message("##### %s #####", nodeName.c_str());
+ //# GRADIENT
+ Glib::ustring gradientNameFill;
+ Glib::ustring gradientNameStroke;
+ Glib::ustring outputFill;
+ Glib::ustring outputStroke;
+ Glib::ustring outputStyle;
+
+ processGradient(item, id, tf, gradientNameFill, outputFill, 1);
+ processGradient(item, id, tf, gradientNameStroke, outputStroke, 0);
+ souts.writeUString(outputFill);
+ souts.writeUString(outputStroke);
+
+ //# STYLE
+ processStyle(item, id, gradientNameFill, gradientNameStroke, outputStyle);
+ souts.writeUString(outputStyle);
+
+ //# ITEM DATA
if (nodeName == "image" || nodeName == "svg:image")
- {
+ {
if (!SP_IS_IMAGE(item))
- {
- g_warning("<image> is not an SPImage. Why? ;-)");
+ {
+ g_warning("<image> is not an SPImage.");
return false;
- }
+ }
SPImage *img = SP_IMAGE(item);
double ix = img->x.value;
@@ -1949,8 +1729,6 @@ bool OdfOutput::writeTree(Writer &couts, Writer &souts,
ibbox = ibbox * tf;
ix = ibbox.min()[Geom::X];
iy = ibbox.min()[Geom::Y];
- //iwidth = ibbox.max()[Geom::X] - ibbox.min()[Geom::X];
- //iheight = ibbox.max()[Geom::Y] - ibbox.min()[Geom::Y];
iwidth = xscale * iwidth;
iheight = yscale * iheight;
@@ -1961,99 +1739,89 @@ bool OdfOutput::writeTree(Writer &couts, Writer &souts,
Glib::ustring href = getAttribute(node, "xlink:href");
std::map<Glib::ustring, Glib::ustring>::iterator iter = imageTable.find(href);
if (iter == imageTable.end())
- {
+ {
g_warning("image '%s' not in table", href.c_str());
return false;
- }
+ }
Glib::ustring newName = iter->second;
couts.printf("<draw:frame ");
- if (id.size() > 0)
+ if (!id.empty())
+ {
couts.printf("id=\"%s\" ", id.c_str());
+ }
couts.printf("draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:layer=\"layout\" ");
//no x or y. make them the translate transform, last one
couts.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
iwidth, iheight);
- if (itemTransformString.size() > 0)
- {
+ if (!itemTransformString.empty())
+ {
couts.printf("draw:transform=\"%s translate(%.3fcm, %.3fcm)\" ",
itemTransformString.c_str(), ix, iy);
- }
+ }
else
- {
- couts.printf("draw:transform=\"translate(%.3fcm, %.3fcm)\" ",
- ix, iy);
- }
+ {
+ couts.printf("draw:transform=\"translate(%.3fcm, %.3fcm)\" ", ix, iy);
+ }
- couts.printf(">\n");
+ couts.writeString(">\n");
couts.printf(" <draw:image xlink:href=\"%s\" xlink:type=\"simple\"\n",
newName.c_str());
- couts.printf(" xlink:show=\"embed\" xlink:actuate=\"onLoad\">\n");
- couts.printf(" <text:p/>\n");
- couts.printf(" </draw:image>\n");
- couts.printf("</draw:frame>\n");
+ couts.writeString(" xlink:show=\"embed\" xlink:actuate=\"onLoad\">\n");
+ couts.writeString(" <text:p/>\n");
+ couts.writeString(" </draw:image>\n");
+ couts.writeString("</draw:frame>\n");
return true;
- }
+ }
else if (SP_IS_SHAPE(item))
- {
- //g_message("### %s is a shape", nodeName.c_str());
+ {
curve = SP_SHAPE(item)->getCurve();
- }
+ }
else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))
- {
+ {
curve = te_get_layout(item)->convertToCurves();
- }
+ }
if (curve)
- {
+ {
//### Default <path> output
-
- couts.printf("<draw:path ");
- if (id.size()>0)
+ couts.writeString("<draw:path ");
+ if (!id.empty())
+ {
couts.printf("id=\"%s\" ", id.c_str());
+ }
std::map<Glib::ustring, Glib::ustring>::iterator siter;
siter = styleLookupTable.find(id);
if (siter != styleLookupTable.end())
- {
+ {
Glib::ustring styleName = siter->second;
couts.printf("draw:style-name=\"%s\" ", styleName.c_str());
- }
-
- std::map<Glib::ustring, Glib::ustring>::iterator giter;
- giter = gradientLookupTable.find(id);
- if (giter != gradientLookupTable.end())
- {
- Glib::ustring gradientName = giter->second;
- couts.printf("draw:fill-gradient-name=\"%s\" ",
- gradientName.c_str());
- }
+ }
couts.printf("draw:layer=\"layout\" svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ",
bbox_x, bbox_y);
couts.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ",
bbox_width, bbox_height);
- couts.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"\n",
+ couts.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"",
bbox_width * 1000.0, bbox_height * 1000.0);
- couts.printf(" svg:d=\"");
+ couts.printf(" svg:d=\"");
int nrPoints = writePath(couts, curve->get_pathvector(),
tf, bbox_x, bbox_y);
- couts.printf("\"");
+ couts.writeString("\"");
- couts.printf(">\n");
+ couts.writeString(">\n");
couts.printf(" <!-- %d nodes -->\n", nrPoints);
- couts.printf("</draw:path>\n\n");
-
+ couts.writeString("</draw:path>\n\n");
curve->unref();
- }
+ }
return true;
}
-
/**
* Write the header for the content.xml file
*/
@@ -2062,59 +1830,56 @@ bool OdfOutput::writeStyleHeader(Writer &outs)
time_t tim;
time(&tim);
- outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<!--\n");
- outs.printf("*************************************************************************\n");
- outs.printf(" file: styles.xml\n");
- outs.printf(" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
- outs.printf(" http://www.inkscape.org\n");
- outs.printf("*************************************************************************\n");
- outs.printf("-->\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<office:document-styles\n");
- outs.printf(" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
- outs.printf(" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
- outs.printf(" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
- outs.printf(" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
- outs.printf(" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
- outs.printf(" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
- outs.printf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
- outs.printf(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
- outs.printf(" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
- outs.printf(" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
- outs.printf(" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
- outs.printf(" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
- outs.printf(" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
- outs.printf(" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
- outs.printf(" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
- outs.printf(" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
- outs.printf(" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
- outs.printf(" xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
- outs.printf(" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
- outs.printf(" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
- outs.printf(" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
- outs.printf(" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
- outs.printf(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
- outs.printf(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
- outs.printf(" xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
- outs.printf(" xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
- outs.printf(" office:version=\"1.0\">\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<!--\n");
- outs.printf("*************************************************************************\n");
- outs.printf(" S T Y L E S\n");
- outs.printf(" Style entries have been pulled from the svg style and\n");
- outs.printf(" representation attributes in the SVG tree. The tree elements\n");
- outs.printf(" then refer to them by name, in the ODF manner\n");
- outs.printf("*************************************************************************\n");
- outs.printf("-->\n");
- outs.printf("\n");
- outs.printf("<office:styles>\n");
- outs.printf("\n");
+ outs.writeString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ outs.writeString("\n");
+ outs.writeString("<!--\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString(" file: styles.xml\n");
+ outs.printf (" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
+ outs.writeString(" http://www.inkscape.org\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString("-->\n");
+ outs.writeString("\n");
+ outs.writeString("<office:document-styles\n");
+ outs.writeString(" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
+ outs.writeString(" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
+ outs.writeString(" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
+ outs.writeString(" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
+ outs.writeString(" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
+ outs.writeString(" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
+ outs.writeString(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
+ outs.writeString(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
+ outs.writeString(" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
+ outs.writeString(" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
+ outs.writeString(" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
+ outs.writeString(" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
+ outs.writeString(" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
+ outs.writeString(" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
+ outs.writeString(" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
+ outs.writeString(" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
+ outs.writeString(" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
+ outs.writeString(" xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
+ outs.writeString(" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
+ outs.writeString(" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
+ outs.writeString(" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
+ outs.writeString(" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
+ outs.writeString(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
+ outs.writeString(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
+ outs.writeString(" xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
+ outs.writeString(" xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
+ outs.writeString(" office:version=\"1.0\">\n");
+ outs.writeString("\n");
+ outs.writeString("<!--\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString(" S T Y L E S\n");
+ outs.writeString(" Style entries have been pulled from the svg style and\n");
+ outs.writeString(" representation attributes in the SVG tree. The tree elements\n");
+ outs.writeString(" then refer to them by name, in the ODF manner\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString("-->\n");
+ outs.writeString("\n");
+ outs.writeString("<office:styles>\n");
+ outs.writeString("\n");
return true;
}
@@ -2125,58 +1890,49 @@ bool OdfOutput::writeStyleHeader(Writer &outs)
*/
bool OdfOutput::writeStyleFooter(Writer &outs)
{
- outs.printf("\n");
- outs.printf("</office:styles>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<office:automatic-styles>\n");
- outs.printf("<!-- ####### 'Standard' styles ####### -->\n");
- outs.printf("<style:style style:name=\"dp1\" style:family=\"drawing-page\"/>\n");
- outs.printf("<style:style style:name=\"gr1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
- outs.printf(" <style:graphic-properties draw:stroke=\"none\" draw:fill=\"none\"\n");
- outs.printf(" draw:textarea-horizontal-align=\"center\"\n");
- outs.printf(" draw:textarea-vertical-align=\"middle\" draw:color-mode=\"standard\"\n");
- outs.printf(" draw:luminance=\"0%%\" draw:contrast=\"0%%\" draw:gamma=\"100%%\" draw:red=\"0%%\"\n");
- outs.printf(" draw:green=\"0%%\" draw:blue=\"0%%\" fo:clip=\"rect(0cm 0cm 0cm 0cm)\"\n");
- outs.printf(" draw:image-opacity=\"100%%\" style:mirror=\"none\"/>\n");
- outs.printf("</style:style>\n");
- outs.printf("<style:style style:name=\"P1\" style:family=\"paragraph\">\n");
- outs.printf(" <style:paragraph-properties fo:text-align=\"center\"/>\n");
- outs.printf("</style:style>\n");
- outs.printf("</office:automatic-styles>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<office:master-styles>\n");
- outs.printf("<draw:layer-set>\n");
- outs.printf(" <draw:layer draw:name=\"layout\"/>\n");
- outs.printf(" <draw:layer draw:name=\"background\"/>\n");
- outs.printf(" <draw:layer draw:name=\"backgroundobjects\"/>\n");
- outs.printf(" <draw:layer draw:name=\"controls\"/>\n");
- outs.printf(" <draw:layer draw:name=\"measurelines\"/>\n");
- outs.printf("</draw:layer-set>\n");
- outs.printf("\n");
- outs.printf("<style:master-page style:name=\"Default\"\n");
- outs.printf(" style:page-master-name=\"PM1\" draw:style-name=\"dp1\"/>\n");
- outs.printf("</office:master-styles>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("</office:document-styles>\n");
- outs.printf("\n");
- outs.printf("<!--\n");
- outs.printf("*************************************************************************\n");
- outs.printf(" E N D O F F I L E\n");
- outs.printf(" Have a nice day - ishmal\n");
- outs.printf("*************************************************************************\n");
- outs.printf("-->\n");
- outs.printf("\n");
+ outs.writeString("\n");
+ outs.writeString("</office:styles>\n");
+ outs.writeString("\n");
+ outs.writeString("<office:automatic-styles>\n");
+ outs.writeString("<!-- ####### 'Standard' styles ####### -->\n");
+ outs.writeString("<style:style style:name=\"dp1\" style:family=\"drawing-page\"/>\n");
+ outs.writeString("<style:style style:name=\"standard\" style:family=\"graphic\">\n");
+
+///TODO: add default document style here
+
+ outs.writeString("</style:style>\n");
+ outs.writeString("<style:style style:name=\"gr1\" style:family=\"graphic\" style:parent-style-name=\"standard\">\n");
+ outs.writeString(" <style:graphic-properties draw:stroke=\"none\" draw:fill=\"none\"\n");
+ outs.writeString(" draw:textarea-horizontal-align=\"center\"\n");
+ outs.writeString(" draw:textarea-vertical-align=\"middle\" draw:color-mode=\"standard\"\n");
+ outs.writeString(" draw:luminance=\"0%\" draw:contrast=\"0%\" draw:gamma=\"100%\" draw:red=\"0%\"\n");
+ outs.writeString(" draw:green=\"0%\" draw:blue=\"0%\" fo:clip=\"rect(0cm 0cm 0cm 0cm)\"\n");
+ outs.writeString(" draw:image-opacity=\"100%\" style:mirror=\"none\"/>\n");
+ outs.writeString("</style:style>\n");
+ outs.writeString("<style:style style:name=\"P1\" style:family=\"paragraph\">\n");
+ outs.writeString(" <style:paragraph-properties fo:text-align=\"center\"/>\n");
+ outs.writeString("</style:style>\n");
+ outs.writeString("</office:automatic-styles>\n");
+ outs.writeString("\n");
+ outs.writeString("<office:master-styles>\n");
+ outs.writeString("<draw:layer-set>\n");
+ outs.writeString(" <draw:layer draw:name=\"layout\"/>\n");
+ outs.writeString(" <draw:layer draw:name=\"background\"/>\n");
+ outs.writeString(" <draw:layer draw:name=\"backgroundobjects\"/>\n");
+ outs.writeString(" <draw:layer draw:name=\"controls\"/>\n");
+ outs.writeString(" <draw:layer draw:name=\"measurelines\"/>\n");
+ outs.writeString("</draw:layer-set>\n");
+ outs.writeString("\n");
+ outs.writeString("<style:master-page style:name=\"Default\"\n");
+ outs.writeString(" style:page-master-name=\"PM1\" draw:style-name=\"dp1\"/>\n");
+ outs.writeString("</office:master-styles>\n");
+ outs.writeString("\n");
+ outs.writeString("</office:document-styles>\n");
return true;
}
-
-
/**
* Write the header for the content.xml file
*/
@@ -2185,69 +1941,61 @@ bool OdfOutput::writeContentHeader(Writer &outs)
time_t tim;
time(&tim);
- outs.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<!--\n");
- outs.printf("*************************************************************************\n");
- outs.printf(" file: content.xml\n");
- outs.printf(" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
- outs.printf(" http://www.inkscape.org\n");
- outs.printf("*************************************************************************\n");
- outs.printf("-->\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<office:document-content\n");
- outs.printf(" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
- outs.printf(" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
- outs.printf(" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
- outs.printf(" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
- outs.printf(" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
- outs.printf(" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
- outs.printf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
- outs.printf(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
- outs.printf(" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
- outs.printf(" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
- outs.printf(" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
- outs.printf(" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
- outs.printf(" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
- outs.printf(" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
- outs.printf(" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
- outs.printf(" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
- outs.printf(" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
- outs.printf(" xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
- outs.printf(" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
- outs.printf(" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
- outs.printf(" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
- outs.printf(" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
- outs.printf(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
- outs.printf(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
- outs.printf(" xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
- outs.printf(" xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
- outs.printf(" office:version=\"1.0\">\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<office:scripts/>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<!--\n");
- outs.printf("*************************************************************************\n");
- outs.printf(" D R A W I N G\n");
- outs.printf(" This section is the heart of SVG-ODF conversion. We are\n");
- outs.printf(" starting with simple conversions, and will slowly evolve\n");
- outs.printf(" into a 'smarter' translation as time progresses. Any help\n");
- outs.printf(" in improving .odg export is welcome.\n");
- outs.printf("*************************************************************************\n");
- outs.printf("-->\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<office:body>\n");
- outs.printf("<office:drawing>\n");
- outs.printf("<draw:page draw:name=\"page1\" draw:style-name=\"dp1\"\n");
- outs.printf(" draw:master-page-name=\"Default\">\n");
- outs.printf("\n");
- outs.printf("\n");
-
+ outs.writeString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ outs.writeString("\n");
+ outs.writeString("<!--\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString(" file: content.xml\n");
+ outs.printf (" Generated by Inkscape: %s", ctime(&tim)); //ctime has its own <cr>
+ outs.writeString(" http://www.inkscape.org\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString("-->\n");
+ outs.writeString("\n");
+ outs.writeString("<office:document-content\n");
+ outs.writeString(" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n");
+ outs.writeString(" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n");
+ outs.writeString(" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n");
+ outs.writeString(" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n");
+ outs.writeString(" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n");
+ outs.writeString(" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n");
+ outs.writeString(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
+ outs.writeString(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
+ outs.writeString(" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n");
+ outs.writeString(" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n");
+ outs.writeString(" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\"\n");
+ outs.writeString(" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n");
+ outs.writeString(" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n");
+ outs.writeString(" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n");
+ outs.writeString(" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n");
+ outs.writeString(" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n");
+ outs.writeString(" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n");
+ outs.writeString(" xmlns:ooo=\"http://openoffice.org/2004/office\"\n");
+ outs.writeString(" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n");
+ outs.writeString(" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n");
+ outs.writeString(" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n");
+ outs.writeString(" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n");
+ outs.writeString(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
+ outs.writeString(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
+ outs.writeString(" xmlns:smil=\"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0\"\n");
+ outs.writeString(" xmlns:anim=\"urn:oasis:names:tc:opendocument:xmlns:animation:1.0\"\n");
+ outs.writeString(" office:version=\"1.0\">\n");
+ outs.writeString("<office:scripts/>\n");
+ outs.writeString("\n");
+ outs.writeString("<!--\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString(" D R A W I N G\n");
+ outs.writeString(" This section is the heart of SVG-ODF conversion. We are\n");
+ outs.writeString(" starting with simple conversions, and will slowly evolve\n");
+ outs.writeString(" into a 'smarter' translation as time progresses. Any help\n");
+ outs.writeString(" in improving .odg export is welcome.\n");
+ outs.writeString("*************************************************************************\n");
+ outs.writeString("-->\n");
+ outs.writeString("\n");
+ outs.writeString("<office:body>\n");
+ outs.writeString("<office:drawing>\n");
+ outs.writeString("<draw:page draw:name=\"page1\" draw:style-name=\"dp1\"\n");
+ outs.writeString(" draw:master-page-name=\"Default\">\n");
+ outs.writeString("\n");
return true;
}
@@ -2257,37 +2005,18 @@ bool OdfOutput::writeContentHeader(Writer &outs)
*/
bool OdfOutput::writeContentFooter(Writer &outs)
{
- outs.printf("\n");
- outs.printf("\n");
-
- outs.printf("</draw:page>\n");
- outs.printf("</office:drawing>\n");
-
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<!-- ######### CONVERSION FROM SVG ENDS ######## -->\n");
- outs.printf("\n");
- outs.printf("\n");
-
- outs.printf("</office:body>\n");
- outs.printf("</office:document-content>\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("\n");
- outs.printf("<!--\n");
- outs.printf("*************************************************************************\n");
- outs.printf(" E N D O F F I L E\n");
- outs.printf(" Have a nice day - ishmal\n");
- outs.printf("*************************************************************************\n");
- outs.printf("-->\n");
- outs.printf("\n");
- outs.printf("\n");
-
+ outs.writeString("\n");
+ outs.writeString("</draw:page>\n");
+ outs.writeString("</office:drawing>\n");
+ outs.writeString("\n");
+ outs.writeString("<!-- ######### CONVERSION FROM SVG ENDS ######## -->\n");
+ outs.writeString("\n");
+ outs.writeString("</office:body>\n");
+ outs.writeString("</office:document-content>\n");
return true;
}
-
/**
* Write the content.xml file. Writes the namesspace headers, then
* calls writeTree().
@@ -2299,39 +2028,48 @@ bool OdfOutput::writeContent(ZipFile &zf, Inkscape::XML::Node *node)
OutputStreamWriter couts(cbouts);
if (!writeContentHeader(couts))
+ {
return false;
+ }
//Style.xml stream
BufferOutputStream sbouts;
OutputStreamWriter souts(sbouts);
if (!writeStyleHeader(souts))
+ {
return false;
-
+ }
//# Descend into the tree, doing all of our conversions
- //# to both files as the same time
+ //# to both files at the same time
+ char *oldlocale = g_strdup (setlocale (LC_NUMERIC, NULL));
+ setlocale (LC_NUMERIC, "C");
if (!writeTree(couts, souts, node))
- {
+ {
g_warning("Failed to convert SVG tree");
+ setlocale (LC_NUMERIC, oldlocale);
+ g_free (oldlocale);
return false;
- }
-
-
+ }
+ setlocale (LC_NUMERIC, oldlocale);
+ g_free (oldlocale);
//# Finish content file
if (!writeContentFooter(couts))
+ {
return false;
+ }
ZipEntry *ze = zf.newEntry("content.xml", "ODF master content file");
ze->setUncompressedData(cbouts.getBuffer());
ze->finish();
-
-
//# Finish style file
if (!writeStyleFooter(souts))
+ {
return false;
+ }
ze = zf.newEntry("styles.xml", "ODF style file");
ze->setUncompressedData(sbouts.getBuffer());
@@ -2344,8 +2082,7 @@ bool OdfOutput::writeContent(ZipFile &zf, Inkscape::XML::Node *node)
/**
* Resets class to its pristine condition, ready to use again
*/
-void
-OdfOutput::reset()
+void OdfOutput::reset()
{
metadata.clear();
styleTable.clear();
@@ -2353,23 +2090,17 @@ OdfOutput::reset()
gradientTable.clear();
gradientLookupTable.clear();
imageTable.clear();
-
-
}
/**
* Descends into the SVG tree, mapping things to ODF when appropriate
*/
-void
-OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gchar const *filename)
+void OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gchar const *filename)
{
reset();
- //g_message("native file:%s\n", filename);
- documentUri = URI(filename);
- /* fixme: It looks like we really are using documentUri as a URI, so we ought to call
- * g_filename_to_uri for the URI constructor. */
+ documentUri = Inkscape::URI(filename);
ZipFile zf;
preprocess(zf, doc->rroot);
@@ -2404,8 +2135,7 @@ OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gchar con
* calls the extension system with the memory allocated XML that
* describes the data.
*/
-void
-OdfOutput::init()
+void OdfOutput::init()
{
Inkscape::Extension::build_from_mem(
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
@@ -2424,8 +2154,7 @@ OdfOutput::init()
/**
* Make sure that we are in the database
*/
-bool
-OdfOutput::check (Inkscape::Extension::Extension */*module*/)
+bool OdfOutput::check (Inkscape::Extension::Extension */*module*/)
{
/* We don't need a Key
if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_POV))
@@ -2435,30 +2164,6 @@ OdfOutput::check (Inkscape::Extension::Extension */*module*/)
return TRUE;
}
-
-
-//########################################################################
-//# I N P U T
-//########################################################################
-
-
-
-//#######################
-//# L A T E R !!! :-)
-//#######################
-
-
-
-
-
-
-
-
-
-
-
-
-
} //namespace Internal
} //namespace Extension
} //namespace Inkscape
diff --git a/src/extension/internal/odf.h b/src/extension/internal/odf.h
index 6b8883134..f8712d5eb 100644
--- a/src/extension/internal/odf.h
+++ b/src/extension/internal/odf.h
@@ -23,23 +23,20 @@
#ifndef EXTENSION_INTERNAL_ODG_OUT_H
#define EXTENSION_INTERNAL_ODG_OUT_H
-#include <dom/dom.h>
-#include <dom/io/stringstream.h>
-#include <dom/uri.h>
+#include <io/stringstream.h>
+#include <util/ziptool.h>
-#include <glibmm.h>
#include "extension/implementation/implementation.h"
-
#include <xml/repr.h>
-
#include <string>
#include <map>
-#include <dom/util/ziptool.h>
-#include <dom/io/domstream.h>
+#include "uri.h"
#include "sp-item.h"
+#include <glibmm/ustring.h>
+
namespace Inkscape
{
namespace Extension
@@ -47,9 +44,7 @@ namespace Extension
namespace Internal
{
-typedef org::w3c::dom::URI URI;
-typedef org::w3c::dom::io::Writer Writer;
-
+typedef Inkscape::IO::Writer Writer;
class StyleInfo
{
@@ -281,7 +276,7 @@ public:
private:
- URI documentUri;
+ Inkscape::URI documentUri;
void reset();
@@ -315,10 +310,10 @@ private:
bool writeStyle(ZipFile &zf);
- bool processStyle(Writer &outs, SPItem *item, const Glib::ustring &id);
+ bool processStyle(SPItem *item, const Glib::ustring &id, const Glib::ustring &gradientNameFill, const Glib::ustring &gradientNameStroke, Glib::ustring& output);
- bool processGradient(Writer &outs, SPItem *item,
- const Glib::ustring &id, Geom::Affine &tf);
+ bool processGradient(SPItem *item,
+ const Glib::ustring &id, Geom::Affine &tf, Glib::ustring& gradientName, Glib::ustring& output, bool checkFillGradient = 1);
bool writeStyleHeader(Writer &outs);
@@ -335,8 +330,6 @@ private:
};
-
-
} //namespace Internal
} //namespace Extension
} //namespace Inkscape
diff --git a/src/extension/internal/pdf-input-cairo.cpp b/src/extension/internal/pdf-input-cairo.cpp
index 5cb4f96c3..c45367c08 100644
--- a/src/extension/internal/pdf-input-cairo.cpp
+++ b/src/extension/internal/pdf-input-cairo.cpp
@@ -23,6 +23,10 @@
#include "extension/input.h"
#include "dialogs/dialog-events.h"
#include "document.h"
+#include "sp-root.h"
+#include "util/units.h"
+
+#include <2geom/rect.h>
#include "inkscape.h"
@@ -95,11 +99,7 @@ PdfImportCairoDialog::PdfImportCairoDialog(PopplerDocument *doc)
_cropTypeCombo = Gtk::manage(new class Gtk::ComboBoxText());
int num_crop_choices = sizeof(crop_setting_choices) / sizeof(crop_setting_choices[0]);
for ( int i = 0 ; i < num_crop_choices ; i++ ) {
-#if WITH_GTKMM_2_24
_cropTypeCombo->append(_(crop_setting_choices[i]));
-#else
- _cropTypeCombo->append_text(_(crop_setting_choices[i]));
-#endif
}
_cropTypeCombo->set_active_text(_(crop_setting_choices[0]));
_cropTypeCombo->set_sensitive(false);
@@ -112,7 +112,7 @@ PdfImportCairoDialog::PdfImportCairoDialog(PopplerDocument *doc)
#if WITH_GTKMM_3_0
_fallbackPrecisionSlider_adj = Gtk::Adjustment::create(2, 1, 256, 1, 10, 10);
- _fallbackPrecisionSlider = Gtk::manage(new Gtk::HScale(_fallbackPrecisionSlider_adj));
+ _fallbackPrecisionSlider = Gtk::manage(new Gtk::Scale(_fallbackPrecisionSlider_adj));
#else
_fallbackPrecisionSlider_adj = Gtk::manage(new class Gtk::Adjustment(2, 1, 256, 1, 10, 10));
_fallbackPrecisionSlider = Gtk::manage(new class Gtk::HScale(*_fallbackPrecisionSlider_adj));
@@ -124,11 +124,7 @@ PdfImportCairoDialog::PdfImportCairoDialog(PopplerDocument *doc)
// Text options
_labelText = Gtk::manage(new class Gtk::Label(_("Text handling:")));
_textHandlingCombo = Gtk::manage(new class Gtk::ComboBoxText());
-#if WITH_GTKMM_2_24
_textHandlingCombo->append(_("Import text as text"));
-#else
- _textHandlingCombo->append_text(_("Import text as text"));
-#endif
_textHandlingCombo->set_active_text(_("Import text as text"));
_localFontsCheck = Gtk::manage(new class Gtk::CheckButton(_("Replace PDF fonts by closest-named installed fonts")));
@@ -232,12 +228,20 @@ PdfImportCairoDialog::PdfImportCairoDialog(PopplerDocument *doc)
vbox1->pack_start(*_importSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0);
hbox1->pack_start(*vbox1);
hbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 4);
+
+#if WITH_GTKMM_3_0
+ get_content_area()->set_homogeneous(false);
+ get_content_area()->set_spacing(0);
+ get_content_area()->pack_start(*hbox1);
+#else
this->get_vbox()->set_homogeneous(false);
this->get_vbox()->set_spacing(0);
this->get_vbox()->pack_start(*hbox1);
+#endif
+
this->set_title(_("PDF Import Settings"));
this->set_modal(true);
- sp_transientize((GtkWidget *)this->gobj()); //Make transient
+ sp_transientize(GTK_WIDGET(this->gobj())); //Make transient
this->property_window_position().set_value(Gtk::WIN_POS_NONE);
this->set_resizable(true);
this->property_destroy_with_parent().set_value(false);
@@ -271,7 +275,11 @@ PdfImportCairoDialog::PdfImportCairoDialog(PopplerDocument *doc)
hbox1->show();
// Connect signals
+#if WITH_GTKMM_3_0
+ _previewArea->signal_draw().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onDraw));
+#else
_previewArea->signal_expose_event().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onExposePreview));
+#endif
_pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onPageNumberChanged));
_cropCheck->signal_toggled().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onToggleCropping));
_fallbackPrecisionSlider_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onPrecisionChanged));
@@ -420,7 +428,7 @@ static void copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
cairo_height = gdk_pixbuf_get_height (pixbuf);
for (y = 0; y < cairo_height; y++)
{
- src = (unsigned int *) (cairo_data + y * cairo_rowstride);
+ src = reinterpret_cast<unsigned int *>(cairo_data + y * cairo_rowstride);
dst = pixbuf_data + y * pixbuf_rowstride;
for (x = 0; x < cairo_width; x++)
{
@@ -438,8 +446,15 @@ static void copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
/**
* \brief Updates the preview area with the previously rendered thumbnail
*/
-bool PdfImportCairoDialog::_onExposePreview(GdkEventExpose */*event*/) {
+#if !WITH_GTKMM_3_0
+bool PdfImportCairoDialog::_onExposePreview(GdkEventExpose * /*event*/) {
+ Cairo::RefPtr<Cairo::Context> cr = _previewArea->get_window()->create_cairo_context();
+ return _onDraw(cr);
+}
+#endif
+
+bool PdfImportCairoDialog::_onDraw(const Cairo::RefPtr<Cairo::Context>& cr) {
// Check if we have a thumbnail at all
if (!_thumb_data) {
return true;
@@ -461,24 +476,14 @@ bool PdfImportCairoDialog::_onExposePreview(GdkEventExpose */*event*/) {
// Set background to white
if (_render_thumb) {
thumb->fill(0xffffffff);
- Glib::RefPtr<Gdk::Pixmap> back_pixmap = Gdk::Pixmap::create(
- _previewArea->get_window(), _thumb_width, _thumb_height, -1);
- if (!back_pixmap) {
- return true;
- }
-
- Cairo::RefPtr<Cairo::Context> cr = back_pixmap->create_cairo_context();
Gdk::Cairo::set_source_pixbuf(cr, thumb, 0, 0);
cr->paint();
- _previewArea->get_window()->set_back_pixmap(back_pixmap, false);
- _previewArea->get_window()->clear();
}
// Copy the thumbnail image from the Cairo surface
if (_render_thumb) {
copy_cairo_surface_to_pixbuf(_cairo_surface, _thumb_data, thumb->gobj());
}
- Cairo::RefPtr<Cairo::Context> cr = _previewArea->get_window()->create_cairo_context();
Gdk::Cairo::set_source_pixbuf(cr, thumb, 0, _render_thumb ? 0 : 20);
cr->paint();
@@ -490,7 +495,7 @@ bool PdfImportCairoDialog::_onExposePreview(GdkEventExpose */*event*/) {
*/
void PdfImportCairoDialog::_setPreviewPage(int page) {
- PopplerPage *_previewed_page = poppler_document_get_page(_poppler_doc, page);
+ PopplerPage *_previewed_page = poppler_document_get_page(_poppler_doc, page-1);
// Try to get a thumbnail from the PDF if possible
if (!_render_thumb) {
@@ -619,6 +624,11 @@ PdfInputCairo::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
SPDocument * doc = SPDocument::createNewDocFromMem(output->c_str(), output->length(), TRUE);
+ // Set viewBox if it doesn't exist
+ if (doc && !doc->getRoot()->viewBox_set) {
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit())));
+ }
+
delete output;
g_object_unref(page);
g_object_unref(document);
@@ -629,8 +639,8 @@ PdfInputCairo::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
static cairo_status_t
_write_ustring_cb(void *closure, const unsigned char *data, unsigned int length)
{
- Glib::ustring* stream = (Glib::ustring*)closure;
- stream->append((const char*)data, length);
+ Glib::ustring* stream = static_cast<Glib::ustring*>(closure);
+ stream->append(reinterpret_cast<const char*>(data), length);
return CAIRO_STATUS_SUCCESS;
}
@@ -642,13 +652,13 @@ void
PdfInputCairo::init(void) {
Inkscape::Extension::build_from_mem(
"<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
- "<name>PDF Input</name>\n"
+ "<name>" N_("PDF Input") "</name>\n"
"<id>org.inkscape.input.cairo-pdf</id>\n"
"<input>\n"
"<extension>.pdf</extension>\n"
"<mimetype>application/pdf</mimetype>\n"
- "<filetypename>Adobe PDF via poppler-cairo (*.pdf)</filetypename>\n"
- "<filetypetooltip>PDF Document</filetypetooltip>\n"
+ "<filetypename>" N_("Adobe PDF via poppler-cairo (*.pdf)") "</filetypename>\n"
+ "<filetypetooltip>" N_("PDF Document") "</filetypetooltip>\n"
"</input>\n"
"</inkscape-extension>", new PdfInputCairo());
} // init
diff --git a/src/extension/internal/pdf-input-cairo.h b/src/extension/internal/pdf-input-cairo.h
index 15235ee19..b65d22f48 100644
--- a/src/extension/internal/pdf-input-cairo.h
+++ b/src/extension/internal/pdf-input-cairo.h
@@ -16,6 +16,10 @@
# include <config.h>
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/dialog.h>
#include <gtkmm/button.h>
#include <gtkmm/buttonbox.h>
@@ -37,6 +41,14 @@
#include "../implementation/implementation.h"
+namespace Gtk {
+#if WITH_GTKMM_3_0
+ class Scale;
+#else
+ class HScale;
+#endif
+}
+
namespace Inkscape {
namespace UI {
@@ -63,7 +75,11 @@ private:
void _setPreviewPage(int page);
// Signal handlers
+#if !WITH_GTKMM_3_0
bool _onExposePreview(GdkEventExpose *event);
+#endif
+
+ bool _onDraw(const Cairo::RefPtr<Cairo::Context>& cr);
void _onPageNumberChanged();
void _onToggleCropping();
void _onPrecisionChanged();
@@ -81,10 +97,11 @@ private:
class Inkscape::UI::Widget::Frame * _pageSettingsFrame;
class Gtk::Label * _labelPrecision;
class Gtk::Label * _labelPrecisionWarning;
- class Gtk::HScale * _fallbackPrecisionSlider;
#if WITH_GTKMM_3_0
+ class Gtk::Scale * _fallbackPrecisionSlider;
Glib::RefPtr<Gtk::Adjustment> _fallbackPrecisionSlider_adj;
#else
+ class Gtk::HScale * _fallbackPrecisionSlider;
class Gtk::Adjustment *_fallbackPrecisionSlider_adj;
#endif
class Gtk::Label * _labelPrecisionComment;
diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp
index d4fc6a8a2..3155ac098 100644
--- a/src/extension/internal/pdfinput/pdf-input.cpp
+++ b/src/extension/internal/pdfinput/pdf-input.cpp
@@ -32,6 +32,7 @@
#endif
#include <gtkmm/alignment.h>
+#include <gtkmm/checkbutton.h>
#include <gtkmm/comboboxtext.h>
#include <gtkmm/drawingarea.h>
#include <gtkmm/frame.h>
@@ -45,6 +46,7 @@
#include "document-private.h"
#include "document-undo.h"
#include "inkscape.h"
+#include "util/units.h"
#include "dialogs/dialog-events.h"
#include <gtk/gtk.h>
@@ -111,11 +113,7 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
_cropTypeCombo = Gtk::manage(new class Gtk::ComboBoxText());
int num_crop_choices = sizeof(crop_setting_choices) / sizeof(crop_setting_choices[0]);
for ( int i = 0 ; i < num_crop_choices ; i++ ) {
-#if WITH_GTKMM_2_24
_cropTypeCombo->append(_(crop_setting_choices[i]));
-#else
- _cropTypeCombo->append_text(_(crop_setting_choices[i]));
-#endif
}
_cropTypeCombo->set_active_text(_(crop_setting_choices[0]));
_cropTypeCombo->set_sensitive(false);
@@ -128,7 +126,7 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
#if WITH_GTKMM_3_0
_fallbackPrecisionSlider_adj = Gtk::Adjustment::create(2, 1, 256, 1, 10, 10);
- _fallbackPrecisionSlider = Gtk::manage(new class Gtk::HScale(_fallbackPrecisionSlider_adj));
+ _fallbackPrecisionSlider = Gtk::manage(new class Gtk::Scale(_fallbackPrecisionSlider_adj));
#else
_fallbackPrecisionSlider_adj = Gtk::manage(new class Gtk::Adjustment(2, 1, 256, 1, 10, 10));
_fallbackPrecisionSlider = Gtk::manage(new class Gtk::HScale(*_fallbackPrecisionSlider_adj));
@@ -140,11 +138,7 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
// Text options
_labelText = Gtk::manage(new class Gtk::Label(_("Text handling:")));
_textHandlingCombo = Gtk::manage(new class Gtk::ComboBoxText());
-#if WITH_GTKMM_2_24
_textHandlingCombo->append(_("Import text as text"));
-#else
- _textHandlingCombo->append_text(_("Import text as text"));
-#endif
_textHandlingCombo->set_active_text(_("Import text as text"));
_localFontsCheck = Gtk::manage(new class Gtk::CheckButton(_("Replace PDF fonts by closest-named installed fonts")));
@@ -248,12 +242,20 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
vbox1->pack_start(*_importSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0);
hbox1->pack_start(*vbox1);
hbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 4);
+
+#if WITH_GTKMM_3_0
+ get_content_area()->set_homogeneous(false);
+ get_content_area()->set_spacing(0);
+ get_content_area()->pack_start(*hbox1);
+#else
this->get_vbox()->set_homogeneous(false);
this->get_vbox()->set_spacing(0);
this->get_vbox()->pack_start(*hbox1);
+#endif
+
this->set_title(_("PDF Import Settings"));
this->set_modal(true);
- sp_transientize((GtkWidget *)this->gobj()); //Make transient
+ sp_transientize(GTK_WIDGET(this->gobj())); //Make transient
this->property_window_position().set_value(Gtk::WIN_POS_NONE);
this->set_resizable(true);
this->property_destroy_with_parent().set_value(false);
@@ -287,7 +289,12 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
hbox1->show();
// Connect signals
+#if WITH_GTKMM_3_0
+ _previewArea->signal_draw().connect(sigc::mem_fun(*this, &PdfImportDialog::_onDraw));
+#else
_previewArea->signal_expose_event().connect(sigc::mem_fun(*this, &PdfImportDialog::_onExposePreview));
+#endif
+
_pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportDialog::_onPageNumberChanged));
_cropCheck->signal_toggled().connect(sigc::mem_fun(*this, &PdfImportDialog::_onToggleCropping));
_fallbackPrecisionSlider_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportDialog::_onPrecisionChanged));
@@ -449,7 +456,7 @@ static void copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
cairo_height = gdk_pixbuf_get_height (pixbuf);
for (y = 0; y < cairo_height; y++)
{
- src = (unsigned int *) (cairo_data + y * cairo_rowstride);
+ src = reinterpret_cast<unsigned int *>(cairo_data + y * cairo_rowstride);
dst = pixbuf_data + y * pixbuf_rowstride;
for (x = 0; x < cairo_width; x++)
{
@@ -469,8 +476,14 @@ static void copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
/**
* \brief Updates the preview area with the previously rendered thumbnail
*/
-bool PdfImportDialog::_onExposePreview(GdkEventExpose */*event*/) {
+#if !WITH_GTKMM_3_0
+bool PdfImportDialog::_onExposePreview(GdkEventExpose * /*event*/) {
+ Cairo::RefPtr<Cairo::Context> cr = _previewArea->get_window()->create_cairo_context();
+ return _onDraw(cr);
+}
+#endif
+bool PdfImportDialog::_onDraw(const Cairo::RefPtr<Cairo::Context>& cr) {
// Check if we have a thumbnail at all
if (!_thumb_data) {
return true;
@@ -478,6 +491,7 @@ bool PdfImportDialog::_onExposePreview(GdkEventExpose */*event*/) {
// Create the pixbuf for the thumbnail
Glib::RefPtr<Gdk::Pixbuf> thumb;
+
if (_render_thumb) {
thumb = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true,
8, _thumb_width, _thumb_height);
@@ -492,17 +506,8 @@ bool PdfImportDialog::_onExposePreview(GdkEventExpose */*event*/) {
// Set background to white
if (_render_thumb) {
thumb->fill(0xffffffff);
- Glib::RefPtr<Gdk::Pixmap> back_pixmap = Gdk::Pixmap::create(
- _previewArea->get_window(), _thumb_width, _thumb_height, -1);
- if (!back_pixmap) {
- return true;
- }
-
- Cairo::RefPtr<Cairo::Context> cr = back_pixmap->create_cairo_context();
Gdk::Cairo::set_source_pixbuf(cr, thumb, 0, 0);
cr->paint();
- _previewArea->get_window()->set_back_pixmap(back_pixmap, false);
- _previewArea->get_window()->clear();
}
#ifdef HAVE_POPPLER_CAIRO
// Copy the thumbnail image from the Cairo surface
@@ -511,7 +516,6 @@ bool PdfImportDialog::_onExposePreview(GdkEventExpose */*event*/) {
}
#endif
- Cairo::RefPtr<Cairo::Context> cr = _previewArea->get_window()->create_cairo_context();
Gdk::Cairo::set_source_pixbuf(cr, thumb, 0, _render_thumb ? 0 : 20);
cr->paint();
return true;
@@ -586,12 +590,19 @@ void PdfImportDialog::_setPreviewPage(int page) {
////////////////////////////////////////////////////////////////////////////////
+bool
+PdfInput::wasCancelled () {
+ return _cancelled;
+}
+
/**
* Parses the selected page of the given PDF document using PdfParser.
*/
SPDocument *
PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
+ _cancelled = false;
+
// Initialize the globalParams variable for poppler
if (!globalParams) {
globalParams = new GlobalParams();
@@ -602,7 +613,7 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
PDFDoc *pdf_doc = new PDFDoc(filename_goo, NULL, NULL, NULL); // TODO: Could ask for password
//delete filename_goo;
#else
- wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL);
+ wchar_t *wfilename = reinterpret_cast<wchar_t*>(g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL));
if (wfilename == NULL) {
return NULL;
@@ -646,6 +657,7 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
if (inkscape_use_gui()) {
dlg = new PdfImportDialog(pdf_doc, uri);
if (!dlg->showDialog()) {
+ _cancelled = true;
delete dlg;
delete pdf_doc;
return NULL;
@@ -736,6 +748,11 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
delete pdf_doc;
delete dlg;
+ // Set viewBox if it doesn't exist
+ if (!doc->getRoot()->viewBox_set) {
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit())));
+ }
+
// Restore undo
DocumentUndo::setUndoSensitive(doc, saved);
diff --git a/src/extension/internal/pdfinput/pdf-input.h b/src/extension/internal/pdfinput/pdf-input.h
index 3b79e6f29..f22a783ff 100644
--- a/src/extension/internal/pdfinput/pdf-input.h
+++ b/src/extension/internal/pdfinput/pdf-input.h
@@ -16,6 +16,10 @@
#ifdef HAVE_POPPLER
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/dialog.h>
#include "../../implementation/implementation.h"
@@ -39,7 +43,11 @@ namespace Gtk {
class DrawingArea;
class Frame;
class HBox;
+#if WITH_GTKMM_3_0
+ class Scale;
+#else
class HScale;
+#endif
class VBox;
class Label;
}
@@ -73,7 +81,11 @@ private:
void _setPreviewPage(int page);
// Signal handlers
+#if !WITH_GTKMM_3_0
bool _onExposePreview(GdkEventExpose *event);
+#endif
+
+ bool _onDraw(const Cairo::RefPtr<Cairo::Context>& cr);
void _onPageNumberChanged();
void _onToggleCropping();
void _onPrecisionChanged();
@@ -91,10 +103,11 @@ private:
class Inkscape::UI::Widget::Frame * _pageSettingsFrame;
class Gtk::Label * _labelPrecision;
class Gtk::Label * _labelPrecisionWarning;
- class Gtk::HScale * _fallbackPrecisionSlider;
#if WITH_GTKMM_3_0
+ class Gtk::Scale * _fallbackPrecisionSlider;
Glib::RefPtr<Gtk::Adjustment> _fallbackPrecisionSlider_adj;
#else
+ class Gtk::HScale * _fallbackPrecisionSlider;
class Gtk::Adjustment *_fallbackPrecisionSlider_adj;
#endif
class Gtk::Label * _labelPrecisionComment;
@@ -131,7 +144,9 @@ public:
SPDocument *open( Inkscape::Extension::Input *mod,
const gchar *uri );
static void init( void );
-
+ virtual bool wasCancelled();
+private:
+ bool _cancelled;
};
} // namespace Implementation
diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp
index 5e8b005e2..b398486e6 100644
--- a/src/extension/internal/pdfinput/pdf-parser.cpp
+++ b/src/extension/internal/pdfinput/pdf-parser.cpp
@@ -34,7 +34,7 @@ extern "C" {
#include "svg-builder.h"
#include "Gfx.h"
#include "pdf-parser.h"
-#include "unit-constants.h"
+#include "util/units.h"
#include "goo/gmem.h"
#include "goo/GooTimer.h"
@@ -76,10 +76,6 @@ extern "C" {
// Operator table
//------------------------------------------------------------------------
-#ifdef WIN32 // this works around a bug in the VC7 compiler
-# pragma optimize("",off)
-#endif
-
PdfOperator PdfParser::opTab[] = {
{"\"", 3, {tchkNum, tchkNum, tchkString},
&PdfParser::opMoveSetShowText},
@@ -249,10 +245,6 @@ PdfOperator PdfParser::opTab[] = {
&PdfParser::opCurveTo2}
};
-#ifdef WIN32 // this works around a bug in the VC7 compiler
-# pragma optimize("",on)
-#endif
-
#define numOps (sizeof(opTab) / sizeof(PdfOperator))
//------------------------------------------------------------------------
@@ -279,14 +271,14 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui
ignoreUndef = 0;
operatorHistory = NULL;
builder = builderA;
- builder->setDocumentSize(state->getPageWidth()*PX_PER_PT,
- state->getPageHeight()*PX_PER_PT);
+ builder->setDocumentSize(Inkscape::Util::Quantity::convert(state->getPageWidth(), "pt", "px"),
+ Inkscape::Util::Quantity::convert(state->getPageHeight(), "pt", "px"));
double *ctm = state->getCTM();
double scaledCTM[6];
for (int i = 0; i < 6; ++i) {
baseMatrix[i] = ctm[i];
- scaledCTM[i] = PX_PER_PT * ctm[i];
+ scaledCTM[i] = Inkscape::Util::Quantity::convert(ctm[i], "pt", "px");
}
saveState();
builder->setTransform((double*)&scaledCTM);
@@ -368,15 +360,23 @@ void PdfParser::parse(Object *obj, GBool topLevel) {
for (int i = 0; i < obj->arrayGetLength(); ++i) {
obj->arrayGet(i, &obj2);
if (!obj2.isStream()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errInternal, -1, "Weird page contents");
+#else
error(-1, const_cast<char*>("Weird page contents"));
+#endif
obj2.free();
return;
}
obj2.free();
}
} else if (!obj->isStream()) {
- error(-1, const_cast<char*>("Weird page contents"));
- return;
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errInternal, -1, "Weird page contents");
+#else
+ error(-1, const_cast<char*>("Weird page contents"));
+#endif
+ return;
}
parser = new Parser(xref, new Lexer(xref, obj), gFalse);
go(topLevel);
@@ -420,7 +420,11 @@ void PdfParser::go(GBool /*topLevel*/)
// too many arguments - something is wrong
} else {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Too many args in content stream");
+#else
error(getPos(), const_cast<char*>("Too many args in content stream"));
+#endif
if (printCommands) {
printf("throwing away arg: ");
obj.print(stdout);
@@ -437,7 +441,11 @@ void PdfParser::go(GBool /*topLevel*/)
// args at end with no command
if (numArgs > 0) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Leftover args in content stream");
+#else
error(getPos(), const_cast<char*>("Leftover args in content stream"));
+#endif
if (printCommands) {
printf("%d leftovers:", numArgs);
for (int i = 0; i < numArgs; ++i) {
@@ -503,7 +511,11 @@ void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
name = cmd->getCmd();
if (!(op = findOp(name))) {
if (ignoreUndef == 0)
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Unknown operator '{0:s}'", name);
+#else
error(getPos(), const_cast<char*>("Unknown operator '%s'"), name);
+#endif
return;
}
@@ -511,26 +523,42 @@ void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
argPtr = args;
if (op->numArgs >= 0) {
if (numArgs < op->numArgs) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Too few ({0:d}) args to '{1:d}' operator", numArgs, name);
+#else
error(getPos(), const_cast<char*>("Too few (%d) args to '%s' operator"), numArgs, name);
+#endif
return;
}
if (numArgs > op->numArgs) {
#if 0
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator", numArgs, name);
+#else
error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name);
#endif
+#endif
argPtr += numArgs - op->numArgs;
numArgs = op->numArgs;
}
} else {
if (numArgs > -op->numArgs) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator",
+#else
error(getPos(), const_cast<char*>("Too many (%d) args to '%s' operator"),
+#endif
numArgs, name);
return;
}
}
for (i = 0; i < numArgs; ++i) {
if (!checkArg(&argPtr[i], op->tchk[i])) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Arg #{0:d} to '{1:s}' operator is wrong type ({2:s})",
+#else
error(getPos(), const_cast<char*>("Arg #%d to '%s' operator is wrong type (%s)"),
+#endif
i, name, argPtr[i].getTypeName());
return;
}
@@ -543,14 +571,13 @@ void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
(this->*op->func)(argPtr, numArgs);
}
-PdfOperator *PdfParser::findOp(char *name) {
- int a, b, m, cmp;
-
- a = -1;
- b = numOps;
+PdfOperator* PdfParser::findOp(char *name) {
+ int a = -1;
+ int b = numOps;
+ int cmp = -1;
// invariant: opTab[a] < name < opTab[b]
while (b - a > 1) {
- m = (a + b) / 2;
+ const int m = (a + b) / 2;
cmp = strcmp(opTab[m].name, name);
if (cmp < 0)
a = m;
@@ -700,7 +727,11 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
return;
}
if (!obj1.isDict()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "ExtGState '{0:s}' is wrong type"), args[0].getName();
+#else
error(getPos(), const_cast<char*>("ExtGState '%s' is wrong type"), args[0].getName());
+#endif
obj1.free();
return;
}
@@ -716,7 +747,11 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
if (state->parseBlendMode(&obj2, &mode)) {
state->setBlendMode(mode);
} else {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
+#else
error(getPos(), const_cast<char*>("Invalid blend mode in ExtGState"));
+#endif
}
}
obj2.free();
@@ -778,7 +813,11 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
state->setTransfer(funcs);
}
} else if (!obj2.isNull()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Invalid transfer function in ExtGState");
+#else
error(getPos(), const_cast<char*>("Invalid transfer function in ExtGState"));
+#endif
}
obj2.free();
@@ -798,8 +837,11 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
funcs[0] = Function::parse(&obj3);
if (funcs[0]->getInputSize() != 1 ||
funcs[0]->getOutputSize() != 1) {
- error(getPos(),
- const_cast<char*>("Invalid transfer function in soft mask in ExtGState"));
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Invalid transfer function in soft mask in ExtGState");
+#else
+ error(getPos(), const_cast<char*>("Invalid transfer function in soft mask in ExtGState"));
+#endif
delete funcs[0];
funcs[0] = NULL;
}
@@ -824,7 +866,7 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
GBool isolated = gFalse;
GBool knockout = gFalse;
if (!obj4.dictLookup(const_cast<char*>("CS"), &obj5)->isNull()) {
-#ifdef POPPLER_NEW_COLOR_SPACE_API
+#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
blendingColorSpace = GfxColorSpace::parse(&obj5, NULL);
#else
blendingColorSpace = GfxColorSpace::parse(&obj5);
@@ -855,15 +897,27 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
delete funcs[0];
}
} else {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
+#else
error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
+#endif
}
obj4.free();
} else {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
+#else
error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
+#endif
}
obj3.free();
} else if (!obj2.isNull()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState");
+#else
error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState"));
+#endif
}
}
obj2.free();
@@ -891,7 +945,11 @@ void PdfParser::doSoftMask(Object *str, GBool alpha,
// check form type
dict->lookup(const_cast<char*>("FormType"), &obj1);
if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Unknown form type");
+#else
error(getPos(), const_cast<char*>("Unknown form type"));
+#endif
}
obj1.free();
@@ -899,7 +957,11 @@ void PdfParser::doSoftMask(Object *str, GBool alpha,
dict->lookup(const_cast<char*>("BBox"), &obj1);
if (!obj1.isArray()) {
obj1.free();
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Bad form bounding box");
+#else
error(getPos(), const_cast<char*>("Bad form bounding box"));
+#endif
return;
}
for (i = 0; i < 4; ++i) {
@@ -1038,7 +1100,7 @@ void PdfParser::opSetFillColorSpace(Object args[], int /*numArgs*/)
res->lookupColorSpace(args[0].getName(), &obj);
GfxColorSpace *colorSpace = 0;
-#ifdef POPPLER_NEW_COLOR_SPACE_API
+#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
if (obj.isNull()) {
colorSpace = GfxColorSpace::parse(&args[0], NULL);
} else {
@@ -1059,7 +1121,11 @@ void PdfParser::opSetFillColorSpace(Object args[], int /*numArgs*/)
state->setFillColor(&color);
builder->updateStyle(state);
} else {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Bad color space (fill)");
+#else
error(getPos(), const_cast<char*>("Bad color space (fill)"));
+#endif
}
}
@@ -1071,7 +1137,7 @@ void PdfParser::opSetStrokeColorSpace(Object args[], int /*numArgs*/)
state->setStrokePattern(NULL);
res->lookupColorSpace(args[0].getName(), &obj);
-#ifdef POPPLER_NEW_COLOR_SPACE_API
+#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
if (obj.isNull()) {
colorSpace = GfxColorSpace::parse(&args[0], NULL);
} else {
@@ -1092,7 +1158,11 @@ void PdfParser::opSetStrokeColorSpace(Object args[], int /*numArgs*/)
state->setStrokeColor(&color);
builder->updateStyle(state);
} else {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Bad color space (stroke)");
+#else
error(getPos(), const_cast<char*>("Bad color space (stroke)"));
+#endif
}
}
@@ -1101,7 +1171,11 @@ void PdfParser::opSetFillColor(Object args[], int numArgs) {
int i;
if (numArgs != state->getFillColorSpace()->getNComps()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'sc' command");
+#else
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'sc' command"));
+#endif
return;
}
state->setFillPattern(NULL);
@@ -1117,7 +1191,11 @@ void PdfParser::opSetStrokeColor(Object args[], int numArgs) {
int i;
if (numArgs != state->getStrokeColorSpace()->getNComps()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SC' command");
+#else
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SC' command"));
+#endif
return;
}
state->setStrokePattern(NULL);
@@ -1130,7 +1208,6 @@ void PdfParser::opSetStrokeColor(Object args[], int numArgs) {
void PdfParser::opSetFillColorN(Object args[], int numArgs) {
GfxColor color;
- GfxPattern *pattern;
int i;
if (state->getFillColorSpace()->getMode() == csPattern) {
@@ -1138,7 +1215,11 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) {
if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() ||
numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace())
->getUnder()->getNComps()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
+#else
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
+#endif
return;
}
for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
@@ -1149,7 +1230,8 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) {
state->setFillColor(&color);
builder->updateStyle(state);
}
-#ifdef POPPLER_NEW_COLOR_SPACE_API
+ GfxPattern *pattern;
+#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
if (args[numArgs-1].isName() &&
(pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
state->setFillPattern(pattern);
@@ -1165,7 +1247,11 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) {
} else {
if (numArgs != state->getFillColorSpace()->getNComps()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
+#else
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
+#endif
return;
}
state->setFillPattern(NULL);
@@ -1181,7 +1267,6 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) {
void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
GfxColor color;
- GfxPattern *pattern;
int i;
if (state->getStrokeColorSpace()->getMode() == csPattern) {
@@ -1190,7 +1275,11 @@ void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
->getUnder() ||
numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace())
->getUnder()->getNComps()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
+#else
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
+#endif
return;
}
for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
@@ -1201,7 +1290,8 @@ void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
state->setStrokeColor(&color);
builder->updateStyle(state);
}
-#ifdef POPPLER_NEW_COLOR_SPACE_API
+ GfxPattern *pattern;
+#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
if (args[numArgs-1].isName() &&
(pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
state->setStrokePattern(pattern);
@@ -1217,7 +1307,11 @@ void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
} else {
if (numArgs != state->getStrokeColorSpace()->getNComps()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
+#else
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
+#endif
return;
}
state->setStrokePattern(NULL);
@@ -1245,7 +1339,11 @@ void PdfParser::opMoveTo(Object args[], int /*numArgs*/)
void PdfParser::opLineTo(Object args[], int /*numArgs*/)
{
if (!state->isCurPt()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "No current point in lineto");
+#else
error(getPos(), const_cast<char*>("No current point in lineto"));
+#endif
return;
}
state->lineTo(args[0].getNum(), args[1].getNum());
@@ -1255,7 +1353,11 @@ void PdfParser::opLineTo(Object args[], int /*numArgs*/)
void PdfParser::opCurveTo(Object args[], int /*numArgs*/)
{
if (!state->isCurPt()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "No current point in curveto");
+#else
error(getPos(), const_cast<char*>("No current point in curveto"));
+#endif
return;
}
double x1 = args[0].getNum();
@@ -1271,7 +1373,11 @@ void PdfParser::opCurveTo(Object args[], int /*numArgs*/)
void PdfParser::opCurveTo1(Object args[], int /*numArgs*/)
{
if (!state->isCurPt()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "No current point in curveto1");
+#else
error(getPos(), const_cast<char*>("No current point in curveto1"));
+#endif
return;
}
double x1 = state->getCurX();
@@ -1287,7 +1393,11 @@ void PdfParser::opCurveTo1(Object args[], int /*numArgs*/)
void PdfParser::opCurveTo2(Object args[], int /*numArgs*/)
{
if (!state->isCurPt()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "No current point in curveto2");
+#else
error(getPos(), const_cast<char*>("No current point in curveto2"));
+#endif
return;
}
double x1 = args[0].getNum();
@@ -1316,7 +1426,11 @@ void PdfParser::opRectangle(Object args[], int /*numArgs*/)
void PdfParser::opClosePath(Object /*args*/[], int /*numArgs*/)
{
if (!state->isCurPt()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "No current point in closepath");
+#else
error(getPos(), const_cast<char*>("No current point in closepath"));
+#endif
return;
}
state->closePath();
@@ -1482,7 +1596,11 @@ void PdfParser::doPatternFillFallback(GBool eoFill) {
doShadingPatternFillFallback(static_cast<GfxShadingPattern *>(pattern), gFalse, eoFill);
break;
default:
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errUnimplemented, getPos(), "Unimplemented pattern type (%d) in fill",
+#else
error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in fill"),
+#endif
pattern->getType());
break;
}
@@ -1501,7 +1619,11 @@ void PdfParser::doPatternStrokeFallback() {
doShadingPatternFillFallback(static_cast<GfxShadingPattern *>(pattern), gTrue, gFalse);
break;
default:
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errUnimplemented, getPos(), "Unimplemented pattern type ({0:d}) in stroke",
+#else
error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in stroke"),
+#endif
pattern->getType());
break;
}
@@ -1624,7 +1746,7 @@ void PdfParser::opShFill(Object args[], int /*numArgs*/)
double *matrix = NULL;
GBool savedState = gFalse;
-#ifdef POPPLER_NEW_COLOR_SPACE_API
+#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
if (!(shading = res->lookupShading(args[0].getName(), NULL))) {
return;
}
@@ -2244,7 +2366,11 @@ void PdfParser::opTextNextLine(Object /*args*/[], int /*numArgs*/)
void PdfParser::opShowText(Object args[], int /*numArgs*/)
{
if (!state->getFont()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "No font in show");
+#else
error(getPos(), const_cast<char*>("No font in show"));
+#endif
return;
}
if (fontChanged) {
@@ -2261,7 +2387,11 @@ void PdfParser::opMoveShowText(Object args[], int /*numArgs*/)
double ty = 0;
if (!state->getFont()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "No font in move/show");
+#else
error(getPos(), const_cast<char*>("No font in move/show"));
+#endif
return;
}
if (fontChanged) {
@@ -2282,7 +2412,11 @@ void PdfParser::opMoveSetShowText(Object args[], int /*numArgs*/)
double ty = 0;
if (!state->getFont()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "No font in move/set/show");
+#else
error(getPos(), const_cast<char*>("No font in move/set/show"));
+#endif
return;
}
if (fontChanged) {
@@ -2306,7 +2440,11 @@ void PdfParser::opShowSpaceText(Object args[], int /*numArgs*/)
int wMode = 0;
if (!state->getFont()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "No font in show/space");
+#else
error(getPos(), const_cast<char*>("No font in show/space"));
+#endif
return;
}
if (fontChanged) {
@@ -2331,7 +2469,11 @@ void PdfParser::opShowSpaceText(Object args[], int /*numArgs*/)
} else if (obj.isString()) {
doShowText(obj.getString());
} else {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Element of show/space array must be number or string");
+#else
error(getPos(), const_cast<char*>("Element of show/space array must be number or string"));
+#endif
}
obj.free();
}
@@ -2429,7 +2571,11 @@ void PdfParser::doShowText(GooString *s) {
if (charProc.isStream()) {
//parse(&charProc, gFalse); // TODO: parse into SVG font
} else {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Missing or bad Type3 CharProc entry");
+#else
error(getPos(), const_cast<char*>("Missing or bad Type3 CharProc entry"));
+#endif
}
//out->endType3Char(state);
if (resDict) {
@@ -2506,7 +2652,11 @@ void PdfParser::opXObject(Object args[], int /*numArgs*/)
return;
}
if (!obj1.isStream()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "XObject '{0:s}' is wrong type", name);
+#else
error(getPos(), const_cast<char*>("XObject '%s' is wrong type"), name);
+#endif
obj1.free();
return;
}
@@ -2522,9 +2672,17 @@ void PdfParser::opXObject(Object args[], int /*numArgs*/)
/* out->psXObject(obj1.getStream(),
obj3.isStream() ? obj3.getStream() : (Stream *)NULL);*/
} else if (obj2.isName()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Unknown XObject subtype '{0:s}'", obj2.getName());
+#else
error(getPos(), const_cast<char*>("Unknown XObject subtype '%s'"), obj2.getName());
+#endif
} else {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "XObject subtype is missing or wrong type");
+#else
error(getPos(), const_cast<char*>("XObject subtype is missing or wrong type"));
+#endif
}
obj2.free();
obj1.free();
@@ -2532,330 +2690,339 @@ void PdfParser::opXObject(Object args[], int /*numArgs*/)
void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg)
{
- Dict *dict, *maskDict;
- int width, height;
- int bits;
- StreamColorSpaceMode csMode;
- GBool mask;
- GBool invert;
- GfxColorSpace *colorSpace, *maskColorSpace;
- GfxImageColorMap *colorMap, *maskColorMap;
- Object maskObj, smaskObj;
- GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
- int maskColors[2*gfxColorMaxComps];
- int maskWidth, maskHeight;
- GBool maskInvert;
- Stream *maskStr;
- Object obj1, obj2;
- int i;
-
- // get info from the stream
- bits = 0;
- csMode = streamCSNone;
- str->getImageParams(&bits, &csMode);
-
- // get stream dict
- dict = str->getDict();
-
- // get size
- dict->lookup(const_cast<char*>("Width"), &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup(const_cast<char*>("W"), &obj1);
- }
- if (obj1.isInt())
- width = obj1.getInt();
- else if (obj1.isReal())
- width = (int)obj1.getReal();
- else
- goto err2;
- obj1.free();
- dict->lookup(const_cast<char*>("Height"), &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup(const_cast<char*>("H"), &obj1);
- }
- if (obj1.isInt())
- height = obj1.getInt();
- else if (obj1.isReal())
- height = (int)obj1.getReal();
- else
- goto err2;
- obj1.free();
-
- // image or mask?
- dict->lookup(const_cast<char*>("ImageMask"), &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup(const_cast<char*>("IM"), &obj1);
- }
- mask = gFalse;
- if (obj1.isBool())
- mask = obj1.getBool();
- else if (!obj1.isNull())
- goto err2;
- obj1.free();
-
- // bit depth
- if (bits == 0) {
- dict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
+ Dict *dict;
+ int width, height;
+ int bits;
+ StreamColorSpaceMode csMode;
+ GBool mask;
+ GBool invert;
+ Object maskObj, smaskObj;
+ GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
+ GBool maskInvert;
+ Object obj1, obj2;
+
+ // get info from the stream
+ bits = 0;
+ csMode = streamCSNone;
+ str->getImageParams(&bits, &csMode);
+
+ // get stream dict
+ dict = str->getDict();
+
+ // get size
+ dict->lookup(const_cast<char*>("Width"), &obj1);
if (obj1.isNull()) {
- obj1.free();
- dict->lookup(const_cast<char*>("BPC"), &obj1);
+ obj1.free();
+ dict->lookup(const_cast<char*>("W"), &obj1);
}
- if (obj1.isInt()) {
- bits = obj1.getInt();
- } else if (mask) {
- bits = 1;
- } else {
- goto err2;
+ if (obj1.isInt()){
+ width = obj1.getInt();
}
- obj1.free();
- }
-
- // display a mask
- if (mask) {
-
- // check for inverted mask
- if (bits != 1)
- goto err1;
- invert = gFalse;
- dict->lookup(const_cast<char*>("Decode"), &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup(const_cast<char*>("D"), &obj1);
+ else if (obj1.isReal()) {
+ width = (int)obj1.getReal();
}
- if (obj1.isArray()) {
- obj1.arrayGet(0, &obj2);
- if (obj2.isInt() && obj2.getInt() == 1)
- invert = gTrue;
- obj2.free();
- } else if (!obj1.isNull()) {
- goto err2;
+ else {
+ goto err2;
}
obj1.free();
-
- // draw it
- builder->addImageMask(state, str, width, height, invert);
-
- } else {
-
- // get color space and color map
- dict->lookup(const_cast<char*>("ColorSpace"), &obj1);
+ dict->lookup(const_cast<char*>("Height"), &obj1);
if (obj1.isNull()) {
- obj1.free();
- dict->lookup(const_cast<char*>("CS"), &obj1);
+ obj1.free();
+ dict->lookup(const_cast<char*>("H"), &obj1);
}
- if (obj1.isName()) {
- res->lookupColorSpace(obj1.getName(), &obj2);
- if (!obj2.isNull()) {
- obj1.free();
- obj1 = obj2;
- } else {
- obj2.free();
- }
+ if (obj1.isInt()) {
+ height = obj1.getInt();
}
- if (!obj1.isNull()) {
-#ifdef POPPLER_NEW_COLOR_SPACE_API
- colorSpace = GfxColorSpace::parse(&obj1, NULL);
-#else
- colorSpace = GfxColorSpace::parse(&obj1);
-#endif
- } else if (csMode == streamCSDeviceGray) {
- colorSpace = new GfxDeviceGrayColorSpace();
- } else if (csMode == streamCSDeviceRGB) {
- colorSpace = new GfxDeviceRGBColorSpace();
- } else if (csMode == streamCSDeviceCMYK) {
- colorSpace = new GfxDeviceCMYKColorSpace();
- } else {
- colorSpace = NULL;
+ else if (obj1.isReal()){
+ height = static_cast<int>(obj1.getReal());
}
- obj1.free();
- if (!colorSpace) {
- goto err1;
+ else {
+ goto err2;
}
- dict->lookup(const_cast<char*>("Decode"), &obj1);
+ obj1.free();
+
+ // image or mask?
+ dict->lookup(const_cast<char*>("ImageMask"), &obj1);
if (obj1.isNull()) {
- obj1.free();
- dict->lookup(const_cast<char*>("D"), &obj1);
+ obj1.free();
+ dict->lookup(const_cast<char*>("IM"), &obj1);
+ }
+ mask = gFalse;
+ if (obj1.isBool()) {
+ mask = obj1.getBool();
+ }
+ else if (!obj1.isNull()) {
+ goto err2;
}
- colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
obj1.free();
- if (!colorMap->isOk()) {
- delete colorMap;
- goto err1;
- }
-
- // get the mask
- haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse;
- maskStr = NULL; // make gcc happy
- maskWidth = maskHeight = 0; // make gcc happy
- maskInvert = gFalse; // make gcc happy
- maskColorMap = NULL; // make gcc happy
- dict->lookup(const_cast<char*>("Mask"), &maskObj);
- dict->lookup(const_cast<char*>("SMask"), &smaskObj);
- if (smaskObj.isStream()) {
- // soft mask
- if (inlineImg) {
- goto err1;
- }
- maskStr = smaskObj.getStream();
- maskDict = smaskObj.streamGetDict();
- maskDict->lookup(const_cast<char*>("Width"), &obj1);
+
+ // bit depth
+ if (bits == 0) {
+ dict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
if (obj1.isNull()) {
- obj1.free();
- maskDict->lookup(const_cast<char*>("W"), &obj1);
+ obj1.free();
+ dict->lookup(const_cast<char*>("BPC"), &obj1);
}
- if (!obj1.isInt()) {
- goto err2;
+ if (obj1.isInt()) {
+ bits = obj1.getInt();
+ } else if (mask) {
+ bits = 1;
+ } else {
+ goto err2;
}
- maskWidth = obj1.getInt();
obj1.free();
- maskDict->lookup(const_cast<char*>("Height"), &obj1);
- if (obj1.isNull()) {
- obj1.free();
- maskDict->lookup(const_cast<char*>("H"), &obj1);
- }
- if (!obj1.isInt()) {
- goto err2;
+ }
+
+ // display a mask
+ if (mask) {
+ // check for inverted mask
+ if (bits != 1) {
+ goto err1;
}
- maskHeight = obj1.getInt();
- obj1.free();
- maskDict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
+ invert = gFalse;
+ dict->lookup(const_cast<char*>("Decode"), &obj1);
if (obj1.isNull()) {
- obj1.free();
- maskDict->lookup(const_cast<char*>("BPC"), &obj1);
+ obj1.free();
+ dict->lookup(const_cast<char*>("D"), &obj1);
}
- if (!obj1.isInt()) {
- goto err2;
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isInt() && obj2.getInt() == 1) {
+ invert = gTrue;
+ }
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
}
- int maskBits = obj1.getInt();
obj1.free();
- maskDict->lookup(const_cast<char*>("ColorSpace"), &obj1);
+
+ // draw it
+ builder->addImageMask(state, str, width, height, invert);
+
+ } else {
+ // get color space and color map
+ GfxColorSpace *colorSpace;
+ dict->lookup(const_cast<char*>("ColorSpace"), &obj1);
if (obj1.isNull()) {
- obj1.free();
- maskDict->lookup(const_cast<char*>("CS"), &obj1);
+ obj1.free();
+ dict->lookup(const_cast<char*>("CS"), &obj1);
}
if (obj1.isName()) {
- res->lookupColorSpace(obj1.getName(), &obj2);
- if (!obj2.isNull()) {
+ res->lookupColorSpace(obj1.getName(), &obj2);
+ if (!obj2.isNull()) {
obj1.free();
obj1 = obj2;
- } else {
+ } else {
obj2.free();
- }
+ }
}
-#ifdef POPPLER_NEW_COLOR_SPACE_API
- maskColorSpace = GfxColorSpace::parse(&obj1, NULL);
+ if (!obj1.isNull()) {
+#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
+ colorSpace = GfxColorSpace::parse(&obj1, NULL);
#else
- maskColorSpace = GfxColorSpace::parse(&obj1);
+ colorSpace = GfxColorSpace::parse(&obj1);
#endif
+ } else if (csMode == streamCSDeviceGray) {
+ colorSpace = new GfxDeviceGrayColorSpace();
+ } else if (csMode == streamCSDeviceRGB) {
+ colorSpace = new GfxDeviceRGBColorSpace();
+ } else if (csMode == streamCSDeviceCMYK) {
+ colorSpace = new GfxDeviceCMYKColorSpace();
+ } else {
+ colorSpace = NULL;
+ }
obj1.free();
- if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
+ if (!colorSpace) {
goto err1;
}
- maskDict->lookup(const_cast<char*>("Decode"), &obj1);
+ dict->lookup(const_cast<char*>("Decode"), &obj1);
if (obj1.isNull()) {
- obj1.free();
- maskDict->lookup(const_cast<char*>("D"), &obj1);
+ obj1.free();
+ dict->lookup(const_cast<char*>("D"), &obj1);
}
- maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
+ GfxImageColorMap *colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
obj1.free();
- if (!maskColorMap->isOk()) {
- delete maskColorMap;
+ if (!colorMap->isOk()) {
+ delete colorMap;
goto err1;
}
- //~ handle the Matte entry
- haveSoftMask = gTrue;
- } else if (maskObj.isArray()) {
- // color key mask
- for (i = 0;
- i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
- ++i) {
- maskObj.arrayGet(i, &obj1);
- maskColors[i] = obj1.getInt();
- obj1.free();
- }
- haveColorKeyMask = gTrue;
- } else if (maskObj.isStream()) {
- // explicit mask
- if (inlineImg) {
- goto err1;
- }
- maskStr = maskObj.getStream();
- maskDict = maskObj.streamGetDict();
- maskDict->lookup(const_cast<char*>("Width"), &obj1);
- if (obj1.isNull()) {
- obj1.free();
- maskDict->lookup(const_cast<char*>("W"), &obj1);
- }
- if (!obj1.isInt()) {
- goto err2;
- }
- maskWidth = obj1.getInt();
- obj1.free();
- maskDict->lookup(const_cast<char*>("Height"), &obj1);
- if (obj1.isNull()) {
- obj1.free();
- maskDict->lookup(const_cast<char*>("H"), &obj1);
- }
- if (!obj1.isInt()) {
- goto err2;
- }
- maskHeight = obj1.getInt();
- obj1.free();
- maskDict->lookup(const_cast<char*>("ImageMask"), &obj1);
- if (obj1.isNull()) {
- obj1.free();
- maskDict->lookup(const_cast<char*>("IM"), &obj1);
- }
- if (!obj1.isBool() || !obj1.getBool()) {
- goto err2;
- }
- obj1.free();
- maskInvert = gFalse;
- maskDict->lookup(const_cast<char*>("Decode"), &obj1);
- if (obj1.isNull()) {
- obj1.free();
- maskDict->lookup(const_cast<char*>("D"), &obj1);
- }
- if (obj1.isArray()) {
- obj1.arrayGet(0, &obj2);
- if (obj2.isInt() && obj2.getInt() == 1) {
- maskInvert = gTrue;
- }
- obj2.free();
- } else if (!obj1.isNull()) {
- goto err2;
- }
- obj1.free();
- haveExplicitMask = gTrue;
- }
-
- // draw it
- if (haveSoftMask) {
- builder->addSoftMaskedImage(state, str, width, height, colorMap,
+
+ // get the mask
+ int maskColors[2*gfxColorMaxComps];
+ haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse;
+ Stream *maskStr = NULL;
+ int maskWidth = 0;
+ int maskHeight = 0;
+ maskInvert = gFalse;
+ GfxImageColorMap *maskColorMap = NULL;
+ dict->lookup(const_cast<char*>("Mask"), &maskObj);
+ dict->lookup(const_cast<char*>("SMask"), &smaskObj);
+ Dict* maskDict;
+ if (smaskObj.isStream()) {
+ // soft mask
+ if (inlineImg) {
+ goto err1;
+ }
+ maskStr = smaskObj.getStream();
+ maskDict = smaskObj.streamGetDict();
+ maskDict->lookup(const_cast<char*>("Width"), &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("W"), &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskWidth = obj1.getInt();
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("Height"), &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("H"), &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskHeight = obj1.getInt();
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("BPC"), &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ int maskBits = obj1.getInt();
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("ColorSpace"), &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("CS"), &obj1);
+ }
+ if (obj1.isName()) {
+ res->lookupColorSpace(obj1.getName(), &obj2);
+ if (!obj2.isNull()) {
+ obj1.free();
+ obj1 = obj2;
+ } else {
+ obj2.free();
+ }
+ }
+#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
+ GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1, NULL);
+#else
+ GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1);
+#endif
+ obj1.free();
+ if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
+ goto err1;
+ }
+ maskDict->lookup(const_cast<char*>("Decode"), &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("D"), &obj1);
+ }
+ maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
+ obj1.free();
+ if (!maskColorMap->isOk()) {
+ delete maskColorMap;
+ goto err1;
+ }
+ //~ handle the Matte entry
+ haveSoftMask = gTrue;
+ } else if (maskObj.isArray()) {
+ // color key mask
+ int i;
+ for (i = 0; i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps; ++i) {
+ maskObj.arrayGet(i, &obj1);
+ maskColors[i] = obj1.getInt();
+ obj1.free();
+ }
+ haveColorKeyMask = gTrue;
+ } else if (maskObj.isStream()) {
+ // explicit mask
+ if (inlineImg) {
+ goto err1;
+ }
+ maskStr = maskObj.getStream();
+ maskDict = maskObj.streamGetDict();
+ maskDict->lookup(const_cast<char*>("Width"), &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("W"), &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskWidth = obj1.getInt();
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("Height"), &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("H"), &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskHeight = obj1.getInt();
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("ImageMask"), &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("IM"), &obj1);
+ }
+ if (!obj1.isBool() || !obj1.getBool()) {
+ goto err2;
+ }
+ obj1.free();
+ maskInvert = gFalse;
+ maskDict->lookup(const_cast<char*>("Decode"), &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup(const_cast<char*>("D"), &obj1);
+ }
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isInt() && obj2.getInt() == 1) {
+ maskInvert = gTrue;
+ }
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
+ }
+ obj1.free();
+ haveExplicitMask = gTrue;
+ }
+
+ // draw it
+ if (haveSoftMask) {
+ builder->addSoftMaskedImage(state, str, width, height, colorMap,
maskStr, maskWidth, maskHeight, maskColorMap);
- delete maskColorMap;
- } else if (haveExplicitMask) {
- builder->addMaskedImage(state, str, width, height, colorMap,
+ delete maskColorMap;
+ } else if (haveExplicitMask) {
+ builder->addMaskedImage(state, str, width, height, colorMap,
maskStr, maskWidth, maskHeight, maskInvert);
- } else {
- builder->addImage(state, str, width, height, colorMap,
- haveColorKeyMask ? maskColors : (int *)NULL);
+ } else {
+ builder->addImage(state, str, width, height, colorMap,
+ haveColorKeyMask ? maskColors : static_cast<int *>(NULL));
+ }
+ delete colorMap;
+
+ maskObj.free();
+ smaskObj.free();
}
- delete colorMap;
-
- maskObj.free();
- smaskObj.free();
- }
- return;
+ return;
err2:
- obj1.free();
+ obj1.free();
err1:
- error(getPos(), const_cast<char*>("Bad image parameters"));
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Bad image parameters");
+#else
+ error(getPos(), const_cast<char*>("Bad image parameters"));
+#endif
}
void PdfParser::doForm(Object *str) {
@@ -2880,7 +3047,11 @@ void PdfParser::doForm(Object *str) {
// check form type
dict->lookup(const_cast<char*>("FormType"), &obj1);
if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Unknown form type");
+#else
error(getPos(), const_cast<char*>("Unknown form type"));
+#endif
}
obj1.free();
@@ -2888,7 +3059,11 @@ void PdfParser::doForm(Object *str) {
dict->lookup(const_cast<char*>("BBox"), &bboxObj);
if (!bboxObj.isArray()) {
bboxObj.free();
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Bad form bounding box");
+#else
error(getPos(), const_cast<char*>("Bad form bounding box"));
+#endif
return;
}
for (i = 0; i < 4; ++i) {
@@ -2924,7 +3099,7 @@ void PdfParser::doForm(Object *str) {
if (obj1.dictLookup(const_cast<char*>("S"), &obj2)->isName(const_cast<char*>("Transparency"))) {
transpGroup = gTrue;
if (!obj1.dictLookup(const_cast<char*>("CS"), &obj3)->isNull()) {
-#ifdef POPPLER_NEW_COLOR_SPACE_API
+#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
blendingColorSpace = GfxColorSpace::parse(&obj3, NULL);
#else
blendingColorSpace = GfxColorSpace::parse(&obj3);
@@ -3085,7 +3260,11 @@ Stream *PdfParser::buildImageStream() {
parser->getObj(&obj);
while (!obj.isCmd(const_cast<char*>("ID")) && !obj.isEOF()) {
if (!obj.isName()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "Inline image dictionary key must be a name object");
+#else
error(getPos(), const_cast<char*>("Inline image dictionary key must be a name object"));
+#endif
obj.free();
} else {
key = copyString(obj.getName());
@@ -3100,7 +3279,11 @@ Stream *PdfParser::buildImageStream() {
parser->getObj(&obj);
}
if (obj.isEOF()) {
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errSyntaxError, getPos(), "End of file in inline image");
+#else
error(getPos(), const_cast<char*>("End of file in inline image"));
+#endif
obj.free();
dict.free();
return NULL;
@@ -3116,12 +3299,20 @@ Stream *PdfParser::buildImageStream() {
void PdfParser::opImageData(Object /*args*/[], int /*numArgs*/)
{
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errInternal, getPos(), "Internal: got 'ID' operator");
+#else
error(getPos(), const_cast<char*>("Internal: got 'ID' operator"));
+#endif
}
void PdfParser::opEndImage(Object /*args*/[], int /*numArgs*/)
{
+#ifdef POPPLER_NEW_ERRORAPI
+ error(errInternal, getPos(), "Internal: got 'EI' operator");
+#else
error(getPos(), const_cast<char*>("Internal: got 'EI' operator"));
+#endif
}
//------------------------------------------------------------------------
@@ -3198,9 +3389,22 @@ void PdfParser::opMarkPoint(Object args[], int numArgs) {
//------------------------------------------------------------------------
void PdfParser::saveState() {
+ bool is_radial = false;
+
+ GfxPattern *pattern = state->getFillPattern();
+ if (pattern != NULL)
+ if (pattern->getType() == 2 ) {
+ GfxShadingPattern *shading_pattern = static_cast<GfxShadingPattern *>(pattern);
+ GfxShading *shading = shading_pattern->getShading();
+ if (shading->getType() == 3)
+ is_radial = true;
+ }
+
builder->saveState();
-// state = state->save(); // nasty hack to prevent GfxRadialShading from getting corrupted during copy operation
- state->save(); // see LP Bug 919176 comment 8
+ if (is_radial)
+ state->save(); // nasty hack to prevent GfxRadialShading from getting corrupted during copy operation
+ else
+ state = state->save(); // see LP Bug 919176 comment 8
clipHistory = clipHistory->save();
}
diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp
index 2f36e19a4..71e6dc6ae 100644
--- a/src/extension/internal/pdfinput/svg-builder.cpp
+++ b/src/extension/internal/pdfinput/svg-builder.cpp
@@ -33,7 +33,7 @@
#include "svg/css-ostringstream.h"
#include "svg/svg-color.h"
#include "color.h"
-#include "unit-constants.h"
+#include "util/units.h"
#include "io/stringstream.h"
#include "io/base64stream.h"
#include "display/nr-filter-utils.h"
@@ -56,15 +56,12 @@ namespace Internal {
#define TRACE(_args) IFTRACE(g_print _args)
-static double ttm[6] = {1, 0, 0, 1, 0, 0}; // temporary transform matrix
-static bool ttm_is_set = false; // flag to forbid setting ttm
-
/**
* \struct SvgTransparencyGroup
* \brief Holds information about a PDF transparency group
*/
struct SvgTransparencyGroup {
- double bbox[6];
+ double bbox[6]; // TODO should this be 4?
Inkscape::XML::Node *container;
bool isolated;
@@ -94,6 +91,9 @@ SvgBuilder::SvgBuilder(SPDocument *document, gchar *docname, XRef *xref)
_preferences = _xml_doc->createElement("svgbuilder:prefs");
_preferences->setAttribute("embedImages", "1");
_preferences->setAttribute("localFonts", "1");
+
+ _ttm[0] = 1; _ttm[1] = 0; _ttm[2] = 0; _ttm[3] = 1; _ttm[4] = 0; _ttm[5] = 0;
+ _ttm_is_set = false;
}
SvgBuilder::SvgBuilder(SvgBuilder *parent, Inkscape::XML::Node *root) {
@@ -216,9 +216,9 @@ Inkscape::XML::Node *SvgBuilder::pushGroup() {
}
}
if (_container->parent()->attribute("inkscape:groupmode") != NULL) {
- ttm[0] = ttm[3] = 1.0; // clear ttm if parent is a layer
- ttm[1] = ttm[2] = ttm[4] = ttm[5] = 0.0;
- ttm_is_set = false;
+ _ttm[0] = _ttm[3] = 1.0; // clear ttm if parent is a layer
+ _ttm[1] = _ttm[2] = _ttm[4] = _ttm[5] = 0.0;
+ _ttm_is_set = false;
}
return _container;
}
@@ -266,14 +266,12 @@ static void svgSetTransform(Inkscape::XML::Node *node, double c0, double c1,
* \brief Generates a SVG path string from poppler's data structure
*/
static gchar *svgInterpretPath(GfxPath *path) {
- GfxSubpath *subpath;
Inkscape::SVG::PathString pathString;
- int i, j;
- for ( i = 0 ; i < path->getNumSubpaths() ; ++i ) {
- subpath = path->getSubpath(i);
+ for (int i = 0 ; i < path->getNumSubpaths() ; ++i ) {
+ GfxSubpath *subpath = path->getSubpath(i);
if (subpath->getNumPoints() > 0) {
pathString.moveTo(subpath->getX(0), subpath->getY(0));
- j = 1;
+ int j = 1;
while (j < subpath->getNumPoints()) {
if (subpath->getCurve(j)) {
pathString.curveTo(subpath->getX(j), subpath->getY(j),
@@ -300,14 +298,6 @@ static gchar *svgInterpretPath(GfxPath *path) {
* Uses the given SPCSSAttr for storing the style properties
*/
void SvgBuilder::_setStrokeStyle(SPCSSAttr *css, GfxState *state) {
-
- // Check line width
- if ( state->getLineWidth() <= 0.0 ) {
- // Ignore stroke
- sp_repr_css_set_property(css, "stroke", "none");
- return;
- }
-
// Stroke color/pattern
if ( state->getStrokeColorSpace()->getMode() == csPattern ) {
gchar *urltext = _createPattern(state->getStrokePattern(), state, true);
@@ -328,7 +318,14 @@ void SvgBuilder::_setStrokeStyle(SPCSSAttr *css, GfxState *state) {
// Line width
Inkscape::CSSOStringStream os_width;
- os_width << state->getLineWidth();
+ double lw = state->getLineWidth();
+ if (lw > 0.0) {
+ os_width << lw;
+ } else {
+ // emit a stroke which is 1px in toplevel user units
+ double pxw = Inkscape::Util::Quantity::convert(1.0, "pt", "px");
+ os_width << 1.0 / state->transformWidth(pxw);
+ }
sp_repr_css_set_property(css, "stroke-width", os_width.str().c_str());
// Line cap
@@ -572,14 +569,14 @@ bool SvgBuilder::getTransform(double *transform) {
void SvgBuilder::setTransform(double c0, double c1, double c2, double c3,
double c4, double c5) {
// do not remember the group which is a layer
- if ((_container->attribute("inkscape:groupmode") == NULL) && !ttm_is_set) {
- ttm[0] = c0;
- ttm[1] = c1;
- ttm[2] = c2;
- ttm[3] = c3;
- ttm[4] = c4;
- ttm[5] = c5;
- ttm_is_set = true;
+ if ((_container->attribute("inkscape:groupmode") == NULL) && !_ttm_is_set) {
+ _ttm[0] = c0;
+ _ttm[1] = c1;
+ _ttm[2] = c2;
+ _ttm[3] = c3;
+ _ttm[4] = c4;
+ _ttm[5] = c5;
+ _ttm_is_set = true;
}
// Avoid transforming a group with an already set clip-path
@@ -629,21 +626,21 @@ gchar *SvgBuilder::_createPattern(GfxPattern *pattern, GfxState *state, bool is_
if ( pattern->getType() == 2 ) { // Shading pattern
GfxShadingPattern *shading_pattern = static_cast<GfxShadingPattern *>(pattern);
double *ptm;
- double ittm[6]; // invert ttm
double m[6] = {1, 0, 0, 1, 0, 0};
double det;
// construct a (pattern space) -> (current space) transform matrix
ptm = shading_pattern->getMatrix();
- det = ttm[0] * ttm[3] - ttm[1] * ttm[2];
+ det = _ttm[0] * _ttm[3] - _ttm[1] * _ttm[2];
if (det) {
- ittm[0] = ttm[3] / det;
- ittm[1] = -ttm[1] / det;
- ittm[2] = -ttm[2] / det;
- ittm[3] = ttm[0] / det;
- ittm[4] = (ttm[2] * ttm[5] - ttm[3] * ttm[4]) / det;
- ittm[5] = (ttm[1] * ttm[4] - ttm[0] * ttm[5]) / det;
+ double ittm[6]; // invert ttm
+ ittm[0] = _ttm[3] / det;
+ ittm[1] = -_ttm[1] / det;
+ ittm[2] = -_ttm[2] / det;
+ ittm[3] = _ttm[0] / det;
+ ittm[4] = (_ttm[2] * _ttm[5] - _ttm[3] * _ttm[4]) / det;
+ ittm[5] = (_ttm[1] * _ttm[4] - _ttm[0] * _ttm[5]) / det;
m[0] = ptm[0] * ittm[0] + ptm[1] * ittm[2];
m[1] = ptm[0] * ittm[1] + ptm[1] * ittm[3];
m[2] = ptm[2] * ittm[0] + ptm[3] * ittm[2];
@@ -676,7 +673,25 @@ gchar *SvgBuilder::_createTilingPattern(GfxTilingPattern *tiling_pattern,
Inkscape::XML::Node *pattern_node = _xml_doc->createElement("svg:pattern");
// Set pattern transform matrix
double *p2u = tiling_pattern->getMatrix();
- Geom::Affine pat_matrix(p2u[0], p2u[1], p2u[2], p2u[3], p2u[4], p2u[5]);
+ double m[6] = {1, 0, 0, 1, 0, 0};
+ double det;
+ det = _ttm[0] * _ttm[3] - _ttm[1] * _ttm[2]; // see LP Bug 1168908
+ if (det) {
+ double ittm[6]; // invert ttm
+ ittm[0] = _ttm[3] / det;
+ ittm[1] = -_ttm[1] / det;
+ ittm[2] = -_ttm[2] / det;
+ ittm[3] = _ttm[0] / det;
+ ittm[4] = (_ttm[2] * _ttm[5] - _ttm[3] * _ttm[4]) / det;
+ ittm[5] = (_ttm[1] * _ttm[4] - _ttm[0] * _ttm[5]) / det;
+ m[0] = p2u[0] * ittm[0] + p2u[1] * ittm[2];
+ m[1] = p2u[0] * ittm[1] + p2u[1] * ittm[3];
+ m[2] = p2u[2] * ittm[0] + p2u[3] * ittm[2];
+ m[3] = p2u[2] * ittm[1] + p2u[3] * ittm[3];
+ m[4] = p2u[4] * ittm[0] + p2u[5] * ittm[2] + ittm[4];
+ m[5] = p2u[4] * ittm[1] + p2u[5] * ittm[3] + ittm[5];
+ }
+ Geom::Affine pat_matrix(m[0], m[1], m[2], m[3], m[4], m[5]);
gchar *transform_text = sp_svg_transform_write(pat_matrix);
pattern_node->setAttribute("patternTransform", transform_text);
g_free(transform_text);
@@ -777,7 +792,7 @@ gchar *SvgBuilder::_createGradient(GfxShading *shading, double *matrix, bool for
Geom::Affine pat_matrix(matrix[0], matrix[1], matrix[2], matrix[3],
matrix[4], matrix[5]);
if ( !for_shading && _is_top_level ) {
- Geom::Affine flip(1.0, 0.0, 0.0, -1.0, 0.0, _height * PT_PER_PX);
+ Geom::Affine flip(1.0, 0.0, 0.0, -1.0, 0.0, Inkscape::Util::Quantity::convert(_height, "px", "pt"));
pat_matrix *= flip;
}
gchar *transform_text = sp_svg_transform_write(pat_matrix);
@@ -1004,9 +1019,7 @@ void SvgBuilder::updateFont(GfxState *state) {
_font_style = sp_repr_css_attr_new();
GfxFont *font = state->getFont();
// Store original name
- if (font->getOrigName()) {
- _font_specification = font->getOrigName()->getCString();
- } else if (font->getName()) {
+ if (font->getName()) {
_font_specification = font->getName()->getCString();
} else {
_font_specification = (char*) "Arial";
@@ -1210,7 +1223,7 @@ void SvgBuilder::updateTextMatrix(GfxState *state) {
*/
void SvgBuilder::_flushText() {
// Ignore empty strings
- if ( _glyphs.size() < 1 ) {
+ if ( _glyphs.empty()) {
_glyphs.clear();
return;
}
@@ -1302,7 +1315,8 @@ void SvgBuilder::_flushText() {
sp_repr_css_set_property(glyph.style, "-inkscape-font-specification", properFontSpec.c_str());
// Set style and unref SPCSSAttr if it won't be needed anymore
- sp_repr_css_change(tspan_node, glyph.style, "style");
+ // assume all <tspan> nodes in a <text> node share the same style
+ sp_repr_css_change(text_node, glyph.style, "style");
if ( glyph.style_changed && i != _glyphs.begin() ) { // Free previous style
sp_repr_css_attr_unref((*prev_iterator).style);
}
@@ -1642,6 +1656,10 @@ Inkscape::XML::Node *SvgBuilder::_createImage(Stream *str, int width, int height
Inkscape::XML::Node *image_node = _xml_doc->createElement("svg:image");
sp_repr_set_svg_double(image_node, "width", 1);
sp_repr_set_svg_double(image_node, "height", 1);
+
+ // PS/PDF images are placed via a transformation matrix, no preserveAspectRatio used
+ image_node->setAttribute("preserveAspectRatio", "none");
+
// Set transformation
svgSetTransform(image_node, 1.0, 0.0, 0.0, -1.0, 0.0, 1.0);
@@ -1818,7 +1836,9 @@ void SvgBuilder::pushTransparencyGroup(GfxState * /*state*/, double *bbox,
// Setup new transparency group
SvgTransparencyGroup *transpGroup = new SvgTransparencyGroup;
- memcpy(&transpGroup->bbox, bbox, sizeof(bbox));
+ for (size_t i = 0; i < 4; i++) {
+ transpGroup->bbox[i] = bbox[i];
+ }
transpGroup->isolated = isolated;
transpGroup->knockout = knockout;
transpGroup->for_softmask = for_softmask;
diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h
index a550565d6..f1ce02cf0 100644
--- a/src/extension/internal/pdfinput/svg-builder.h
+++ b/src/extension/internal/pdfinput/svg-builder.h
@@ -19,7 +19,7 @@
class SPDocument;
namespace Inkscape {
namespace XML {
- class Document;
+ struct Document;
class Node;
}
}
@@ -31,10 +31,10 @@ namespace Inkscape {
#include "CharTypes.h"
class GooString;
class Function;
-struct GfxState;
-class GfxColor;
+class GfxState;
+struct GfxColor;
class GfxColorSpace;
-class GfxRGB;
+struct GfxRGB;
class GfxPath;
class GfxPattern;
class GfxTilingPattern;
@@ -223,6 +223,8 @@ private:
Inkscape::XML::Node *_preferences; // Preferences container node
double _width; // Document size in px
double _height; // Document size in px
+ double _ttm[6]; ///< temporary transform matrix
+ bool _ttm_is_set;
};
diff --git a/src/extension/internal/svg.cpp b/src/extension/internal/svg.cpp
index 9b1098afd..8b272af60 100644
--- a/src/extension/internal/svg.cpp
+++ b/src/extension/internal/svg.cpp
@@ -44,7 +44,7 @@ using Inkscape::XML::Node;
-void pruneExtendedAttributes( Inkscape::XML::Node *repr )
+static void pruneExtendedAttributes( Inkscape::XML::Node *repr )
{
if (repr) {
if ( repr->type() == Inkscape::XML::ELEMENT_NODE ) {
diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c
new file mode 100644
index 000000000..c62c83120
--- /dev/null
+++ b/src/extension/internal/text_reassemble.c
@@ -0,0 +1,2926 @@
+/**
+ @file text_reassemble.c
+
+\verbatim
+Method:
+ 1. For all ordered text objects which are sequential and share the same esc.
+ 2. For the first only pull x,y,esc and save, these define origin and rotation.
+ 3. Save the text object.
+ 4. Phase I: For all saved text objects construct lines.
+ 5. Check for allowed overlaps on sequential saved text object bounding rectangles.
+ 6 If found merge second with first, check next one.
+ 7. If not found, start a new complex (line).
+ 8. Phase II; for all lines construct paragraphs.
+ 9. Check alignment and line spacing of preceding line with current line.
+ 10. if alignment is the same, and line spacing is compatible merge current line into
+ current paragraph. Reaverage line spacing over all lines in paragraph. Check next one.
+ 11. If alignment does not match start a new paragraph.
+ (Test program)
+ 12. Over all phase II paragraphs
+ 13. Over all phase I lines in each paragraph.
+ 14. Over all text objects in each line.
+ Emit SVG corresponding to this construct to a file dump.svg.
+ (Conversion to other file types would be modeled on this example.)
+ 15. Clean up.
+ (General program)
+ Like for the Test program, but final representation may not be SVG.
+ Text object and bounding rectangle memory would all be released. If another set of
+ text will be processed then hang onto both Freetype and Fontconfig structures. If no
+ other text will be processed here, then also release Freetype structures. If the caller uses
+ Fontconfig elsewhere then do not release it, otherwise, do so.
+
+NOTE ON COORDINATES: x is positive to the right, y is positive down. So (0,0) is the upper left corner, and the
+lower left corner of a rectangle has a LARGER Y coordinate than the upper left. Ie, LL=(10,10) UR=(30,5) is typical.
+\endverbatim
+*/
+
+/*
+
+Compilation of test program (with all debugging output, but not loop testing):
+On Windows use:
+
+ gcc -Wall -DWIN32 -DTEST -DDBG_TR_PARA -DDBG_TR_INPUT \
+ -I. -I/c/progs/devlibs32/include -I/c/progs/devlibs32/include/freetype2\
+ -o text_reassemble text_reassemble.c uemf_utf.c \
+ -lfreetype6 -lfontconfig-1 -liconv -lm -L/c/progs/devlibs32/bin
+
+On Linux use:
+
+ gcc -Wall -DTEST -DDBG_TR_PARA -DDBG_TR_INPUT -I. -I/usr/include/freetype2 -o text_reassemble text_reassemble.c uemf_utf.c -lfreetype -lfontconfig -lm
+
+Compilation of object file only (Windows):
+
+ gcc -Wall -DWIN32 -c \
+ -I. -I/c/progs/devlibs32/include -I/c/progs/devlibs32/include/freetype2\
+ text_reassemble.c
+
+Compilation of object file only (Linux):
+ gcc -Wall -c -I. -I/usr/include/freetype2 text_reassemble.c
+
+
+Optional compiler switches for development:
+ -DDBG_TR_PARA draw bounding rectangles for paragraphs in SVG output
+ -DDBG_TR_INPUT draw input text and their bounding rectangles in SVG output
+ -DTEST build the test program
+ -DDBG_LOOP force the test program to cycle 5 times. Useful for finding
+ memory leaks. Ouput file is overwritten each time.
+
+
+File: text_reassemble.c
+Version: 0.0.13
+Date: 24-MAR-2014
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2014 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "text_reassemble.h"
+#include <libuemf/uemf_utf.h> /* For a couple of text functions. Exact copy from libUEMF. */
+#include <float.h>
+
+/* Code generated by make_ucd_mn_table.c using:
+ cat mnlist.txt | ./make_ucd_mn_table >generated.c
+*/
+#include <stdint.h>
+int is_mn_unicode(int test){
+#define MN_TEST_LIMIT 921600
+#define N_SPAGES 225
+#define N_CPAGES 192
+#define N_CPDATA 344
+#define C_PER_S 16
+ uint8_t superpages[N_SPAGES]={
+ 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x06,
+ 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0B};
+
+ uint8_t cpages[N_CPAGES]={
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x19, 0x00, 0x00,
+ 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x1C, 0x1D, 0x1E, 0x1F, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x21, 0x00,
+ 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x25, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27,
+ 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ uint32_t cpage_data[N_CPDATA]={
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000F8, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFE0000, 0xBFFFFFFF, 0x000000B6, 0x00000000,
+ 0x07FF0000, 0x00000000, 0xFFFFF800, 0x00010000, 0x00000000, 0x00000000, 0x9FC00000, 0x00003D9F,
+ 0x00020000, 0xFFFF0000, 0x000007FF, 0x00000000, 0x00000000, 0x0001FFC0, 0x00000000, 0x000FF800,
+ 0xFBC00000, 0x00003EEF, 0x0E000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x7FFFFFF0,
+ 0x00000007, 0x14000000, 0x00FE21FE, 0x0000000C, 0x00000002, 0x10000000, 0x0000201E, 0x0000000C,
+ 0x00000006, 0x10000000, 0x00023986, 0x00230000, 0x00000006, 0x10000000, 0x000021BE, 0x0000000C,
+ 0x00000002, 0x90000000, 0x0040201E, 0x0000000C, 0x00000004, 0x00000000, 0x00002001, 0x00000000,
+ 0x00000000, 0xC0000000, 0x00603DC1, 0x0000000C, 0x00000000, 0x90000000, 0x00003040, 0x0000000C,
+ 0x00000000, 0x00000000, 0x0000201E, 0x0000000C, 0x00000000, 0x00000000, 0x005C0400, 0x00000000,
+ 0x00000000, 0x07F20000, 0x00007F80, 0x00000000, 0x00000000, 0x1BF20000, 0x00003F00, 0x00000000,
+ 0x03000000, 0x02A00000, 0x00000000, 0x7FFE0000, 0xFEFFE0DF, 0x1FFFFFFF, 0x00000040, 0x00000000,
+ 0x00000000, 0x66FDE000, 0xC3000000, 0x001E0001, 0x20002064, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xE0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x001C0000, 0x001C0000, 0x000C0000, 0x000C0000, 0x00000000, 0x3FB00000, 0x200FFE40, 0x00000000,
+ 0x00003800, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000200, 0x00000000, 0x00000000,
+ 0x00000000, 0x0E040187, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x01800000, 0x00000000, 0x7F400000, 0x9FF81FE5, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x0000000F, 0x17D00000, 0x00000004, 0x000FF800, 0x00000003, 0x00000B3C, 0x00000000, 0x0003A340,
+ 0x00000000, 0x00CFF000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFF70000, 0x001021FD,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xF000007F,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1FFF0000, 0x0001FFE2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00038000,
+ 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00003C00, 0x00000000, 0x00000000, 0x06000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x3FF08000, 0x80000000, 0x00000000, 0x00000000, 0x00030000,
+ 0x00000844, 0x00000060, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x0003FFFF,
+ 0x00000000, 0x00003FC0, 0x0003FF80, 0x00000000, 0x00000007, 0x13C80000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00667E00, 0x00001008, 0x00000000, 0x00000000, 0xC19D0000, 0x00000002, 0x00403000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00002120,
+ 0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x0000FFFF, 0x0000007F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20000000,
+ 0x0000F06E, 0x87000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000002, 0xFF000000, 0x0000007F, 0x00000000, 0x00000003, 0x06780000, 0x00000000, 0x00000000,
+ 0x00000007, 0x001FEF80, 0x00000000, 0x00000000, 0x00000003, 0x7FC00000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00BF2800, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00078000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0xF8000380, 0x00000FE7, 0x00003C00, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x0000001C, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF};
+
+ int result=0;
+
+ int spage_idx;
+ int cpage_row, cpage_column, cpage_idx;
+ int cd_row, cd_column, cd_idx, cd_bit;
+
+ if(test<MN_TEST_LIMIT){
+ spage_idx = test >> 12;
+ cpage_row = superpages[spage_idx];
+ cpage_column = (test>>8) & 15;
+ cpage_idx = C_PER_S*cpage_row + cpage_column;
+ cd_row = cpages[cpage_idx];
+ cd_column = test>>5 & 7;
+ cd_idx = 8*cd_row + cd_column;
+ cd_bit = test & 31;
+ result = cpage_data[cd_idx] & (1 << cd_bit);
+ }
+ return(result);
+}
+
+
+
+/**
+ \brief Find a (sub)string in a caseinvariant manner, used for locating "Narrow" in font name
+ \return Returns -1 if no match, else returns the position (numbered from 0) of the first character of the match.
+ \param string Text to search
+ \param sub Text to find
+*/
+int TR_findcasesub(const char *string, const char *sub){
+ int i,j;
+ int match=0;
+ for(i=0; string[i]; i++){
+ for(match=1,j=0; sub[j] && string[i+j]; j++){
+ if(toupper(sub[j]) != toupper(string[i+j])){
+ match=0;
+ break;
+ }
+ }
+ if(match && !sub[j])break; /* matched over the entire substring */
+ }
+ return((match ? i : -1));
+}
+
+/**
+ \brief Constrouct a fontspec from a TCHUNK_SPECS and a fontname
+ \return Returns NULL on error, new fontspec on success
+ \param tsp pointer to TCHUNK_SPECS to use for information
+ \param fontname Fontname to use in the new fontspec
+*/
+ /* construct a font name */
+char *TR_construct_fontspec(const TCHUNK_SPECS *tsp, const char *fontname){
+ int newlen = 128 + strlen(fontname); /* too big, but not by much */
+ char *newfs = NULL;
+ newfs = (char *) malloc(newlen);
+ sprintf(newfs,"%s:slant=%d:weight=%d:size=%lf:width=%d",fontname,tsp->italics,tsp->weight,tsp->fs,(tsp->co ? 75 : tsp->condensed));
+ return(newfs);
+}
+
+
+/**
+ \brief Reconstrouct a fontspec by substituting a font name into an existing spec
+ \return Returns NULL on error, new fontspec on success
+ \param fontspec Original fontspec, only the name will be changed
+ \param fontname Fontname to substitute into the new fontspec
+*/
+ /* construct a font name */
+char *TR_reconstruct_fontspec(const char *fontspec, const char *fontname){
+ int colon;
+ int newlen = strlen(fontspec) + strlen(fontname) + 1; /* too big, but not by much */
+ char *newfs = NULL;
+ newfs = (char *) malloc(newlen);
+ colon = strcspn(fontspec,":");
+ if(colon){ sprintf(newfs,"%s%s",fontname,&fontspec[colon]); }
+ return(newfs);
+}
+
+/**
+ \brief Find a font in the list that has a glyph for this character, change alternate to match
+ \return Returns 0 if no match or an error, else returns the glyph index in the new alternate font
+ \param fti pointer to the FT_INFO structure, may be modified if alternate font is added
+ \param efsp Pointer to a Pointer to the original FNT_SPECS struct. On return contains the FNT_SPECS corresponding to the glyph_index..
+ \param wc Current character (32 bit int)
+*/
+int TR_find_alternate_font(FT_INFO *fti, FNT_SPECS **efsp, uint32_t wc){
+ int glyph_index=0; /* this is the unknown character glyph */
+ uint32_t i;
+ FcCharSet *cs;
+ FcResult result = FcResultMatch;
+ FcPattern *pattern, *fpat;
+ char *filename;
+ char *fontname;
+ char *newfontspec;
+ int fi_idx;
+ FNT_SPECS *fsp,*fsp2;
+ if(!fti || !efsp || !*efsp)return(0);
+ fsp = *efsp;
+ for(i=0;i<fsp->used;i++){ /* first check in alts */
+ fsp2 = &fti->fonts[fsp->alts[i].fi_idx]; /* these are in order of descending previous usage */
+ glyph_index = FT_Get_Char_Index( fsp2->face, wc); /* we have the face, might as well check that directly */
+ if (glyph_index){ /* found a glyph for the character in this font */
+ (void) fsp_alts_weight(fsp, i);
+ *efsp = fsp2;
+ return(glyph_index);
+ }
+ }
+
+ /* it was not in alts, now go through fontset and see if it is in there */
+ for(i=1; i< (unsigned int) fsp->fontset->nfont;i++){ /* already know the primary does not have this character */
+ result = FcPatternGetCharSet(fsp->fontset->fonts[i], FC_CHARSET, 0, &cs);
+ if(result != FcResultMatch) return(0); /* some terrible problem, this should never happen */
+ if (FcCharSetHasChar(cs, wc)){ /* found a glyph for the character in this font */
+ glyph_index = i;
+
+ /* Do a lot of work to find the filename corresponding to the fontset entry.
+ None of these should ever fail, but if one does, return 0
+ */
+ if(
+ !(pattern = FcNameParse((const FcChar8 *)&(fsp->fontspec))) ||
+ !FcConfigSubstitute(NULL, pattern, FcMatchPattern)
+ )return(0);
+ FcDefaultSubstitute(pattern);
+ if(
+ !(fpat = FcFontRenderPrepare(NULL, pattern, fsp->fontset->fonts[i])) ||
+ (FcPatternGetString( fpat, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch) ||
+ (FcPatternGetString( fsp->fontset->fonts[i], FC_FULLNAME, 0, (FcChar8 **)&fontname) != FcResultMatch)
+ )return(0);
+
+ /* find the font (added from an unrelated fontset, for instance) or insert it as new */
+ fi_idx = ftinfo_find_loaded_by_src(fti, (uint8_t *) filename);
+ if(fi_idx < 0){
+ newfontspec = TR_reconstruct_fontspec((char *) fsp->fontspec, fontname);
+ fi_idx = ftinfo_load_fontname(fti, newfontspec);
+ free(newfontspec);
+ if(fi_idx < 0)return(0); /* This could happen if we run out of memory*/
+ }
+
+ /* add the new font index to the alts list on the (current) fsp. */
+ (void) fsp_alts_insert(fsp, fi_idx);
+
+ /* release FC's own memory related to this call that does not need to be kept around so that face will work */
+ FcPatternDestroy(pattern);
+
+ *efsp = &(fti->fonts[fi_idx]);
+ return(glyph_index);
+ }
+ }
+
+ return(0);
+}
+
+/**
+ \brief Get the advance for the 32 bit character
+
+ \return Returns -1 on error, or advance in units of 1/64th of a Point.
+ \param fti pointer to the FT_INFO structure, may be modified if alternate font is required
+ \param fsp Pointer to FNT_SPECS struct.
+ \param wc Current character (32 bit int)
+ \param pc Previous character
+ \param load_flags Controls internal advance:
+ FT_LOAD_NO_SCALE, internal advance is in 1/64th of a point. (kerning values are still scaled)
+ FT_LOAD_TARGET_NORMAL internal advance is in 1/64th of a point. The scale
+ factor seems to be (Font Size in points)*(DPI)/(32.0 pnts)*(72 dpi).
+ \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application.
+ \param ymin If the pointer is defined, the value is adjusted if ymin of wc character is less than the current value.
+ \param ymax If the pointer is defined, the value is adjusted if ymin of wc character is more than the current value.
+*/
+int TR_getadvance(FT_INFO *fti, FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int load_flags, int kern_mode, int *ymin, int *ymax){
+ FT_Glyph glyph;
+ int glyph_index;
+ int advance=-1;
+ FT_BBox bbox;
+
+ if(is_mn_unicode(wc))return(0); /* no advance on Unicode Mn characters */
+
+ glyph_index = FT_Get_Char_Index( fsp->face, wc);
+ if(!glyph_index){ /* not in primary font, check alternates */
+ glyph_index = TR_find_alternate_font(fti, &fsp, wc);
+ }
+ if(glyph_index){
+ if (!FT_Load_Glyph( fsp->face, glyph_index, load_flags )){
+ if ( !FT_Get_Glyph( fsp->face->glyph, &glyph ) ) {
+ advance = fsp->face->glyph->advance.x;
+ FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_UNSCALED, &bbox );
+ if(ymin && (bbox.yMin < *ymin))*ymin=bbox.yMin;
+ if(ymax && (bbox.yMax > *ymax))*ymax=bbox.yMax;
+ if(pc)advance += TR_getkern2(fsp, wc, pc, kern_mode);
+ FT_Done_Glyph(glyph);
+ }
+ }
+ }
+ /* If there was no way to determine the width, this returns the error value */
+ return(advance);
+}
+
+/**
+ \brief Get the kerning for a pair of 32 bit characters
+ \return Returns 0 on error, or kerning value (which may be 0) for the pair in units of 1/64th of a point.
+ \param fsp Pointer to FNT_SPECS struct.
+ \param wc Current character (32 bit int)
+ \param pc Previous character
+ \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application.
+*/
+int TR_getkern2(FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int kern_mode){
+ int this_glyph_index;
+ int prev_glyph_index;
+ int kern=0;
+ FT_Vector akerning;
+
+ this_glyph_index = FT_Get_Char_Index( fsp->face, wc);
+ prev_glyph_index = FT_Get_Char_Index( fsp->face, pc);
+ if(!FT_Get_Kerning( fsp->face,
+ prev_glyph_index,
+ this_glyph_index,
+ kern_mode,
+ &akerning )){
+ kern = akerning.x; /* Is sign correct? */
+ }
+ return(kern);
+}
+
+/**
+ \brief Get the kerning for a pair of 32 bit characters, where one is the last character in the previous text block, and the other is the first in the current text block.
+ \return Returns 0 on error, or kerning value (which may be 0) for the pair in units of 1/64th of a point.
+ \param fsp Pointer to FNT_SPECS struct.
+ \param tsp current text object
+ \param ptsp previous text object
+ \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application.
+*/
+int TR_kern_gap(FNT_SPECS *fsp, TCHUNK_SPECS *tsp, TCHUNK_SPECS *ptsp, int kern_mode){
+ int kern=0;
+ uint32_t *text32=NULL;
+ uint32_t *ptxt32=NULL;
+ size_t tlen,plen;
+ while(ptsp && tsp){
+ text32 = U_Utf8ToUtf32le((char *) tsp->string, 0, &tlen);
+ if(!text32){ // LATIN1 encoded >128 are generally not valid UTF, so the first will fail
+ text32 = U_Latin1ToUtf32le((char *) tsp->string,0, &tlen);
+ if(!text32)break;
+ }
+ ptxt32 = U_Utf8ToUtf32le((char *) ptsp->string,0,&plen);
+ if(!ptxt32){ // LATIN1 encoded >128 are generally not valid UTF, so the first will fail
+ ptxt32 = U_Latin1ToUtf32le((char *) ptsp->string,0, &plen);
+ if(!ptxt32)break;
+ }
+ kern = TR_getkern2(fsp, *text32, ptxt32[plen-1], kern_mode);
+ break;
+ }
+ if(text32)free(text32);
+ if(ptxt32)free(ptxt32);
+ return(kern);
+}
+
+
+
+
+/**
+ \brief Find baseline on Y axis of a complex.
+ If the complex is a TR_TEXT or TR_LINE find its baseline.
+ If the complex is TR_PARA_[UCLR]J find the baseline of the last line.
+ If there are multiple text elements in a TR_LINE, the baseline is that of the
+ element that uses the largest font. This will definitely give the wrong
+ result if that line starts with a super or subscript that is full font size, but
+ they are usually smaller.
+ \return Returns 0 if it cannot determine a baseline, else returns the baseline Y coordinate.
+ \param tri pointer to the TR_INFO structure holding all TR data
+ \param src index of the current complex
+ \param ymax If the pointer is defined, the value is adjusted if ymax of current complex is more than the current value.
+ \param ymin If the pointer is defined, the value is adjusted if ymin of current complex is less than the current value.
+*/
+double TR_baseline(TR_INFO *tri, int src, double *ymax, double *ymin){
+ double baseline=0;
+ volatile double tmp=0.0; /* This MUST be volatile */
+ double yheight;
+ int last;
+ int i;
+ int trec;
+ CX_INFO *cxi=tri->cxi;
+ BR_INFO *bri=tri->bri;
+ TP_INFO *tpi=tri->tpi;
+ FT_INFO *fti=tri->fti;
+ FNT_SPECS *fsp;
+ last = cxi->cx[src].kids.used - 1;
+ switch (cxi->cx[src].type){
+ case TR_TEXT:
+ trec = cxi->cx[src].kids.members[0]; /* for this complex type there is only ever one member */
+ baseline = bri->rects[trec].yll - tpi->chunks[trec].boff;
+ fsp = &(fti->fonts[tpi->chunks[trec].fi_idx]);
+ yheight = fsp->face->bbox.yMax - fsp->face->bbox.yMin;
+ if(ymax){
+ tmp = tpi->chunks[trec].fs * ((double)fsp->face->bbox.yMax/yheight);
+ if(*ymax <= tmp)*ymax = tmp;
+ }
+ else if(ymin){
+ tmp = tpi->chunks[trec].fs * ((double)-fsp->face->bbox.yMin/yheight); /* yMin in face is negative */
+ if(*ymin <= tmp)*ymin = tmp;
+ }
+ break;
+ case TR_LINE:
+ for(i=last;i>=0;i--){ /* here last is the count of text objects in the complex */
+ trec = cxi->cx[src].kids.members[i];
+ fsp = &(fti->fonts[tpi->chunks[trec].fi_idx]);
+ yheight = fsp->face->bbox.yMax - fsp->face->bbox.yMin;
+ if(ymax){
+ tmp = tpi->chunks[trec].fs * (((double)fsp->face->bbox.yMax)/yheight);
+ /* gcc 4.6.3 had a bizarre optimization error for -O2 and -O3 where *ymax <= tmp was
+ not true when *ymax == tmp, as verified by examining the binary representations.
+ This was apparently due to retained excess precision. Making tmp volatile
+ forces it to be stored into a 64 bit location, dropping the extra 12 bits from
+ the 80 bit register. */
+ if(*ymax <= tmp){
+ *ymax = tmp;
+ baseline = bri->rects[trec].yll - tpi->chunks[trec].boff;
+ }
+ }
+ else if(ymin){
+ tmp = tpi->chunks[trec].fs * (((double)-fsp->face->bbox.yMin)/yheight); /* yMin in face is negative */
+ if(*ymin <= tmp){
+ *ymin = tmp;
+ baseline = bri->rects[trec].yll - tpi->chunks[trec].boff;
+ }
+ }
+ }
+ break;
+ case TR_PARA_UJ:
+ case TR_PARA_LJ:
+ case TR_PARA_CJ:
+ case TR_PARA_RJ:
+ trec = cxi->cx[src].kids.members[last];
+ baseline = TR_baseline(tri, trec, ymax, ymin);
+ break;
+ }
+ return(baseline);
+}
+
+/**
+ \brief Check or set vertical advance on the growing complex relative to the current complex.
+ Vadvance is a multiplicative factor like 1.25.
+ The distance between successive baselines is vadvance * max(font_size), where the maximum
+ is over all text elements in src.
+ The growing complex is always the last one in the CX_INFO section of the TR_INFO structure.
+ If an existing vadvance does not match the one which would be required to fit the next complex
+ to add to the growing one, it terminates a growing complex. (Ie, starts a new paragraph.)
+ Find baseline on Y axis of a complex.
+ If the complex is a TR_TEXT or TR_LINE find its baseline.
+ If the complex is TR_PARA+* find the baseline of the last line.
+ If there are multiple text elements in a TR_LINE, the baseline is that of the
+ element that uses the largest font. This will definitely give the wrong
+ result if that line starts with a super or subscript that is full font size, but
+ they are usually smaller.
+ \return Returns 0 on success, !0 on failure.
+ \param tri pointer to the TR_INFO structure holding all TR data
+ \param src index of the current complex, to be added to the growing complex.
+ This lets the value of "src - lines" determine the weight to give to each new vadvance value
+ as it is merged into the running weighted average. This improves the accuracy of the vertical advance,
+ since there can be some noise introduced when lines have different maximum font sizes.
+ \param lines index of the first text block that was added to the growing complex.
+*/
+int TR_check_set_vadvance(TR_INFO *tri, int src, int lines){
+ int status = 0;
+ CX_INFO *cxi = tri->cxi;
+ TP_INFO *tpi = tri->tpi;
+ double ymax = DBL_MIN;
+ double ymin = DBL_MIN;
+ double prevbase;
+ double thisbase;
+ double weight;
+ int trec;
+ double newV;
+ int dst;
+
+ dst = cxi->used-1; /* complex being grown */
+
+ prevbase = TR_baseline(tri, dst, NULL, &ymin);
+ thisbase = TR_baseline(tri, src, &ymax, NULL);
+ newV = (thisbase - prevbase)/(ymax + ymin);
+ trec = cxi->cx[dst].kids.members[0]; /* complex whose first text record holds vadvance for this complex */
+ trec = cxi->cx[trec].kids.members[0]; /* text record that halds vadvance for this complex */
+ if(tpi->chunks[trec].vadvance){
+ /* already set on the first text (only place it is stored.)
+ See if the line to be added is compatible.
+ All text fields in a complex have the same advance, so just set/check the first one.
+ vadvance must be within 1% or do not add a new line */
+ if(fabs(1.0 - (tpi->chunks[trec].vadvance/newV) > 0.01)){
+ status = 1;
+ }
+ else { /* recalculate the weighted vadvance */
+ weight = (1.0 / (double) (src - lines));
+ tpi->chunks[trec].vadvance = tpi->chunks[trec].vadvance*(1.0-weight) + newV*weight;
+ }
+ }
+ else { /* only happens when src = lines + 1*/
+ tpi->chunks[trec].vadvance = newV;
+ }
+ return(status);
+}
+
+
+/**
+ \brief Initialize an FT_INFO structure. Sets up a freetype library to use in this context.
+ \returns a pointer to the FT_INFO structure created, or NULL on error.
+*/
+FT_INFO *ftinfo_init(void){
+ FT_INFO *fti = NULL;
+ if(FcInit()){
+ fti = (FT_INFO *)calloc(1,sizeof(FT_INFO));
+ if(fti){
+ if(!FT_Init_FreeType( &(fti->library))){
+ fti->space=0;
+ fti->used=0;
+
+ if(ftinfo_make_insertable(fti)){
+ FT_Done_FreeType(fti->library);
+ free(fti);
+ fti=NULL;
+ }
+ }
+ else {
+ free(fti);
+ fti=NULL;
+ }
+ }
+ if(!fti)FcFini();
+ }
+ return(fti);
+}
+
+/**
+ \brief Make an FT_INFO structure insertable. Adds storage as needed.
+ \param fti pointer to the FT_INFO structure
+ \returns 0 on success, !0 on error.
+*/
+int ftinfo_make_insertable(FT_INFO *fti){
+ int status=0;
+ if(!fti)return(2);
+ if(fti->used >= fti->space){
+ fti->space += ALLOCINFO_CHUNK;
+ if((fti->fonts = (FNT_SPECS *) realloc(fti->fonts, fti->space * sizeof(FNT_SPECS) ))){
+ memset(&fti->fonts[fti->used],0,(fti->space - fti->used)*sizeof(FNT_SPECS));
+ }
+ else {
+ status=1;
+ }
+ }
+ return(status);
+}
+
+
+/**
+ \brief Insert a copy of a FNT_SPECS structure into the FT_INFO structure.
+ \param fti pointer to the FT_INFO structure.
+ \param fsp pointer to the FNT_SPECS structure.
+ \returns 0 on success, !0 on error.
+*/
+int ftinfo_insert(FT_INFO *fti, FNT_SPECS *fsp){
+ int status=1;
+ if(!fti)return(2);
+ if(!fsp)return(3);
+ if(!(status = ftinfo_make_insertable(fti))){
+ memcpy(&(fti->fonts[fti->used]),fsp,sizeof(FNT_SPECS));
+ fti->used++;
+ }
+ return(status);
+}
+
+
+
+/**
+ \brief Release an FT_INFO structure. Release all associated memory.
+ Use like: fi_ptr = ftinfo_release(fi_ptr)
+ \param fti pointer to the FT_INFO structure.
+ \returns NULL.
+*/
+FT_INFO *ftinfo_release(FT_INFO *fti){
+ (void) ftinfo_clear(fti);
+ FcFini(); /* shut down FontConfig, release memory, patterns must have already been released or boom! */
+ return NULL;
+}
+
+
+/**
+ \brief Clear an FT_INFO structure. Release all Freetype memory but does not release Fontconfig.
+ This would be called in preference to ftinfo_release() if some other part of the program needed
+ to continue using Fontconfig.
+ Use like: fi_ptr = ftinfo_clear(fi_ptr)
+ \param fti pointer to the FT_INFO structure.
+ \returns NULL.
+*/
+FT_INFO *ftinfo_clear(FT_INFO *fti){
+ uint32_t i;
+ FNT_SPECS *fsp;
+ if(fti){
+ for(i=0;i<fti->used;i++){
+ fsp = &(fti->fonts[i]);
+ FT_Done_Face(fsp->face); /* release memory for face controlled by FreeType */
+ free(fsp->file); /* release memory holding copies of paths */
+ free(fsp->fontspec); /* release memory holding copies of font names */
+ FcPatternDestroy(fsp->fpat); /* release memory for FontConfig fpats */
+ FcFontSetDestroy(fsp->fontset);
+ if(fsp->alts){ free(fsp->alts); }
+ }
+ free(fti->fonts);
+ FT_Done_FreeType(fti->library); /* release all other FreeType memory */
+ free(fti);
+ }
+ return NULL;
+}
+
+
+/**
+ \brief Find the loaded font matching fontspec
+ \returns index of font on success, -1 if not found
+ \param tri pointer to the TR_INFO structure.
+ \param fontspec UTF-8 description of the font, as constructed in trinfo_load_fontname
+*/
+
+int ftinfo_find_loaded_by_spec(const FT_INFO *fti, const uint8_t *fontspec){
+ uint32_t i;
+ int status = -1;
+ /* If it is already loaded, do not load it again */
+ for(i=0;i<fti->used;i++){
+ if(0==strcmp((char *) fti->fonts[i].fontspec, (char *)fontspec)){
+ status=i;
+ break;
+ }
+ }
+ return(status);
+}
+
+/**
+ \brief Find the loaded font matching the source file
+ \returns index of font on success, -1 if not found
+ \param tri pointer to the TR_INFO structure.
+ \param filename UTF-8 file name for the font
+*/
+
+int ftinfo_find_loaded_by_src(const FT_INFO *fti, const uint8_t *filename){
+ uint32_t i;
+ int status = -1;
+ /* If it is already loaded, do not load it again */
+ for(i=0;i<fti->used;i++){
+ if(0==strcmp((char *) fti->fonts[i].file, (char *) filename)){
+ status=i;
+ break;
+ }
+ }
+ return(status);
+}
+
+
+/**
+ \brief Load a (new) font by name into a TR_INFO structure or find it if it is already loaded
+ \returns fi_idx of inserted (or found) font on success, <0 on error.
+ \param fti pointer to the FT_INFO structure.
+ \param fontname UTF-8 font name
+ \param fontspec UTF-8 font specification used for query string.
+*/
+
+int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec){
+ FcPattern *pattern = NULL;
+ FcPattern *fpat = NULL;
+ FcFontSet *fontset = NULL;
+ FcResult result = FcResultMatch;
+ char *filename;
+ double fd;
+ FNT_SPECS *fsp;
+ int status;
+ int fi_idx;
+
+ if(!fti)return(-1);
+
+ /* If it is already loaded, do not load it again */
+ status = ftinfo_find_loaded_by_spec(fti, (uint8_t *) fontspec);
+ if(status >= 0){ return(status); }
+ status = 0; /* was -1, reset to 0 */
+
+ ftinfo_make_insertable(fti);
+ fi_idx = fti->used;
+
+ pattern = FcNameParse((const FcChar8 *)fontspec);
+ while(1) { /* this is NOT a loop, it uses breaks to avoid gotos and deep nesting */
+ if(!(pattern)){ status = -2; break; }
+ if(!FcConfigSubstitute(NULL, pattern, FcMatchPattern)){ status = -3; break; };
+ FcDefaultSubstitute(pattern);
+ /* get a fontset, trimmed to only those with new glyphs as needed, so that missing glyph's may be handled */
+ if(!(fontset = FcFontSort (NULL,pattern, FcTrue, NULL, &result)) || (result != FcResultMatch)){ status = -4; break; }
+ if(!(fpat = FcFontRenderPrepare(NULL, pattern, fontset->fonts[0]))){ status = -405; break; }
+ if(FcPatternGetString( fpat, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch){ status = -5; break; }
+ if(FcPatternGetDouble( fpat, FC_SIZE, 0, &fd) != FcResultMatch){ status = -6; break; }
+
+ /* copy these into memory for external use */
+ fsp = &(fti->fonts[fti->used]);
+ fsp->fontset = fontset;
+ fsp->alts = NULL; /* Initially no links to alternate fonts */
+ fsp->space = 0;
+ fsp->file = (uint8_t *) U_strdup((char *) filename);
+ fsp->fontspec = (uint8_t *) U_strdup((char *) fontspec);
+ fsp->fpat = fpat;
+ fsp->fsize = fd;
+ break;
+ }
+ /* release FC's own memory related to this call that does not need to be kept around so that face will work */
+ if(pattern)FcPatternDestroy(pattern); /* done with this memory */
+ if(status<0){
+ if(fontset)FcFontSetDestroy(fontset);
+ if(fpat)FcPatternDestroy(fpat);
+ return(status);
+ }
+
+ /* get the current face */
+ if(FT_New_Face( fti->library, (const char *) fsp->file, 0, &(fsp->face) )){ return(-8); }
+
+ if(FT_Set_Char_Size(
+ fsp->face, /* handle to face object */
+ 0, /* char_width in 1/64th of points */
+ fd*64, /* char_height in 1/64th of points */
+ 72, /* horizontal device resolution, DPI */
+ 72) /* vebrical device resolution, DPI */
+ ){ return(-9); }
+
+ /* The space advance is needed in various places. Get it now, and get it in the font units,
+ so that it can be scaled later with the text size */
+ status = TR_getadvance(fti, fsp,' ',0,FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, FT_KERNING_UNSCALED, NULL, NULL);
+ if(status < 0)return(-7);
+ fsp->spcadv = ((double) status)/(64.0);
+
+ fti->used++;
+
+/*
+ char *fs;
+ int fb;
+ if(FcPatternGetBool( fpat, FC_OUTLINE, 0, &fb)== FcResultMatch){ printf("outline: %d\n",fb);fflush(stdout); }
+ if(FcPatternGetBool( fpat, FC_SCALABLE, 0, &fb)== FcResultMatch){ printf("scalable: %d\n",fb);fflush(stdout); }
+ if(FcPatternGetDouble( fpat, FC_DPI, 0, &fd)== FcResultMatch){ printf("DPI: %lf\n",fd);fflush(stdout); }
+ if(FcPatternGetInteger( fpat, FC_FONTVERSION, 0, &fb)== FcResultMatch){ printf("fontversion: %d\n",fb);fflush(stdout); }
+ if(FcPatternGetString( fpat, FC_FULLNAME , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FULLNAME : %s\n",fs);fflush(stdout); }
+ if(FcPatternGetString( fpat, FC_FAMILY , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FAMILY : %s\n",fs);fflush(stdout); }
+ if(FcPatternGetString( fpat, FC_STYLE , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("STYLE : %s\n",fs);fflush(stdout); }
+ if(FcPatternGetString( fpat, FC_FOUNDRY , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FOUNDRY : %s\n",fs);fflush(stdout); }
+ if(FcPatternGetString( fpat, FC_FAMILYLANG , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FAMILYLANG : %s\n",fs);fflush(stdout); }
+ if(FcPatternGetString( fpat, FC_STYLELANG , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("STYLELANG : %s\n",fs);fflush(stdout); }
+ if(FcPatternGetString( fpat, FC_FULLNAMELANG, 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FULLNAMELANG: %s\n",fs);fflush(stdout); }
+ if(FcPatternGetString( fpat, FC_CAPABILITY , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("CAPABILITY : %s\n",fs);fflush(stdout); }
+ if(FcPatternGetString( fpat, FC_FONTFORMAT , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FONTFORMAT : %s\n",fs);fflush(stdout); }
+*/
+
+ return(fi_idx);
+}
+
+/**
+ \brief Dump the contents of the TR_INFO structure to stdout. For debugging purposes,not used in production code.
+ \param tri pointer to the TR_INFO structure.
+*/
+void ftinfo_dump(const FT_INFO *fti){
+ uint32_t i,j;
+ FNT_SPECS *fsp;
+ printf("fti space: %d\n",fti->space);
+ printf("fti used: %d\n",fti->used);
+ for(i=0; i< fti->used; i++){
+ fsp = &(fti->fonts[i]);
+ printf("fti font: %6d space: %6d used: %6d spcadv %8lf fsize %8lf \n",i,fsp->space,fsp->used,fsp->spcadv,fsp->fsize);
+ printf(" file: %s\n",fsp->file);
+ printf(" fspc: %s\n",fsp->fontspec);
+ for(j=0;j<fsp->used;j++){
+ printf(" alts: %6d fi_idx: %6d wgt: %6d\n",j,fsp->alts[j].fi_idx,fsp->alts[j].weight);
+ }
+ }
+
+}
+
+/**
+ \brief Make the FNT_SPECS alts structure insertable. Adds storage as needed.
+ \param fti pointer to the FT_INFO structure
+ \returns 0 on success, !0 on error.
+*/
+int fsp_alts_make_insertable(FNT_SPECS *fsp){
+ int status=0;
+ if(!fsp)return(2);
+ if(fsp->used >= fsp->space){
+ fsp->space += ALLOCINFO_CHUNK;
+ if((fsp->alts = (ALT_SPECS *) realloc(fsp->alts, fsp->space * sizeof(ALT_SPECS) ))){
+ memset(&fsp->alts[fsp->used],0,(fsp->space - fsp->used)*sizeof(ALT_SPECS));
+ }
+ else {
+ status=1;
+ }
+ }
+ return(status);
+}
+
+
+/**
+ \brief Insert a new ALT_SPECS into the FNT_SPECS alts list.
+ \param fsp pointer to the FNT_SPECS structure.
+ \param fi_idx font index to add to the alts list
+ \returns 0 on success, !0 on error.
+*/
+int fsp_alts_insert(FNT_SPECS *fsp, uint32_t fi_idx){
+ int status=1;
+ ALT_SPECS alt;
+ if(!fsp)return(3);
+ alt.fi_idx = fi_idx;
+ alt.weight = 1; /* new ones start with this weight, it can only go up */
+ if(!(status = fsp_alts_make_insertable(fsp))){
+ fsp->alts[fsp->used] = alt;
+ fsp->used++;
+ }
+ return(status);
+}
+
+/**
+ \brief Increment the weight of an alts entry by 1, readjust order if necessary
+ \param fsp pointer to the FNT_SPECS structure.
+ \param idx index of the alts entry to increment
+ \returns 0 on success, !0 on error.
+*/
+int fsp_alts_weight(FNT_SPECS *fsp, uint32_t a_idx){
+ uint32_t i;
+ ALT_SPECS alt;
+ if(!fsp)return(1);
+ if(!fsp->used)return(2);
+ if(a_idx >= fsp->used)return(3);
+ /* If a counter hits the limit divide all counts in half. */
+ if(fsp->alts[a_idx].weight == UINT32_MAX){
+ for(i=0; i<fsp->used; i++){ fsp->alts[i].weight /= 2; }
+ }
+ fsp->alts[a_idx].weight++;
+ for(i=a_idx; i>0; i--){
+ if(fsp->alts[i-1].weight >= fsp->alts[a_idx].weight)break;
+ alt = fsp->alts[i-1];
+ fsp->alts[i-1] = fsp->alts[a_idx];
+ fsp->alts[a_idx] = alt;
+ }
+ return(0);
+}
+
+
+
+/**
+ \brief Make a CHILD_SPECS structure insertable. Adds storage as needed.
+ \param csp pointer to the CHILD_SPECS structure
+ \returns 0 on success, !0 on error.
+*/
+int csp_make_insertable(CHILD_SPECS *csp){
+ int status=0;
+ if(!csp)return(2);
+ if(csp->used >= csp->space){
+ csp->space += ALLOCINFO_CHUNK;
+ if((csp->members = (int *) realloc(csp->members, csp->space * sizeof(int) ))){
+ memset(&csp->members[csp->used],0,(csp->space - csp->used)*sizeof(int));
+ }
+ else {
+ status=1;
+ }
+ }
+ return(status);
+}
+
+/**
+ \brief Add a member to a CHILD_SPECS structure. (Member is an index for either a text object or a complex.)
+ \param dst pointer to the CHILD_SPECS structure.
+ \param src index of the member.
+ \returns 0 on success, !0 on error.
+*/
+int csp_insert(CHILD_SPECS *dst, int src){
+ int status=1;
+ if(!dst)return(2);
+ if(!(status=csp_make_insertable(dst))){
+ dst->members[dst->used]=src;
+ dst->used++;
+ }
+ return(status);
+}
+
+/**
+ \brief Append all the members of one CHILD_SPECS structure to another CHILD_SPECS structure.
+ Member is an index for either a text object or a complex.
+ The donor is not modified.
+ \param dst pointer to the recipient CHILD_SPECS structure.
+ \param src pointer to the donor CHILD_SPECS structure.
+ \returns 0 on success, !0 on error.
+*/
+int csp_merge(CHILD_SPECS *dst, CHILD_SPECS *src){
+ uint32_t i;
+ int status=1;
+ if(!dst)return(2);
+ if(!src)return(3);
+ for(i=0;i<src->used;i++){
+ status = csp_insert(dst, src->members[i]);
+ if(status)break;
+ }
+ return(status);
+}
+
+/**
+ \brief Release a CHILD_SPECS structure. Release all associated memory.
+ \param csp pointer to the CHILD_SPECS structure.
+ \returns NULL.
+*/
+void csp_release(CHILD_SPECS *csp){
+ if(csp){
+ free(csp->members);
+ csp->space = 0;
+ csp->used = 0;
+ }
+}
+
+/**
+ \brief Clear a CHILD_SPECS structure, making all allocated slots usable. Does not release associated memory.
+ \param csp pointer to the CHILD_SPECS structure.
+ \returns NULL.
+*/
+void csp_clear(CHILD_SPECS *csp){
+ csp->used = 0;
+}
+
+
+/**
+ \brief Initialize an CX_INFO structure. Holds complexes (multiple text objects in known positions and order.)
+ \returns a pointer to the CX_INFO structure created, or NULL on error.
+*/
+CX_INFO *cxinfo_init(void){
+ CX_INFO *cxi = NULL;
+ cxi = (CX_INFO *)calloc(1,sizeof(CX_INFO));
+ if(cxi){
+ if(cxinfo_make_insertable(cxi)){
+ free(cxi);
+ cxi=NULL;
+ }
+ }
+ return(cxi);
+}
+
+/**
+ \brief Make a CX_INFO structure insertable. Adds storage as needed.
+ \returns 0 on success, !0 on error.
+ \param cxi pointer to the CX_INFO structure
+*/
+int cxinfo_make_insertable(CX_INFO *cxi){
+ int status=0;
+ if(cxi->used >= cxi->space){
+ cxi->space += ALLOCINFO_CHUNK;
+ if((cxi->cx = (CX_SPECS *) realloc(cxi->cx, cxi->space * sizeof(CX_SPECS) ))){
+ memset(&cxi->cx[cxi->used],0,(cxi->space - cxi->used)*sizeof(CX_SPECS));
+ }
+ else {
+ status=1;
+ }
+ }
+ return(status);
+}
+
+/**
+ \brief Insert a complex into the CX_INFO structure. (Insert may be either TR_TEXT or TR_LINE.)
+ \returns 0 on success, !0 on error.
+ \param cxi pointer to the CX_INFO structure (complexes).
+ \param src index of the complex to insert.
+ \param src_rt_tidx index of the bounding rectangle
+ \param type TR_TEXT (index is for tpi->chunks[]) or TR_LINE (index is for cxi->kids[])
+*/
+int cxinfo_insert(CX_INFO *cxi, int src, int src_rt_tidx, enum tr_classes type){
+ int status=1;
+ if(!cxi)return(2);
+ if(!(status=cxinfo_make_insertable(cxi))){
+ cxi->cx[cxi->used].rt_cidx = src_rt_tidx;
+ cxi->cx[cxi->used].type = type;
+ status = csp_insert(&(cxi->cx[cxi->used].kids), src);
+ cxi->used++;
+ }
+ return(status);
+}
+
+/**
+ \brief Append a complex to the CX_INFO structure and give it a type.
+ \param cxi pointer to the CX_INFO structure (complexes).
+ \param src index of the complex to append.
+ \param type TR_LINE (src is an index for tpi->chunks[]) or TR_PARA (src is an index for cxi->kids[]).
+ \returns 0 on success, !0 on error.
+*/
+int cxinfo_append(CX_INFO *cxi, int src, enum tr_classes type){
+ int status=1;
+ if(!cxi)return(2);
+ if(!(status=cxinfo_make_insertable(cxi))){
+ cxi->cx[cxi->used-1].type = type;
+ status = csp_insert(&(cxi->cx[cxi->used-1].kids), src);
+ }
+ return(status);
+}
+
+
+/**
+ \brief Merge a complex dst with N members (N>=1) by adding a second complex src, and change the type.
+ \param cxi pointer to the CX_INFO structure (complexes).
+ \param dst index of the complex to expand.
+ \param src index of the donor complex (which is not modified).
+ \param type TR_LINE (src is an index for tpi->chunks[]) or TR_PARA (src is an index for cxi->kids[]).
+ \returns 0 on success, !0 on error.
+*/
+int cxinfo_merge(CX_INFO *cxi, int dst, int src, enum tr_classes type){
+ int status =1;
+ if(!cxi)return(2);
+ if(!cxi->used)return(3);
+ if(dst < 0 || dst >= (int) cxi->used)return(4);
+ if(src < 0)return(5);
+ cxi->cx[dst].type = type;
+ status = csp_merge(&(cxi->cx[dst].kids), &(cxi->cx[src].kids));
+ return(status);
+}
+
+/**
+ \brief Trim the last complex from thelist of complexes.
+ \param cxi pointer to the CX_INFO structure (complexes).
+ \returns 0 on success, !0 on error.
+*/
+int cxinfo_trim(CX_INFO *cxi){
+ int status = 0;
+ int last ;
+ if(!cxi)return(1);
+ if(!cxi->used)return(2);
+ last = cxi->used - 1;
+ csp_clear(&(cxi->cx[last].kids));
+ cxi->used--;
+ return(status);
+}
+
+
+/**
+ \brief Dump the contents of the TR_INFO structure to stdout. For debugging purposes,not used in production code.
+ \param tri pointer to the TR_INFO structure.
+*/
+void cxinfo_dump(const TR_INFO *tri){
+ uint32_t i,j,k;
+ CX_INFO *cxi = tri->cxi;
+ BR_INFO *bri = tri->bri;
+ TP_INFO *tpi = tri->tpi;
+ BRECT_SPECS *bsp;
+ CX_SPECS *csp;
+ if(cxi){
+ printf("cxi space: %d\n",cxi->space);
+ printf("cxi used: %d\n",cxi->used);
+ printf("cxi phase1: %d\n",cxi->phase1);
+ printf("cxi lines: %d\n",cxi->lines);
+ printf("cxi paras: %d\n",cxi->paras);
+ printf("cxi xy: %lf , %lf\n",tri->x,tri->y);
+
+ for(i=0;i<cxi->used;i++){
+ csp = &(cxi->cx[i]);
+ bsp = &(bri->rects[csp->rt_cidx]);
+ printf("cxi cx[%d] type:%d rt_tidx:%d kids_used:%d kids_space:%d\n",i, csp->type, csp->rt_cidx, csp->kids.used, csp->kids.space);
+ printf("cxi cx[%d] br (LL,UR) (%lf,%lf),(%lf,%lf)\n",i,bsp->xll,bsp->yll,bsp->xur,bsp->yur);
+ for(j=0;j<csp->kids.used;j++){
+ k = csp->kids.members[j];
+ bsp = &(bri->rects[k]);
+ if(csp->type == TR_TEXT || csp->type == TR_LINE){
+ printf("cxi cx[%d] member:%3d tp_idx:%3d ldir:%d rt_tidx:%3d br (LL,UR) (%8.3lf,%8.3lf),(%8.3lf,%8.3lf) xy (%8.3lf,%8.3lf) kern (%8.3lf,%8.3lf) text:<%s> decor:%5.5x\n",
+ i, j, k, tpi->chunks[k].ldir, tpi->chunks[k].rt_tidx,
+ bsp->xll,bsp->yll,bsp->xur,bsp->yur,
+ tpi->chunks[k].x, tpi->chunks[k].y,
+ tpi->chunks[k].xkern, tpi->chunks[k].ykern,
+ tpi->chunks[k].string, tpi->chunks[k].decoration );
+ }
+ else { /* TR_PARA_* */
+ printf("cxi cx[%d] member:%d cx_idx:%d\n",i, j, k);
+ }
+ }
+ }
+ }
+ return;
+}
+
+/**
+ \brief Release a CX_INFO structure. Release all associated memory.
+ use like: cxi = cxiinfo_release(cxi);
+ \param cxi pointer to the CX_INFO structure.
+ \returns NULL.
+*/
+CX_INFO *cxinfo_release(CX_INFO *cxi){
+ uint32_t i;
+ if(cxi){
+ for(i=0;i<cxi->used;i++){ csp_release(&cxi->cx[i].kids); }
+ free(cxi->cx);
+ free(cxi); /* release the overall cxinfo structure */
+ }
+ return NULL;
+}
+
+
+/**
+ \brief Initialize an TP_INFO structure. Holds text objects from which complexes are built.
+ \returns a pointer to the TP_INFO structure created, or NULL on error.
+*/
+TP_INFO *tpinfo_init(void){
+ TP_INFO *tpi = NULL;
+ tpi = (TP_INFO *)calloc(1,sizeof(TP_INFO));
+ if(tpi){
+ if(tpinfo_make_insertable(tpi)){
+ free(tpi);
+ tpi=NULL;
+ }
+ }
+ return(tpi);
+}
+
+
+/**
+ \brief Make a TP_INFO structure insertable. Adds storage as needed.
+ \returns 0 on success, !0 on error.
+ \param tpi pointer to the TP_INFO structure
+*/
+int tpinfo_make_insertable(TP_INFO *tpi){
+ int status=0;
+ if(tpi->used >= tpi->space){
+ tpi->space += ALLOCINFO_CHUNK;
+ if((tpi->chunks = (TCHUNK_SPECS *) realloc(tpi->chunks, tpi->space * sizeof(TCHUNK_SPECS) ))){
+ memset(&tpi->chunks[tpi->used],0,(tpi->space - tpi->used)*sizeof(TCHUNK_SPECS));
+ }
+ else {
+ status=1;
+ }
+ }
+ return(status);
+}
+
+/**
+ \brief Insert a copy of a TCHUNK_SPECS structure into a TP_INFO structure. (Insert a text object.)
+ \returns 0 on success, !0 on error.
+ \param tpi pointer to the TP_INFO structure
+ \param tsp pointer to the TCHUNK_SPECS structure
+*/
+int tpinfo_insert(TP_INFO *tpi, const TCHUNK_SPECS *tsp){
+ int status=1;
+ TCHUNK_SPECS *ltsp;
+ if(!tpi)return(2);
+ if(!tsp)return(3);
+ if(!(status = tpinfo_make_insertable(tpi))){
+ ltsp = &(tpi->chunks[tpi->used]);
+ memcpy(ltsp,tsp,sizeof(TCHUNK_SPECS));
+ if(tsp->co)ltsp->condensed = 75; /* Narrow was set in the font name */
+ ltsp->xkern = ltsp->ykern = 0.0; /* kerning will be calculated from the derived layout */
+ tpi->used++;
+ }
+ return(status);
+}
+
+/**
+ \brief Release a TP_INFO structure. Release all associated memory.
+ use like: tpi = tpinfo_release(tpi);
+ \returns NULL.
+ \param tpi pointer to the TP_INFO structure.
+*/
+TP_INFO *tpinfo_release(TP_INFO *tpi){
+ uint32_t i;
+ if(tpi){
+ for(i=0;i<tpi->used;i++){
+ free(tpi->chunks[i].string); }
+ free(tpi->chunks); /* release the array */
+ free(tpi); /* release the overall tpinfo structure */
+ }
+ return NULL;
+}
+
+/**
+ \brief Initialize an BR_INFO structure. Holds bounding rectangles, for both text objects and complexes.
+ \returns a pointer to the BR_INFO structure created, or NULL on error.
+*/
+BR_INFO *brinfo_init(void){
+ BR_INFO *bri = NULL;
+ bri = (BR_INFO *)calloc(1,sizeof(BR_INFO));
+ if(bri){
+ if(brinfo_make_insertable(bri)){
+ free(bri);
+ bri=NULL;
+ }
+ }
+ return(bri);
+}
+
+/**
+ \brief Make a BR_INFO structure insertable. Adds storage as needed.
+ \returns 0 on success, !0 on error.
+ \param bri pointer to the BR_INFO structure
+*/
+int brinfo_make_insertable(BR_INFO *bri){
+ int status=0;
+ if(!bri)return(2);
+ if(bri->used >= bri->space){
+ bri->space += ALLOCINFO_CHUNK;
+ if(!(bri->rects = (BRECT_SPECS *) realloc(bri->rects, bri->space * sizeof(BRECT_SPECS) ))){ status = 1; }
+ }
+ return(status);
+}
+
+/**
+ \brief Insert a copy of a BRECT_SPEC structure into a BR_INFO structure. (Insert a bounding rectangle.)
+ \returns 0 on success, !0 on error.
+ \param bri pointer to the BR_INFO structure
+ \param element pointer to the BRECT_SPECS structure
+*/
+int brinfo_insert(BR_INFO *bri, const BRECT_SPECS *element){
+ int status=1;
+ if(!bri)return(2);
+ if(!(status=brinfo_make_insertable(bri))){
+ memcpy(&(bri->rects[bri->used]),element,sizeof(BRECT_SPECS));
+ bri->used++;
+ }
+ return(status);
+}
+
+/**
+ \brief Merge BRECT_SPEC element src into/with BRECT_SPEC element dst. src is unchanged. (Merge two bounding rectangles.)
+ \returns 0 on success, !0 on error.
+ \param bri pointer to the BR_INFO structure
+ \param dst index of the destination bounding rectangle.
+ \param src index of the source bounding rectangle.
+*/
+int brinfo_merge(BR_INFO *bri, int dst, int src){
+ if(!bri)return(1);
+ if(!bri->used)return(2);
+ if(dst<0 || dst >= (int) bri->used)return(3);
+ if(src<0 || src >= (int) bri->used)return(4);
+ bri->rects[dst].xll = TEREMIN(bri->rects[dst].xll, bri->rects[src].xll);
+ bri->rects[dst].yll = TEREMAX(bri->rects[dst].yll, bri->rects[src].yll); /* MAX because Y is positive DOWN */
+ bri->rects[dst].xur = TEREMAX(bri->rects[dst].xur, bri->rects[src].xur);
+ bri->rects[dst].yur = TEREMIN(bri->rects[dst].yur, bri->rects[src].yur); /* MIN because Y is positive DOWN */
+/*
+printf("bri_Merge into rect:%d (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",dst,
+(bri->rects[dst].xll),
+(bri->rects[dst].yll),
+(bri->rects[dst].xur),
+(bri->rects[dst].yur),
+(bri->rects[src].xll),
+(bri->rects[src].yll),
+(bri->rects[src].xur),
+(bri->rects[src].yur));
+*/
+ return(0);
+}
+
+/**
+ \brief Check for an allowable overlap of two bounding rectangles.
+ Allowable overlap is any area overlap of src and dst bounding rectangles, after
+ they have been expanded (padded) by allowed edge expansions. (For instance, if
+ missing spaces must be accounted for.)
+ The method works backwards: look for all reasons they might not overlap,
+ if none are found, then the rectangles do overlap.
+ An overlap here does not count just a line or a point - area must be involved.
+ \returns 0 on success (overlap detected), 1 on no overlap, anything else is an error.
+ \param bri pointer to the BR_INFO structure
+ \param dst index of the destination bounding rectangle.
+ \param src index of the source bounding rectangle.
+ \param rp_dst Pointer to edge padding values for dst.
+ \param rp_src Pointer to edge padding values for src.
+*/
+int brinfo_overlap(const BR_INFO *bri, int dst, int src, RT_PAD *rp_dst, RT_PAD *rp_src){
+ int status;
+ BRECT_SPECS *br_dst;
+ BRECT_SPECS *br_src;
+ if(!bri || !rp_dst || !rp_src)return(2);
+ if(!bri->used)return(3);
+ if(dst<0 || dst>= (int) bri->used)return(4);
+ if(src<0 || src>= (int) bri->used)return(5);
+ br_dst=&bri->rects[dst];
+ br_src=&bri->rects[src];
+ if( /* Test all conditions that exclude overlap, if any are true, then no overlap */
+ ((br_dst->xur + rp_dst->right) < (br_src->xll - rp_src->left) ) || /* dst fully to the left */
+ ((br_dst->xll - rp_dst->left) > (br_src->xur + rp_src->right) ) || /* dst fully to the right */
+ ((br_dst->yur - rp_dst->up) > (br_src->yll + rp_src->down) ) || /* dst fully below (Y is positive DOWN) */
+ ((br_dst->yll + rp_dst->down) < (br_src->yur - rp_src->up) ) /* dst fully above (Y is positive DOWN) */
+ ){
+ status = 1;
+ }
+ else {
+ /* overlap not excluded, so it must occur.
+ Only accept overlaps that are mostly at one end or the other, not mostly top or bottom.
+ If the following condition is true then there is no more than a tiny bit of horizontal overlap of src
+ within dist, which suggests that the two pieces of text may be considered part of one line.
+ (For a vertical alphabet the same method could be used for up/down.) */
+ if(
+ (br_src->xll >= br_dst->xur - rp_dst->right) || /* src overlaps just a little on the right (L->R language) */
+ (br_src->xur <= br_dst->xll + rp_dst->left) /* src overlaps just a little on the left (R->L language) */
+ ){
+ status = 0;
+ }
+ else { /* Too much overlap, reject the overlap */
+ status = 1;
+ }
+ }
+/*
+printf("Overlap status:%d\nOverlap trects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",
+status,
+(br_dst->xll - rp_dst->left ),
+(br_dst->yll - rp_dst->down ),
+(br_dst->xur + rp_dst->right),
+(br_dst->yur + rp_dst->up ),
+(br_src->xll - rp_src->left ),
+(br_src->yll - rp_src->down ),
+(br_src->xur + rp_src->right),
+(br_src->yur + rp_src->up ));
+printf("Overlap brects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",
+(br_dst->xll),
+(br_dst->yll),
+(br_dst->xur),
+(br_dst->yur),
+(br_src->xll),
+(br_src->yll),
+(br_src->xur),
+(br_src->yur));
+printf("Overlap rprect (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",
+(rp_dst->left),
+(rp_dst->down),
+(rp_dst->right),
+(rp_dst->up),
+(rp_src->left),
+(rp_src->down),
+(rp_src->right),
+(rp_src->up));
+*/
+ return(status);
+}
+
+/**
+ \brief Check for various sorts of invalid text elements upstream (language dir changes, draw order backwards from language direction)
+ \returns 0 on success (not upstream), 1 if upstream, anything else is an error.
+ \param bri pointer to the BR_INFO structure
+ \param dst index of the destination bounding rectangle.
+ \param src index of the source bounding rectangle.
+ \param ddir direction of dst
+ \param sdir direction of src
+*/
+
+int brinfo_upstream(BR_INFO *bri, int dst, int src, int ddir, int sdir){
+ int status=0;
+ BRECT_SPECS *br_dst;
+ BRECT_SPECS *br_src;
+ if(!bri)return(2);
+ if(!bri->used)return(3);
+ if(dst<0 || dst>= (int) bri->used)return(4);
+ if(src<0 || src>= (int) bri->used)return(5);
+ br_dst=&bri->rects[dst];
+ br_src=&bri->rects[src];
+ if( ddir == LDIR_RL && sdir == LDIR_LR){
+ if(br_dst->xur <= (br_src->xll + br_src->xur)/2.0){ status = 1; }
+ }
+ else if( ddir == LDIR_LR && sdir == LDIR_RL){
+ if((br_src->xll + br_src->xur)/2.0 <= br_dst->xll ){ status = 1; }
+ }
+ else if( ddir == LDIR_RL && sdir == LDIR_RL){
+ if(br_dst->xur <= (br_src->xll + br_src->xur)/2.0){ status = 1; }
+ }
+ else if( ddir == LDIR_LR && sdir == LDIR_LR){
+ if((br_src->xll + br_src->xur)/2.0 <= br_dst->xll ){ status = 1; }
+ }
+ return(status);
+}
+
+
+/**
+ \brief Try to deduce justification of a paragraph from the bounding rectangles for two successive lines.
+ \returns one of TR_PARA_ UJ (unknown justified), LJ, CJ, or RJ (left, center, or right justified).
+ \param bri pointer to the BR_INFO structure
+ \param dst index of the destination bounding rectangle.
+ \param src index of the source bounding rectangle.
+ \param slop allowed error in edge alignment.
+ \param type Preexisting justification for dst, if any. Justification of dst and src must match this or
+ TR_PARA_UJ is returned even if dst and src have some (other) alignment.
+*/
+enum tr_classes brinfo_pp_alignment(const BR_INFO *bri, int dst, int src, double slop, enum tr_classes type){
+ enum tr_classes newtype;
+ BRECT_SPECS *br_dst = & bri->rects[dst];
+ BRECT_SPECS *br_src = & bri->rects[src];
+ if((br_dst->yur >= br_src->yur) || (br_dst->yll >= br_src->yll)){ /* Y is positive DOWN */
+ /* lines in the wrong vertical order, no paragraph possible (Y is positive down) */
+ newtype = TR_PARA_UJ;
+ }
+ else if(fabs(br_dst->xll - br_src->xll) < slop){
+ /* LJ (might also be CJ but LJ takes precedence) */
+ newtype = TR_PARA_LJ;
+ }
+ else if(fabs(br_dst->xur - br_src->xur) < slop){
+ /* RJ */
+ newtype = TR_PARA_RJ;
+ }
+ else if(fabs( (br_dst->xur + br_dst->xll)/2.0 - (br_src->xur + br_src->xll)/2.0 ) < slop){
+ /* CJ */
+ newtype = TR_PARA_CJ;
+ }
+ else {
+ /* not aligned */
+ newtype = TR_PARA_UJ;
+ }
+ /* within a paragraph type can change from unknown to known, but not from one known type to another*/
+ if((type != TR_PARA_UJ) && (newtype != type)){
+ newtype = TR_PARA_UJ;
+ }
+/*
+printf("pp_align newtype:%d brects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",
+newtype,
+(br_dst->xll),
+(br_dst->yll),
+(br_dst->xur),
+(br_dst->yur),
+(br_src->xll),
+(br_src->yll),
+(br_src->xur),
+(br_src->yur));
+*/
+ return(newtype);
+}
+
+/**
+ \brief Release a BR_INFO structure. Release all associated memory.
+ use like: bri = brinfo_release(bri);
+ \param bri pointer to the BR_INFO structure.
+ \returns NULL.
+*/
+BR_INFO *brinfo_release(BR_INFO *bri){
+ if(bri){
+ free(bri->rects);
+ free(bri); /* release the overall brinfo structure */
+ }
+ return NULL;
+}
+
+
+
+/**
+ \brief Initialize an TR_INFO structure. Holds all data for text reassembly.
+ \returns a pointer to the TR_INFO structure created, or NULL on error.
+*/
+TR_INFO *trinfo_init(TR_INFO *tri){
+ if(tri)return(tri); /* tri is already set, double initialization is not allowed */
+ if(!(tri = (TR_INFO *)calloc(1,sizeof(TR_INFO))) ||
+ !(tri->fti = ftinfo_init()) ||
+ !(tri->tpi = tpinfo_init()) ||
+ !(tri->bri = brinfo_init()) ||
+ !(tri->cxi = cxinfo_init())
+ ){ tri = trinfo_release(tri); }
+ tri->out = NULL; /* This will allocate as needed, it might not ever be needed. */
+ tri->qe = 0.0;
+ tri->esc = 0.0;
+ tri->x = DBL_MAX;
+ tri->y = DBL_MAX;
+ tri->dirty = 0;
+ tri->use_kern = 1;
+ tri->load_flags = FT_LOAD_NO_SCALE;
+ tri->kern_mode = FT_KERNING_UNSCALED;
+ tri->outspace = 0;
+ tri->outused = 0;
+ tri->usebk = BKCLR_NONE;
+ memset(&(tri->bkcolor),0,sizeof(TRCOLORREF));
+ return(tri);
+}
+
+/**
+ \brief Release a TR_INFO structure completely.
+ Release all associated memory, including FontConfig.
+ See also trinfo_clear() and trinfo_release_except_FC().
+ use like: tri = trinfo_release(tri);
+ \param tri pointer to the TR_INFO structure.
+ \returns NULL.
+*/
+TR_INFO *trinfo_release(TR_INFO *tri){
+ if(tri){
+ if(tri->bri)tri->bri=brinfo_release(tri->bri);
+ if(tri->tpi)tri->tpi=tpinfo_release(tri->tpi);
+ if(tri->fti)tri->fti=ftinfo_release(tri->fti);
+ if(tri->cxi)tri->cxi=cxinfo_release(tri->cxi);
+ if(tri->out){ free(tri->out); tri->out=NULL; };
+ free(tri);
+ }
+ return(NULL);
+}
+
+/**
+ \brief Release a TR_INFO structure mostly.
+ Release all associated memory EXCEPT Fontconfig.
+ Fontconfig may still be needed elsewhere in a program and there is no way to figure that out here.
+ See also trinfo_clear() and trinfo_release().
+ use like: tri = trinfo_release_except_FC(tri);
+ \param tri pointer to the TR_INFO structure.
+ \returns NULL.
+*/
+TR_INFO *trinfo_release_except_FC(TR_INFO *tri){
+ if(tri){
+ if(tri->bri)tri->bri=brinfo_release(tri->bri);
+ if(tri->tpi)tri->tpi=tpinfo_release(tri->tpi);
+ if(tri->fti)tri->fti=ftinfo_clear(tri->fti);
+ if(tri->cxi)tri->cxi=cxinfo_release(tri->cxi);
+ if(tri->out){ free(tri->out); tri->out=NULL; };
+ free(tri);
+ }
+ return(NULL);
+}
+
+/**
+ \brief Clear a TR_INFO structure.
+ Releases text and rectangle information, but retains font information, both
+ Freetype information and Fontconfig information.
+ See also trinfo_release() and trinfo_release_except_FC().
+ Use like: tri = trinfo_clear(tri);
+ \param tri pointer to the TR_INFO structure.
+ \returns NULL.
+*/
+TR_INFO *trinfo_clear(TR_INFO *tri){
+ if(tri){
+
+ if(tri->bri)tri->bri=brinfo_release(tri->bri);
+ if(tri->tpi)tri->tpi=tpinfo_release(tri->tpi);
+ if(tri->cxi)tri->cxi=cxinfo_release(tri->cxi);
+ if(tri->out){
+ free(tri->out);
+ tri->out = NULL;
+ tri->outused = 0;
+ tri->outspace = 0;
+ };
+ /* Do NOT modify: qe, use_kern, usebk, load_flags, kern_mode, or bkcolor. Set the rest back to their defaults */
+ tri->esc = 0.0;
+ tri->x = DBL_MAX;
+ tri->y = DBL_MAX;
+ tri->dirty = 0;
+ if(!(tri->tpi = tpinfo_init()) || /* re-init the pieces just released */
+ !(tri->bri = brinfo_init()) ||
+ !(tri->cxi = cxinfo_init())
+ ){
+ tri = trinfo_release(tri); /* something horrible happened, clean out tri and return NULL */
+ }
+ }
+ return(tri);
+}
+
+
+/**
+ \brief Set the quantization error value for a TR_INFO structure.
+ If coordinates have passed through an integer form limits
+ in accuracy may have been imposed. For instance, if the X coordinate of a point in such a file
+ is 1000, and the conversion factor from those coordinates to points is .04, then eq is .04. This
+ just says that single coordinates are only good to within .04, and two coordinates may differ by as much
+ as .08, just due to quantization error. So if some calculation shows a difference of
+ .02 it may be interpreted as this sort of error and set to 0.0.
+ \returns 0 on success, !0 on error.
+ \param tri pointer to TR_INFO structure
+ \param qe quantization error.
+*/
+int trinfo_load_qe(TR_INFO *tri, double qe){
+ if(!tri)return(1);
+ if(qe<0.0)return(2);
+ tri->qe=qe;
+ return(0);
+}
+
+/**
+ \brief Set the background color and whether or not to use it.
+ When background color is turned on each line of text is underwritten with a rectangle
+ of the specified color. The rectangle is the merged bounding rectangle for that line.
+ \returns 0 on success but nothing changed, >0 on error, <0 on success and a value changed.
+ \param tri pointer to TR_INFO structure
+ \param usebk 0 for no background, anything else uses background color
+ \param bkcolor background color to use
+*/
+int trinfo_load_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor){
+ int status=0;
+ if(!tri){ status = 1; }
+ else {
+ if((usebk < BKCLR_NONE) || (usebk > BKCLR_ALL)){ status = 2; }
+ else {
+ status = trinfo_check_bk(tri, usebk, bkcolor);
+ tri->usebk = usebk;
+ tri->bkcolor = bkcolor;
+ }
+ }
+ return(status);
+}
+
+/**
+ \brief Are the proposed new background and background color a change?
+ \returns 0 if they are the same, -1 if either is different
+ \param tri pointer to TR_INFO structure
+ \param usebk 0 for no background, anything else uses background color
+ \param bkcolor background color to use
+*/
+int trinfo_check_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor){
+ int status = 0;
+ if( (tri->usebk != usebk) || memcmp(&tri->bkcolor,&bkcolor,sizeof(TRCOLORREF))){ status = -1; }
+ return(status);
+}
+
+/**
+ \brief Set Freetype parameters and kerning mode (if any) in a TRI_INFO structure.
+ \returns 0 on success, !0 on error.
+ \param tri pointer to a TR_INFO structure
+ \param use_kern 0 if kerning is to be employed, !0 otherwise.
+ \param load_flags Controls internal advance:
+ FT_LOAD_NO_SCALE, internal advance is in 1/64th of a point. (kerning values are still scaled)
+ FT_LOAD_TARGET_NORMAL internal advance is in 1/64th of a point. The scale
+ factor seems to be (Font Size in points)*(DPI)/(32.0 pnts)*(72 dpi).
+ \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application.
+*/
+int trinfo_load_ft_opts(TR_INFO *tri, int use_kern, int load_flags, int kern_mode){
+ if(!tri)return(1);
+ tri->use_kern = use_kern;
+ tri->load_flags = load_flags;
+ tri->kern_mode = kern_mode;
+ return(0);
+}
+
+/**
+ \brief Append text to a TR_INFO struct's output buffer, expanding it if necessary.
+ \returns 0 on success, !0 on error.
+ \param tri pointer to a TR_INFO structure
+ \param src Pointer to a text string.
+*/
+int trinfo_append_out(TR_INFO *tri, const char *src){
+ size_t slen;
+ if(!src)return(-1);
+ slen = strlen(src);
+ if(tri->outused + (int) slen + 1 >= tri->outspace){
+ tri->outspace += TEREMAX(ALLOCOUT_CHUNK,slen+1);
+ if(!(tri->out = realloc(tri->out, tri->outspace )))return(-1);
+ }
+ memcpy(tri->out + tri->outused, src, slen+1); /* copy the terminator */
+ tri->outused += slen; /* do not count the terminator in the length */
+ return(0);
+}
+
+
+/**
+ \brief Load a text object into a TR_INFO struct.
+ \returns 0 on success, !0 on error. -1 means that the escapement is different from the objects already loaded.
+ \param tri pointer to a TR_INFO structure
+ \param tsp pointer to a TCHUNK_SPECS structure (text object to load)
+ \param escapement angle in degrees of the text object.
+ \param flags special processing flags:
+ TR_EMFBOT calculate Y coordinates of ALIBOT object compatible with EMF files TA_BOTTOM alignment.
+*/
+int trinfo_load_textrec(TR_INFO *tri, const TCHUNK_SPECS *tsp, double escapement, int flags){
+
+ int status;
+ double x,y,xe;
+ double asc,dsc; /* these are the ascender/descender for the actual text */
+ int ymin,ymax;
+ double fasc,fdsc; /* these are the ascender/descender for the font as a whole (text independent) */
+ TP_INFO *tpi;
+ FT_INFO *fti;
+ BR_INFO *bri;
+ int current,idx,taln;
+ uint32_t prev;
+ uint32_t *text32,*tptr;
+ FNT_SPECS *fsp;
+ BRECT_SPECS bsp;
+
+ /* check incoming parameters */
+ if(!tri)return(1);
+ if(!tsp)return(2);
+ if(!tsp->string)return(3);
+ fti = tri->fti;
+ tpi = tri->tpi;
+ bri = tri->bri;
+ idx = tsp->fi_idx;
+ taln = tsp->taln;
+ if(!fti->used)return(4);
+ if(idx <0 || idx >= (int) fti->used)return(5);
+ fsp = &(fti->fonts[idx]);
+
+ if(!tri->dirty){
+ tri->x = tsp->x;
+ tri->y = tsp->y;
+ tri->esc = escapement;
+ tri->dirty = 1;
+ }
+ else {
+ if(tri->esc != escapement)return(-1);
+ }
+
+
+ tpinfo_insert(tpi,tsp);
+ current=tpi->used-1;
+ ymin = 64000;
+ ymax = -64000;
+
+ /* The geometry model has origin Y at the top of screen, positive Y is down, maximum positive
+ Y is at the bottom of the screen. That makes "top" (by positive Y) actually the bottom
+ (as viewed on the screen.) */
+
+ escapement *= 2.0 * M_PI / 360.0; /* degrees to radians */
+ x = tpi->chunks[current].x - tri->x; /* convert to internal orientation */
+ y = tpi->chunks[current].y - tri->y;
+ tpi->chunks[current].x = x * cos(escapement) - y * sin(escapement); /* coordinate transformation */
+ tpi->chunks[current].y = x * sin(escapement) + y * cos(escapement);
+
+/* Careful! face bbox does NOT scale with FT_Set_Char_Size
+printf("Face idx:%d bbox: xMax/Min:%ld,%ld yMax/Min:%ld,%ld UpEM:%d asc/des:%d,%d height:%d size:%lf\n",
+ idx,
+ fsp->face->bbox.xMax,fsp->face->bbox.xMin,
+ fsp->face->bbox.yMax,fsp->face->bbox.yMin,
+ fsp->face->units_per_EM,fsp->face->ascender,fsp->face->descender,fsp->face->height,fsp->fsize);
+*/
+
+ text32 = U_Utf8ToUtf32le((char *) tsp->string,0,NULL);
+ if(!text32){ // LATIN1 encoded >128 are generally not valid UTF, so the first will fail
+ text32 = U_Latin1ToUtf32le((char *) tsp->string,0,NULL);
+ if(!text32)return(5);
+ }
+ /* baseline advance is independent of character orientation */
+ for(xe=0.0, prev=0, tptr=text32; *tptr; tptr++){
+ status = TR_getadvance(fti, fsp, *tptr, (tri->use_kern ? prev: 0), tri->load_flags, tri->kern_mode, &ymin, &ymax);
+ if(status>=0){
+ xe += ((double) status)/64.0;
+ }
+ else { return(6); }
+ prev=*tptr;
+ }
+
+ /* Some glyphs in fonts have no vertical extent, for instance, Hebrew glyphs in Century Schoolbook L.
+ Use the 3/4 of the font size as a (very bad) approximation for the actual values. */
+ if(ymin==0 && ymax==0){
+ ymax = 0.75 * fsp->fsize * 64.0;
+ }
+
+ asc = ((double) (ymax))/64.0;
+ dsc = ((double) (ymin))/64.0; /* This is negative */
+/* This did not work very well because the ascender/descender went well beyond the actual characters, causing
+ overlaps on lines that did not actually overlap (vertically).
+ asc = ((double) (fsp->face->ascender) )/64.0;
+ dsc = ((double) (fsp->face->descender))/64.0;
+*/
+
+ free(text32);
+
+ /* find the font ascender descender (general one, not specific for current text) */
+ fasc = ((double) (fsp->face->ascender) )/64.0;
+ fdsc = ((double) (fsp->face->descender))/64.0;
+
+ if(tri->load_flags & FT_LOAD_NO_SCALE) xe *= tsp->fs/32.0;
+
+ /* now place the rectangle using ALN information */
+ if( taln & ALIHORI & ALILEFT ){
+ bsp.xll = tpi->chunks[current].x;
+ bsp.xur = tpi->chunks[current].x + xe;
+ }
+ else if( taln & ALIHORI & ALICENTER){
+ bsp.xll = tpi->chunks[current].x - xe/2.0;
+ bsp.xur = tpi->chunks[current].x + xe/2.0;
+ }
+ else{ /* taln & ALIHORI & ALIRIGHT */
+ bsp.xll = tpi->chunks[current].x - xe;
+ bsp.xur = tpi->chunks[current].x;
+ }
+ tpi->chunks[current].ldir = tsp->ldir;
+
+ if(tri->load_flags & FT_LOAD_NO_SCALE){
+ asc *= tsp->fs/32.0;
+ dsc *= tsp->fs/32.0;
+ fasc *= tsp->fs/32.0;
+ fdsc *= tsp->fs/32.0;
+ }
+
+
+ /* From this point forward y is on the baseline, so need to correct it in chunks. The asc/dsc are the general
+ ones for the font, else the text content will muck around with the baseline in BAD ways. */
+ if( taln & ALIVERT & ALITOP ){ tpi->chunks[current].y += fasc; }
+ else if( taln & ALIVERT & ALIBASE){ } /* no correction required */
+ else{ /* taln & ALIVERT & ALIBOT */
+ if(flags & TR_EMFBOT){ tpi->chunks[current].y -= 0.35 * tsp->fs; } /* compatible with EMF implementations */
+ else { tpi->chunks[current].y += fdsc; }
+ }
+ tpi->chunks[current].boff = -dsc;
+
+ /* since y is always on the baseline, the lower left and upper right are easy. These use asc/dsc for the particular text,
+ so that the bounding box will fit it tightly. */
+ bsp.yll = tpi->chunks[current].y - dsc;
+ bsp.yur = tpi->chunks[current].y - asc;
+ brinfo_insert(bri,&bsp);
+ tpi->chunks[current].rt_tidx = bri->used - 1; /* index of rectangle that contains it */
+
+ return(0);
+}
+
+/**
+ \brief Fontweight conversion. Fontconfig units to SVG units.
+ Anything not recognized becomes "normal" == 400.
+ There is no interpolation because a value that mapped to 775, for instance, most
+ likely would not display properly because it is intermediate between 700 and 800, and
+ only those need be supported in SVG viewers.
+ \returns SVG font weight
+ \param weight Fontconfig font weight.
+*/
+int TR_weight_FC_to_SVG(int weight){
+ int ret=400;
+ if( weight == 0){ ret = 100; }
+ else if(weight == 40){ ret = 200; }
+ else if(weight == 50){ ret = 300; }
+ else if(weight == 80){ ret = 400; }
+ else if(weight == 100){ ret = 500; }
+ else if(weight == 180){ ret = 600; }
+ else if(weight == 200){ ret = 700; }
+ else if(weight == 205){ ret = 800; }
+ else if(weight == 210){ ret = 900; }
+ else { ret = 400; }
+ return(ret);
+}
+
+/**
+ \brief Set the padding that will be added to bounding rectangles before checking for overlaps in brinfo_overlap().
+ \returns void
+ \param rt_pad pointer to an RT_PAD structure.
+ \param up padding for the top of a bounding rectangle.
+ \param down padding for the bottom of a bounding rectangle.
+ \param left padding for the left of a bounding rectangle.
+ \param right padding for the right of a bounding rectangle.
+*/
+void TR_rt_pad_set(RT_PAD *rt_pad, double up, double down, double left, double right){
+ rt_pad->up = up;
+ rt_pad->down = down;
+ rt_pad->left = left;
+ rt_pad->right = right;
+}
+
+/**
+ \brief Convert from analyzed complexes to SVG format.
+ \returns void
+ \param tri pointer to a TR_INFO struct which will be analyzed. Result is stored in its "out" buffer.
+*/
+void TR_layout_2_svg(TR_INFO *tri){
+ double x = tri->x;
+ double y = tri->y;
+ double dx,dy;
+ double esc;
+ double recenter; /* horizontal offset to set things up correctly for CJ and RJ text, is 0 for LJ*/
+ double lineheight=1.25;
+ int cutat;
+ FT_INFO *fti=tri->fti; /* Font info storage */
+ TP_INFO *tpi=tri->tpi; /* Text Info/Position Info storage */
+ BR_INFO *bri=tri->bri; /* bounding Rectangle Info storage */
+ CX_INFO *cxi=tri->cxi; /* Complexes deduced for this text */
+ TCHUNK_SPECS *tsp; /* current text object */
+ CX_SPECS *csp;
+ CX_SPECS *cline_sp;
+ unsigned int i,j,k,jdx,kdx;
+ int ldir;
+ char obuf[1024]; /* big enough for style and so forth */
+ char cbuf[16]; /* big enough for one hex color */
+
+ char stransform[128];
+ double newx,newy,tmpx;
+ uint32_t utmp;
+
+/*
+#define DBG_TR_PARA 0
+#define DBG_TR_INPUT 1
+*/
+ /* The debug section below is difficult to see if usebk is anything other than BKCLR_NONE */
+#if DBG_TR_PARA || DBG_TR_INPUT /* enable debugging code, writes extra information into SVG */
+ /* put rectangles down for each text string - debugging!!! This will not work properly for any Narrow fonts */
+ esc = tri->esc;
+ esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */
+ sprintf(stransform,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y);
+ for(i=cxi->phase1; i<cxi->used;i++){ /* over all complex members from phase2 == TR_PARA_* complexes */
+ csp = &(cxi->cx[i]);
+ for(j=0; j<csp->kids.used; j++){ /* over all members of these complexes, which are phase1 complexes */
+ jdx = csp->kids.members[j]; /* index of phase1 complex (all are TR_TEXT or TR_LINE) */
+ for(k=0; k<cxi->cx[jdx].kids.used; k++){ /* over all members of the phase1 complex */
+ kdx = cxi->cx[jdx].kids.members[k]; /* index for text objects in tpi */
+ tsp = &tpi->chunks[kdx];
+ ldir = tsp->ldir;
+ if(!j && !k){
+#if DBG_TR_PARA
+ TRPRINT(tri, "<rect\n");
+ TRPRINT(tri, "style=\"color:#0000FF;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:none;stroke:#000000;stroke-width:0.8;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n");
+ sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[csp->rt_cidx].xur - bri->rects[csp->rt_cidx].xll));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].yll - bri->rects[csp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].xll),1.25*(bri->rects[csp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, stransform);
+ TRPRINT(tri, "/>\n");
+#endif /* DBG_TR_PARA */
+ }
+#if DBG_TR_INPUT /* debugging code, this section writes the original text objects */
+ newx = 1.25*(ldir == LDIR_RL ? bri->rects[tsp->rt_tidx].xur : bri->rects[tsp->rt_tidx].xll);
+ newy = 1.25*(bri->rects[tsp->rt_tidx].yur);
+ TRPRINT(tri, "<rect\n");
+ TRPRINT(tri, "style=\"color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:none;stroke:#00FF00;stroke-width:0.3;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n");
+ sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[tsp->rt_tidx].xur - bri->rects[tsp->rt_tidx].xll));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].yll - bri->rects[tsp->rt_tidx].yur));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].xll),newy);
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, stransform);
+ TRPRINT(tri, "/>\n");
+
+ newy = 1.25*(bri->rects[tsp->rt_tidx].yll - tsp->boff);
+ sprintf(obuf,"<text x=\"%lf\" y=\"%lf\"\n",newx, newy );
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"xml:space=\"preserve\"\n");
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, stransform);
+ TRPRINT(tri, "style=\"fill:#FF0000;");
+ sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal"));
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, "font-variant:normal;");
+ sprintf(obuf,"font-weight:%d;",TR_weight_FC_to_SVG(tsp->weight));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"font-stretch:%s;",(tsp->condensed==100 ? "Normal" : "Condensed"));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"text-anchor:%s;",(tsp->ldir == LDIR_RL ? "end" : "start"));
+ TRPRINT(tri, obuf);
+ cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fontspec,":");
+ sprintf(obuf,"font-family:%.*s;",cutat,fti->fonts[tsp->fi_idx].fontspec);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"\n\">%s</text>\n",&tsp->string[tsp->spaces]);
+ TRPRINT(tri, obuf);
+#endif /* DBG_TR_INPUT debugging code, original text objects */
+ }
+ }
+ }
+#endif /* DBG_TR_PARA and/or DBG_TR_INPUT */
+
+
+ if(tri->usebk){
+ esc = tri->esc;
+ esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */
+ sprintf(stransform,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y);
+
+ for(i=cxi->phase1; i<cxi->used;i++){ /* over all complex members from phase2 == TR_PARA_* complexes */
+ TRPRINT(tri, "<g>\n"); /* group backgrounds for each <text> object in the SVG */
+ csp = &(cxi->cx[i]);
+ for(j=0; j<csp->kids.used; j++){ /* over all members of these complexes, which are phase1 complexes */
+ jdx = csp->kids.members[j]; /* index of phase1 complex (all are TR_TEXT or TR_LINE) */
+ cline_sp = &(cxi->cx[jdx]);
+ if(tri->usebk == BKCLR_LINE){
+ TRPRINT(tri, "<rect\n");
+ sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[cline_sp->rt_cidx].xur - bri->rects[cline_sp->rt_cidx].xll));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[cline_sp->rt_cidx].yll - bri->rects[cline_sp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[cline_sp->rt_cidx].xll),1.25*(bri->rects[cline_sp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, stransform);
+ TRPRINT(tri, "/>\n");
+ }
+
+ for(k=0; k<cxi->cx[jdx].kids.used; k++){ /* over all members of the phase1 complex */
+ kdx = cxi->cx[jdx].kids.members[k]; /* index for text objects in tpi */
+ tsp = &tpi->chunks[kdx];
+ ldir = tsp->ldir;
+ if(!j && !k){
+ if(tri->usebk == BKCLR_ALL){
+ TRPRINT(tri, "<rect\n");
+ sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[csp->rt_cidx].xur - bri->rects[csp->rt_cidx].xll));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].yll - bri->rects[csp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].xll),1.25*(bri->rects[csp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, stransform);
+ TRPRINT(tri, "/>\n");
+ }
+ }
+ if(tri->usebk == BKCLR_FRAG){
+ newx = 1.25*(ldir == LDIR_RL ? bri->rects[tsp->rt_tidx].xur : bri->rects[tsp->rt_tidx].xll);
+ newy = 1.25*(bri->rects[tsp->rt_tidx].yur);
+ TRPRINT(tri, "<rect\n");
+ sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[tsp->rt_tidx].xur - bri->rects[tsp->rt_tidx].xll));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].yll - bri->rects[tsp->rt_tidx].yur));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",newx,newy);
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, stransform);
+ TRPRINT(tri, "/>\n");
+ }
+ }
+ }
+ TRPRINT(tri, "</g>\n"); /* end of grouping for backgrounds for each <text> object in the SVG */
+ }
+ }
+
+
+ /* over all complex members from phase2. Paragraphs == TR_PARA_* */
+ for(i=cxi->phase1; i<cxi->used;i++){
+ csp = &(cxi->cx[i]);
+ esc = tri->esc;
+ esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */
+
+ /* over all members of the present Paragraph. Each of these is a line and a phase 1 complex.
+ It may be either TR_TEXT or TR_LINE */
+ for(j=0; j<csp->kids.used; j++){
+ if(j){
+ sprintf(obuf,"</tspan>");
+ TRPRINT(tri, obuf);
+ }
+ jdx = csp->kids.members[j]; /* index of phase1 complex (all are TR_TEXT or TR_LINE) */
+ recenter = 0; /* mostly to quiet a compiler warning, should always be set below */
+
+
+ /* over all members of the present Line. These are the original text objects which were reassembled.
+ There will be one for TR_TEXT, more than one for TR_LINE */
+ for(k=0; k<cxi->cx[jdx].kids.used; k++){
+ kdx = cxi->cx[jdx].kids.members[k]; /* index for text objects in tpi, for this k */
+ tsp = &tpi->chunks[kdx]; /* text chunk for this k */
+ ldir = tsp->ldir; /* language direction for this k */
+ if(!k){ /* first iteration */
+ switch(csp->type){ /* set up the alignment, if there is one */
+ case TR_TEXT:
+ case TR_LINE:
+ /* these should never occur, this section quiets a compiler warning */
+ break;
+ case TR_PARA_UJ:
+ case TR_PARA_LJ:
+ if(ldir == LDIR_RL){ recenter = -(bri->rects[cxi->cx[jdx].rt_cidx].xur - bri->rects[cxi->cx[jdx].rt_cidx].xll); }
+ else { recenter = 0.0; }
+ break;
+ case TR_PARA_CJ:
+ if(ldir == LDIR_RL){ recenter = -(bri->rects[cxi->cx[jdx].rt_cidx].xur - bri->rects[cxi->cx[jdx].rt_cidx].xll)/2.0; }
+ else { recenter = +(bri->rects[cxi->cx[jdx].rt_cidx].xur - bri->rects[cxi->cx[jdx].rt_cidx].xll)/2.0; }
+ break;
+ case TR_PARA_RJ:
+ if(ldir == LDIR_RL){ recenter = 0.0; }
+ else { recenter = +(bri->rects[cxi->cx[jdx].rt_cidx].xur - bri->rects[cxi->cx[jdx].rt_cidx].xll); }
+ break;
+ }
+ if(!j){
+ TRPRINT(tri, "<text\n");
+ TRPRINT(tri, "xml:space=\"preserve\"\n");
+ TRPRINT(tri, "style=\"");
+ sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal"));
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, "font-variant:normal;");
+ sprintf(obuf,"font-weight:%d;",TR_weight_FC_to_SVG(tsp->weight));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"font-stretch:%s;",(tsp->condensed==100 ? "Normal" : "Condensed"));
+ TRPRINT(tri, obuf);
+ if(tsp->vadvance){ lineheight = tsp->vadvance *100.0; }
+ else { lineheight = 125.0; }
+ sprintf(obuf,"line-height:%lf%%;",lineheight);
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, "letter-spacing:0px;");
+ TRPRINT(tri, "word-spacing:0px;");
+ TRPRINT(tri, "fill:#000000;");
+ TRPRINT(tri, "fill-opacity:1;");
+ TRPRINT(tri, "stroke:none;");
+ cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fontspec,":");
+ sprintf(obuf,"font-family:%.*s;",cutat,fti->fonts[tsp->fi_idx].fontspec);
+ TRPRINT(tri, obuf);
+ switch(csp->type){ /* set up the alignment, if there is one */
+ case TR_TEXT:
+ case TR_LINE:
+ /* these should never occur, this section quiets a compiler warning */
+ break;
+ case TR_PARA_UJ:
+ case TR_PARA_LJ:
+ sprintf(obuf,"text-align:start;text-anchor:start;");
+ break;
+ case TR_PARA_CJ:
+ sprintf(obuf,"text-align:center;text-anchor:middle;");
+ break;
+ case TR_PARA_RJ:
+ sprintf(obuf,"text-align:end;text-anchor:end;");
+ break;
+ }
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, "\"\n"); /* End of style specification */
+ sprintf(obuf,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc),1.25*x,1.25*y);
+ TRPRINT(tri, obuf);
+ tmpx = 1.25*((ldir == LDIR_RL ? bri->rects[kdx].xur : bri->rects[kdx].xll) + recenter);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n>",tmpx,1.25*(bri->rects[kdx].yll - tsp->boff));
+ TRPRINT(tri, obuf);
+ }
+ tmpx = 1.25*((ldir == LDIR_RL ? bri->rects[kdx].xur : bri->rects[kdx].xll) + recenter);
+ sprintf(obuf,"<tspan sodipodi:role=\"line\"\nx=\"%lf\" y=\"%lf\"\n>",tmpx,1.25*(bri->rects[kdx].yll - tsp->boff));
+ TRPRINT(tri, obuf);
+ }
+ TRPRINT(tri, "<tspan\n");
+
+ /* Scale kerning and make any other necessary adjustments
+
+ */
+ dx = 1.25 * tsp->xkern;
+ dy = 1.25 * tsp->ykern;
+
+ sprintf(obuf,"dx=\"%lf\" dy=\"%lf\" ",dx, dy);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"style=\"fill:#%2.2X%2.2X%2.2X;",tsp->color.Red,tsp->color.Green,tsp->color.Blue);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal"));
+ TRPRINT(tri, obuf);
+ if(tsp->decoration & TXTDECOR_TMASK){
+ sprintf(obuf,"text-decoration:");
+ /* multiple text decoration styles may be set */
+ utmp = tsp->decoration & TXTDECOR_TMASK;
+ if(utmp & TXTDECOR_UNDER ){ strcat(obuf,"underline"); }
+ if(utmp & TXTDECOR_OVER ){ strcat(obuf,"overline"); }
+ if(utmp & TXTDECOR_BLINK ){ strcat(obuf,"blink"); }
+ if(utmp & TXTDECOR_STRIKE){ strcat(obuf,"line-through");}
+ if(*obuf){
+ /* only a single text decoration line type may be set */
+ switch(tsp->decoration & TXTDECOR_LMASK){
+ case TXTDECOR_SOLID: break; // "solid" is the CSS 3 default, omitting it remains CSS 2 compatible
+ case TXTDECOR_DOUBLE: strcat(obuf," double"); break; // these are all CSS3
+ case TXTDECOR_DOTTED: strcat(obuf," dotted"); break;
+ case TXTDECOR_DASHED: strcat(obuf," dashed"); break;
+ case TXTDECOR_WAVY: strcat(obuf," wavy" ); break;
+ default: break;
+ }
+ if((tsp->decoration & TXTDECOR_CLRSET) && memcmp(&(tsp->decColor),&(tsp->color),sizeof(TRCOLORREF))){
+ /* CSS 3, CSS 2 implementations may choke on it. If the specified color matches text color omit, for better CSS 2 compatitiblity. */
+ sprintf(cbuf," #%2.2X%2.2X%2.2X",tsp->decColor.Red,tsp->decColor.Green,tsp->decColor.Blue);
+ strcat(obuf,cbuf);
+ }
+ }
+ strcat(obuf,";");
+ TRPRINT(tri,obuf);
+ }
+ TRPRINT(tri, "font-variant:normal;");
+ sprintf(obuf,"font-weight:%d;",TR_weight_FC_to_SVG(tsp->weight));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"font-stretch:%s;",(tsp->condensed==100 ? "Normal" : "Condensed"));
+ TRPRINT(tri, obuf);
+ cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fontspec,":");
+ sprintf(obuf,"font-family:%.*s;\"",cutat,fti->fonts[tsp->fi_idx].fontspec);
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, "\n>");
+ TRPRINT(tri, (char *) tsp->string);
+ TRPRINT(tri, "</tspan>");
+ } /* end of k loop */
+ } /* end of j loop */
+ TRPRINT(tri,"</tspan></text>\n");
+ } /* end of i loop */
+}
+
+/**
+ \brief Attempt to figure out the original organization, in lines and paragraphs, of the text objects.
+ The method is:
+ 1. Generate complexes from the text objects (strings) by overlaps (optionally allowing up to two spaces to be
+ added) to produce larger rectangles. Complexes that are more or less sequential and have 2 or more text objects
+ are TR_LINEs, therwise they are TR_TEXT.
+ 2. Group sequential complexes (TR_LINE or TR_TEXT) into TR_PARA_UJ (paragraphs,by smooth progression in vertical
+ position down page).
+ 3. Analyze the paragraphs to classify them as Left/Center/Right justified (possibly with indentation.) If
+ they do not fall into any of these categories break that one back down into TR_LINE/TR_TEXT.
+ 4. Return the number of complex text objects.
+ \returns Number of complexes. (>=1, <= number of text objects.) <0 is an error.
+ \param tri pointer to the TR_INFO structure holding the data, which will also hold the results.
+*/
+int TR_layout_analyze(TR_INFO *tri){
+ unsigned int i,j,k;
+ int ok;
+ int cxidx;
+ int src_rt;
+ int dst_rt;
+ TP_INFO *tpi;
+ BR_INFO *bri;
+ CX_INFO *cxi;
+ FT_INFO *fti;
+ BRECT_SPECS bsp;
+ RT_PAD rt_pad_i;
+ RT_PAD rt_pad_j;
+ double ratio;
+ double qsp,dx,dy;
+ double spcadv;
+ enum tr_classes type;
+ TCHUNK_SPECS *tspi;
+ TCHUNK_SPECS *tspj;
+ TCHUNK_SPECS *tspRevEnd=NULL;
+ TCHUNK_SPECS *tspRevStart=NULL;
+ CX_SPECS *csp;
+ CHILD_SPECS *kidp; /* used with preceding complex (see below) */
+ CHILD_SPECS *kidc; /* used with current complex (see below) */
+ int lastldir,ldir,rev;
+
+ if(!tri)return(-1);
+ if(!tri->cxi)return(-2);
+ if(!tri->tpi)return(-3);
+ if(!tri->bri)return(-4);
+ if(!tri->fti)return(-5);
+ tpi=tri->tpi;
+ cxi=tri->cxi;
+ bri=tri->bri;
+ fti=tri->fti;
+ cxi->lines = 0;
+ cxi->paras = 0;
+ cxi->phase1 = 0;
+
+/* When debugging
+ ftinfo_dump(fti);
+*/
+ /* Phase 1. Working sequentially, insert text. Initially as TR_TEXT and then try to extend to TR_LINE by checking
+ overlaps. When done the complexes will contain a mix of TR_LINE and TR_TEXT. */
+
+ for(i=0; i<tpi->used; i++){
+ tspi = &(tpi->chunks[i]);
+ memcpy(&bsp,&(bri->rects[tspi->rt_tidx]),sizeof(BRECT_SPECS)); /* Must make a copy as next call may reallocate rects! */
+ (void) brinfo_insert(bri,&bsp);
+ dst_rt = bri->used-1;
+ (void) cxinfo_insert(cxi, i, dst_rt, TR_TEXT);
+ cxidx = cxi->used-1;
+
+ spcadv = fti->fonts[tspi->fi_idx].spcadv * tspi->fs/32.0; /* spcadv was always FT_LOAD_NO_SCALE */
+ /* for the leading text: pad with no leading and two trailing spaces, leading and trailing depend on direction */
+ if(tspi->ldir == LDIR_RL){ TR_rt_pad_set(&rt_pad_i,tri->qe, tri->qe, tri->qe + 2.0 * spcadv, 0.0); }
+ else { TR_rt_pad_set(&rt_pad_i,tri->qe, tri->qe, 0.0, tri->qe + 2.0 * spcadv); }
+
+ for(j=i+1; j<tpi->used; j++){
+ tspj = &(tpi->chunks[j]);
+ /* Reject font size changes of greater than 50%, these are almost certainly not continuous text. These happen
+ in math formulas, for instance, where a sum or integral is much larger than the other symbols. */
+ ratio = (double)(tspj->fs)/(double)(tspi->fs);
+ if(ratio >2.0 || ratio <0.5)break;
+
+ spcadv = fti->fonts[tspj->fi_idx].spcadv * tspj->fs/32.0; /* spcadv was always FT_LOAD_NO_SCALE */
+ /* for the trailing text: pad with one leading and trailing spaces (so it should work L->R and R->L) */
+ TR_rt_pad_set(&rt_pad_j,tri->qe, tri->qe, spcadv, spcadv);
+ src_rt = tspj->rt_tidx;
+
+ /* Reject direction changes like [1 <- Hebrew][2 -> English], that is where the direction changes AND the
+ next logical piece of text is "upstream" positionally of its logical predecessor. The meaning of such
+ a construct is at best ambiguous. The test is only applied with respect to the first text chunk. This sort
+ of construct may appear when a valid initial construct like [1->English][2<-Hebrew][3->English] is edited
+ and the leading chunk of text removed.
+
+ Also reject reversed order text as in (English) <A><B><C> (draw order) arranged as <C><B><A>. This happens
+ if the language direction field is incorrect, perhaps due to a corrupt or malformed input file.
+ */
+ if(brinfo_upstream(bri,
+ dst_rt, /* index into bri for dst */
+ src_rt, /* index into bri for src */
+ tspi->ldir,tspj->ldir))break;
+
+ if(!brinfo_overlap(bri,
+ dst_rt, /* index into bri for dst */
+ src_rt, /* index into bri for src */
+ &rt_pad_i,&rt_pad_j)){
+ (void) cxinfo_append(cxi,j,TR_LINE);
+ (void) brinfo_merge(bri,dst_rt,src_rt);
+ /* for the leading text: pad with two leading and trailing spaces (so it should work L->R and R->L */
+ spcadv = fti->fonts[tspj->fi_idx].spcadv * tspj->fs/32.0; /* spcadv was always FT_LOAD_NO_SCALE */
+ TR_rt_pad_set(&rt_pad_i, tri->qe, tri->qe,
+ tri->qe + 2.0 * spcadv, tri->qe + 2.0 * spcadv);
+ }
+ else { /* either alignment ge*/
+ break;
+ }
+ }
+
+ /* Bidirectional text will cause complexes to not assemble in one pass.
+ This happens whenever a change of direction occurs with 2 or more sequential elements in
+ the opposite direction,
+
+ Let + = LR and - = RL.
+
+ Reading left to right, this happens with +-- or -++.
+ For instance, the sequence ++-+ ---+ would break into the two complexes shown.
+ Not until the last element in the second complex is added will the bounding rectangles for the complexes overlap.
+
+ Check for this effect now if there is a preceding complex and the first element of the current complex is
+ reversed from the last in the preceding. */
+ if(cxidx >= 1){
+ kidp = &(cxi->cx[cxidx-1].kids);
+ kidc = &(cxi->cx[cxidx ].kids);
+ tspi = &(tpi->chunks[ kidp->members[kidp->used - 1] ]); /* here, the last text element in preceding complex */
+ tspj = &(tpi->chunks[ kidc->members[0 ] ]); /* here, tge first text element in current complex */
+ if(tspi->ldir != tspj->ldir){
+ spcadv = fti->fonts[tspi->fi_idx].spcadv * tspi->fs/32.0;
+ if(tspi->ldir == LDIR_RL){ TR_rt_pad_set(&rt_pad_i,tri->qe, tri->qe, tri->qe + 2.0 * spcadv, 0.0); }
+ else { TR_rt_pad_set(&rt_pad_i,tri->qe, tri->qe, 0.0, tri->qe + 2.0 * spcadv); }
+ spcadv = fti->fonts[tspj->fi_idx].spcadv * tspj->fs/32.0;
+ TR_rt_pad_set(&rt_pad_j,tri->qe, tri->qe, spcadv, spcadv);
+ if(!brinfo_overlap(bri,
+ cxi->cx[cxidx-1].rt_cidx, /* index into rt for dst cx */
+ cxi->cx[cxidx].rt_cidx, /* index into rt for src cx */
+ &rt_pad_i,&rt_pad_j)){
+ /* Merge the current complex into the preceding one*/
+ (void) cxinfo_merge(cxi, cxidx-1, cxidx, TR_LINE);
+ (void) brinfo_merge(bri,cxi->cx[cxidx-1].rt_cidx,cxi->cx[cxidx].rt_cidx); /* merge the bounding boxes*/
+ (void) cxinfo_trim(cxi);
+ cxi->lines--; /* else the normal line count value is one too high */
+ /* remove the current complex */
+ }
+ }
+ }
+
+ if(cxi->cx[cxidx].type == TR_LINE)cxi->lines++;
+ i=j-1; /* start up after the last merged entry (there may not be any) */
+ }
+ cxi->phase1 = cxi->used; /* total complexes defined in this phase, all TR_LINE or TR_TEXT */
+
+ /* phase 1.5, calculate kerning. This is as good a place to do it as any. At this point all kern values
+ are zero. Each of these pieces is strictly unidirectional, but each piece can have a different direction.
+ The direction of the line is set by the first text element. The ends of runs of elements which are
+ reversed with respect to the line direction are special, everything else is simple:
+ Let: + == L->R, - == R->L, $ == end of text, the rules for kerning on B are:
+ A B others xkern
+ [+|$] + + [+|$] Bll - Aur
+ [-|$] - - [-|$] All - Bur (chs)
+ + - + [-|$] Bll - Aur (chs)
+ - + - [+|$] All - Bur
+ + - -...[-=C] [+|$] All - Cur (chs)
+ - + +...[+=C] [-|$] Cll - Aur
+
+ chs = change sign, because dx is an absolute direction, and direction of text on RTL is in -x.
+
+ Kerning calculations currently seems unstable for R->L if the kerning extends to the end of the line. If
+ the first and last characters are back in sync there are no issues. When things go south R->L left justified
+ text is not justified when read in.
+ */
+
+ for(i=0; i < cxi->phase1; i++){ /* over all lines */
+ csp = &(cxi->cx[i]);
+ if(csp->kids.used < 2)continue; /* no kerning possible */
+ tspi = &tpi->chunks[csp->kids.members[0]]; /* used here as last tsp. no kerning is applied to the first element */
+ lastldir = ldir = tspi->ldir;
+ rev = 0; /* the first ldir defines forward and reverse */
+ for(j=1; j<csp->kids.used; j++){
+ tspj = &tpi->chunks[csp->kids.members[j]];
+ ldir = tspj->ldir;
+ if(ldir != lastldir){ /* direction change */
+ rev = !rev; /* reverse direction tracker */
+ if(!rev){ /* back in original orientation */
+ if(ldir == LDIR_RL){ tspj->xkern = bri->rects[tspj->rt_tidx].xur - bri->rects[tspRevStart->rt_tidx].xll; }
+ else { tspj->xkern = bri->rects[tspj->rt_tidx].xll - bri->rects[tspRevStart->rt_tidx].xur; }
+ tspj->ykern = (bri->rects[tspj->rt_tidx].yll - tspj->boff) -
+ (bri->rects[tspRevStart->rt_tidx].yll - tspRevStart->boff);
+ }
+ else { /* now in reversed orientation */
+ tspRevStart = tspj; /* Save the beginning of this run (length >=1 ) */
+ /* scan forward for the last text object in this orientation, include the first */
+ for(k=j; k <csp->kids.used; k++){
+ if(tpi->chunks[csp->kids.members[k]].ldir == ldir){ tspRevEnd = &tpi->chunks[csp->kids.members[k]]; }
+ else { break; }
+ }
+ if(lastldir == LDIR_RL){ tspj->xkern = bri->rects[tspRevEnd->rt_tidx].xur - bri->rects[tspi->rt_tidx].xll; }
+ else { tspj->xkern = bri->rects[tspRevEnd->rt_tidx].xll - bri->rects[tspi->rt_tidx].xur; }
+ tspj->ykern = (bri->rects[tspRevEnd->rt_tidx].yll - tspRevEnd->boff) -
+ (bri->rects[ tspi->rt_tidx].yll - tspi->boff );
+ }
+ }
+ else {
+ if(ldir == LDIR_RL){ tspj->xkern = bri->rects[tspj->rt_tidx].xur - bri->rects[tspi->rt_tidx].xll; }
+ else { tspj->xkern = bri->rects[tspj->rt_tidx].xll - bri->rects[tspi->rt_tidx].xur; }
+ tspj->ykern = (bri->rects[tspj->rt_tidx].yll - tspj->boff) -
+ (bri->rects[tspi->rt_tidx].yll - tspi->boff);
+ }
+
+
+ /*
+ Sometimes a font substitution was absolutely terrible, for instance, for Arial Narrow on (most) Linux systems,
+ The resulting advance (xkern) may be much too large so that it overruns the next text chunk. Since
+ overlapping text on the same line is almost never encountered, this may be used to detect the bad
+ substitution so that a more appropriate offset can be used.
+ Detect this situation as a negative dx < 1/2 a space character's width while |dy| < an entire space width.
+ The y constraints allow super and subscripts, which overlap in x but are shifted above/below in y.
+ */
+ spcadv = fti->fonts[tspj->fi_idx].spcadv * tspj->fs/32.0;
+ qsp = 0.25 * spcadv;
+ dx = tspj->xkern;
+ dy = tspj->ykern;
+ if(dy <=qsp && dy >= -qsp){
+ if(ldir==LDIR_RL){
+ if(dx > 2*qsp)tspj->xkern = 0.0;
+ }
+ else {
+ if(dx < -2*qsp)tspj->xkern = 0.0;
+ }
+ }
+
+ /* if x or y kern is less than twice the quantization error it is probably noise, set it to zero */
+ if(fabs(tspj->xkern) <= 2.0*tri->qe)tspj->xkern = 0.0;
+ if(fabs(tspj->ykern) <= 2.0*tri->qe)tspj->ykern = 0.0;
+
+ /* reintroduce spaces on the leading edge of text "j" if the kerning can be in part or in whole replaced
+ with 1 or 2 spaces */
+ if(tspj->ykern == 0.0){
+ double spaces = tspj->xkern/spcadv; /* negative on RL language, positive on LR */
+ if((ldir == LDIR_RL && (spaces <= -0.9 && spaces >= -2.1)) ||
+ (ldir == LDIR_LR && (spaces >= 0.9 && spaces <= 2.1)) ){
+ int ispaces = lround(spaces);
+ tspj->xkern -= ((double)ispaces*spcadv);
+ if(ispaces<0)ispaces=-ispaces;
+ size_t slen = strlen((char *)tspj->string);
+ uint8_t *newstring = malloc(1 + ispaces + slen);
+ sprintf((char *)newstring," "); /* start with two spaces, possibly overwrite one in the next line */
+ memcpy(newstring+ispaces,tspj->string,slen+1); /* copy existing string to proper position */
+ free(tspj->string);
+ tspj->string = newstring;
+ tspj->spaces = ispaces; // only needed to fix optional debugging SVG output later
+ }
+ }
+
+ tspi = tspj;
+ lastldir = ldir;
+ }
+ }
+
+
+ /* Phase 2, try to group sequential lines. There may be "lines" that are still TR_TEXT, as in:
+
+ ... this is a sentence that wraps by one
+ word.
+
+ And some paragrahs might be single word lines (+ = bullet in the following)
+
+ +verbs
+ +nouns
+ +adjectives
+
+ Everything starts out as TR_PARA_UJ and if the next one can be lined up, the type changes to
+ an aligned paragraph and complexes are appended to the existing one.
+ */
+
+ for(i=0; i < cxi->phase1; i++){
+ type = TR_PARA_UJ; /* any paragraph alignment will be acceptable */
+ /* Must make a copy as next call may reallocate rects, so if we just passed a pointer to something in the structure
+ it would vaporize part way through the call. */
+ memcpy(&bsp,&(bri->rects[cxi->cx[i].rt_cidx]),sizeof(BRECT_SPECS));
+ (void) brinfo_insert(bri,&bsp);
+ dst_rt = bri->used-1;
+ (void) cxinfo_insert(cxi, i, dst_rt, type);
+
+ cxi->paras++;
+ ok = 1;
+ for(j=i+1; ok && (j < cxi->phase1); j++){
+ type = brinfo_pp_alignment(bri, cxi->cx[i].rt_cidx, cxi->cx[j].rt_cidx, 3*tri->qe, type);
+ switch (type){
+ case TR_PARA_UJ: /* paragraph type was set and j line does not fit, or no paragraph alignment matched */
+ ok = 0; /* force exit from j loop */
+ j--; /* this will increment at loop bottom */
+ break;
+ case TR_PARA_LJ:
+ case TR_PARA_CJ:
+ case TR_PARA_RJ:
+ /* two successive lines have been identified (possible following others already in the paragraph */
+ if(TR_check_set_vadvance(tri,j,i)){ /* check for compatibility with vadvance if set, set it if it isn't. */
+ ok = 0; /* force exit from j loop */
+ j--; /* this will increment at loop bottom */
+ }
+ else {
+ src_rt = cxi->cx[j].rt_cidx;
+ (void) cxinfo_append(cxi, j, type);
+ (void) brinfo_merge(bri, dst_rt, src_rt);
+ }
+ break;
+ default:
+ return(-6); /* programming error */
+ }
+ }
+ if(j>=cxi->phase1)break;
+ i=j-1;
+ }
+
+
+/* When debugging
+ cxinfo_dump(tri);
+*/
+
+ return(cxi->used);
+}
+
+
+/* no doxygen documentation below this point, these pieces are for the text program, not the library. */
+
+#if TEST
+#define MAXLINE 2048 /* big enough for testing */
+enum OP_TYPES {OPCOM,OPOOPS,OPFONT,OPESC,OPORI,OPXY,OPFS,OPTEXT,OPALN,OPLDIR,OPMUL,OPITA,OPWGT,OPDEC,OPCND,OPBKG,OPCLR,OPDCLR,OPBCLR,OPFLAGS,OPEMIT,OPDONE};
+
+int parseit(char *buffer,char **data){
+ int pre;
+ pre = strcspn(buffer,":");
+ if(!pre)return(OPOOPS);
+ *data=&buffer[pre+1];
+ buffer[pre]='\0';
+ if(*buffer=='#' )return(OPCOM );
+ if(0==strcmp("FONT",buffer))return(OPFONT);
+ if(0==strcmp("ESC" ,buffer))return(OPESC );
+ if(0==strcmp("ORI", buffer))return(OPORI );
+ if(0==strcmp("XY", buffer))return(OPXY );
+ if(0==strcmp("FS", buffer))return(OPFS );
+ if(0==strcmp("TEXT",buffer))return(OPTEXT);
+ if(0==strcmp("ALN", buffer))return(OPALN );
+ if(0==strcmp("LDIR",buffer))return(OPLDIR);
+ if(0==strcmp("MUL", buffer))return(OPMUL );
+ if(0==strcmp("ITA", buffer))return(OPITA );
+ if(0==strcmp("WGT", buffer))return(OPWGT );
+ if(0==strcmp("DEC", buffer))return(OPDEC );
+ if(0==strcmp("CND", buffer))return(OPCND );
+ if(0==strcmp("BKG", buffer))return(OPBKG );
+ if(0==strcmp("CLR", buffer))return(OPCLR );
+ if(0==strcmp("DCLR", buffer))return(OPDCLR );
+ if(0==strcmp("BCLR",buffer))return(OPBCLR );
+ if(0==strcmp("FLAG",buffer))return(OPFLAGS);
+ if(0==strcmp("EMIT",buffer))return(OPEMIT);
+ if(0==strcmp("DONE",buffer))return(OPDONE);
+ return(OPOOPS);
+}
+
+void boom(char *string,int lineno){
+ fprintf(stderr,"Fatal error at line %d %s\n",lineno,string);
+ exit(EXIT_FAILURE);
+}
+
+
+void init_as_svg(TR_INFO *tri){
+ TRPRINT(tri,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
+ TRPRINT(tri,"<!-- Created with Inkscape (http://www.inkscape.org/) -->\n");
+ TRPRINT(tri,"\n");
+ TRPRINT(tri,"<svg\n");
+ TRPRINT(tri," xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n");
+ TRPRINT(tri," xmlns:cc=\"http://creativecommons.org/ns#\"\n");
+ TRPRINT(tri," xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n");
+ TRPRINT(tri," xmlns:svg=\"http://www.w3.org/2000/svg\"\n");
+ TRPRINT(tri," xmlns=\"http://www.w3.org/2000/svg\"\n");
+ TRPRINT(tri," xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n");
+ TRPRINT(tri," xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"\n");
+ TRPRINT(tri," width=\"900\"\n");
+ TRPRINT(tri," height=\"675\"\n");
+ TRPRINT(tri," id=\"svg4122\"\n");
+ TRPRINT(tri," version=\"1.1\"\n");
+ TRPRINT(tri," inkscape:version=\"0.48+devel r11679 custom\"\n");
+ TRPRINT(tri," sodipodi:docname=\"simplest_text.svg\">\n");
+ TRPRINT(tri," <defs\n");
+ TRPRINT(tri," id=\"defs4124\" />\n");
+ TRPRINT(tri," <sodipodi:namedview\n");
+ TRPRINT(tri," id=\"base\"\n");
+ TRPRINT(tri," pagecolor=\"#ffffff\"\n");
+ TRPRINT(tri," bordercolor=\"#666666\"\n");
+ TRPRINT(tri," borderopacity=\"1.0\"\n");
+ TRPRINT(tri," inkscape:pageopacity=\"0.0\"\n");
+ TRPRINT(tri," inkscape:pageshadow=\"2\"\n");
+ TRPRINT(tri," inkscape:zoom=\"0.98994949\"\n");
+ TRPRINT(tri," inkscape:cx=\"309.88761\"\n");
+ TRPRINT(tri," inkscape:cy=\"482.63995\"\n");
+ TRPRINT(tri," inkscape:document-units=\"px\"\n");
+ TRPRINT(tri," inkscape:current-layer=\"layer1\"\n");
+ TRPRINT(tri," showgrid=\"false\"\n");
+ TRPRINT(tri," width=\"0px\"\n");
+ TRPRINT(tri," height=\"0px\"\n");
+ TRPRINT(tri," fit-margin-top=\"0\"\n");
+ TRPRINT(tri," fit-margin-left=\"0\"\n");
+ TRPRINT(tri," fit-margin-right=\"0\"\n");
+ TRPRINT(tri," fit-margin-bottom=\"0\"\n");
+ TRPRINT(tri," units=\"in\"\n");
+ TRPRINT(tri," inkscape:window-width=\"1200\"\n");
+ TRPRINT(tri," inkscape:window-height=\"675\"\n");
+ TRPRINT(tri," inkscape:window-x=\"26\"\n");
+ TRPRINT(tri," inkscape:window-y=\"51\"\n");
+ TRPRINT(tri," inkscape:window-maximized=\"0\" />\n");
+ TRPRINT(tri," <metadata\n");
+ TRPRINT(tri," id=\"metadata4127\">\n");
+ TRPRINT(tri," <rdf:RDF>\n");
+ TRPRINT(tri," <cc:Work\n");
+ TRPRINT(tri," rdf:about=\"\">\n");
+ TRPRINT(tri," <dc:format>image/svg+xml</dc:format>\n");
+ TRPRINT(tri," <dc:type\n");
+ TRPRINT(tri," rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n");
+ TRPRINT(tri," <dc:title></dc:title>\n");
+ TRPRINT(tri," </cc:Work>\n");
+ TRPRINT(tri," </rdf:RDF>\n");
+ TRPRINT(tri," </metadata>\n");
+ TRPRINT(tri," <g\n");
+ TRPRINT(tri," inkscape:label=\"Layer 1\"\n");
+ TRPRINT(tri," inkscape:groupmode=\"layer\"\n");
+ TRPRINT(tri," id=\"layer1\"\n");
+ TRPRINT(tri," transform=\"translate(0,0)\">\n");
+ TRPRINT(tri,"\n");
+}
+
+
+void flush_as_svg(TR_INFO *tri, FILE *fp){
+ fwrite(tri->out,tri->outused,1,fp);
+}
+
+FILE *close_as_svg(TR_INFO *tri, FILE *fp){
+ TRPRINT(tri, " </g>\n");
+ TRPRINT(tri, "</svg>\n");
+ flush_as_svg(tri,fp);
+ fclose(fp);
+ return(NULL);
+}
+
+
+int main(int argc, char *argv[]){
+ char *data;
+ char inbuf[MAXLINE];
+ FILE *fpi = NULL;
+ FILE *fpo = NULL;
+ int op;
+ double fact = 1.0; /* input units to points */
+ double escapement = 0.0; /* degrees */
+ int lineno = 0;
+ int ok = 1;
+ int status;
+ TCHUNK_SPECS tsp;
+ TR_INFO *tri=NULL;
+ int flags=0;
+ char *infile;
+ uint32_t utmp32;
+ TRCOLORREF bkcolor;
+ int bkmode;
+ char *fontspec;
+
+ infile=malloc(strlen(argv[1])+1);
+ strcpy(infile,argv[1]);
+
+ if(argc < 2 || !(fpi = fopen(infile,"r"))){
+ printf("Usage: text_reassemble input_file\n");
+ printf(" Test program reads an input file containing lines like:\n");
+ printf(" FONT:(font for next text)\n");
+ printf(" ESC:(escapement angle degrees of text line, up from X axis)\n");
+ printf(" ORI:(angle degrees of character orientation, up from X axis)\n");
+ printf(" FS:(font size, units)\n");
+ printf(" XY:(x,y) X 0 is at left, N is at right, Y 0 is at top, N is at bottom, as page is viewed.\n");
+ printf(" TEXT:(UTF8 text)\n");
+ printf(" ALN:combination of {LCR}{BLT} = Text is placed on {X,Y} at Left/Center/Right of text, at Bottom,baseLine,Top of text.\n");
+ printf(" LDIR:{LR|RL|TB) Left to Right, Right to Left, and Top to Bottom \n");
+ printf(" MUL:(float, multiplicative factor to convert FS,XY units to points).\n");
+ printf(" ITA:(Italics, 0=normal, 100=italics, 110=oblique).\n");
+ printf(" WGT:(Weight, 0-215: 80=normal, 200=bold, 215=ultrablack, 0=thin)).\n");
+ printf(" DEC:(this is a bit field. For color see DCLR\n");
+ printf(" style: 000 none, 001 underline,002 overline, 004 blink, 008 strike-through\n");
+ printf(" line: 000 solid, 010 double, 020 dotted, 040 dashed, 080 wavy)\n");
+ printf(" CND:(Condensed 50-200: 100=normal, 50=ultracondensed, 75=condensed, 200=expanded).\n");
+ printf(" BKG:(Background color: 0 none, 1 by input fragment, 2 by assembled line, 3 by entire assembly. Use BCLR, THEN BKG) \n");
+ printf(" CLR:(Text RGB color, as 6 HEX digits, like: FF0000 (red) or 0000FF (blue)) \n");
+ printf(" DCLR:(Decoration color, specify like CLR, except 1000000 or higher disables.)\n");
+ printf(" BCLR:(Background RGB color, specify like CLR.) \n");
+ printf(" FLAG: Special processing options. 1 EMF compatible text alignment.\n");
+ printf(" EMIT:(Process everything up to this point, then start clean for remaining input).\n");
+ printf(" DONE:(no more input, process it).\n");
+ printf(" # comment\n");
+ printf("\n");
+ printf(" The output is a summary of how the pieces are to be assembled into complex text.\n");
+ printf("\n");
+ printf(" egrep pattern: '^LOAD:|^FONT:|^ESC:|^ORI:|^FS:|^XY:|^TEXT:|^ALN:|^LDIR:|^MUL:|^ITA:|^WGT:|^DEC:|^CND:|^BKG:|^CLR:|^BCLR:|^DCLR:|^FLAG:|^EMIT:^DONE:'\n");
+ exit(EXIT_FAILURE);
+ }
+
+ tri = trinfo_init(tri); /* If it loops the trinfo_clear at the end will reset tri to the proper state, do NOT call trinfo_init twice! */
+
+#ifdef DBG_LOOP
+ int ldx;
+ for(ldx=0;ldx<5;ldx++){
+ if(fpi)fclose(fpi);
+ fpi = fopen(infile,"r");
+#endif
+ tsp.string = NULL;
+ tsp.ori = 0.0; /* degrees */
+ tsp.fs = 12.0; /* font size */
+ tsp.x = 0.0;
+ tsp.y = 0.0;
+ tsp.boff = 0.0; /* offset to baseline from LL corner of bounding rectangle, changes with fs and taln*/
+ tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */
+ tsp.taln = ALILEFT + ALIBASE;
+ tsp.ldir = LDIR_LR;
+ tsp.color.Red = tsp.decColor.Red = 0; /* RGBA Black */
+ tsp.color.Green = tsp.decColor.Green = 0; /* RGBA Black */
+ tsp.color.Blue = tsp.decColor.Blue = 0; /* RGBA Black */
+ tsp.color.Reserved = tsp.decColor.Reserved = 0; /* unused */
+ tsp.italics = 0;
+ tsp.weight = 80;
+ tsp.condensed = 100;
+ tsp.decoration = 0; /* none */
+ tsp.spaces = 0; /* none */
+ tsp.fi_idx = -1; /* set to an invalid */
+ tsp.rt_tidx = -1; /* set to an invalid */
+ tsp.xkern = tsp.ykern = 0.0;
+ /* no need to set rt_tidx */
+
+
+
+ if(!tri){
+ fprintf(stderr,"Fatal error, could not initialize data structures\n");
+ exit(EXIT_FAILURE);
+ }
+ (void) trinfo_load_ft_opts(tri, 1,
+ FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP,
+ FT_KERNING_UNSCALED);
+
+ fpo=fopen("dump.svg","wb");
+ init_as_svg(tri);
+
+ while(ok){
+ lineno++;
+ if(!fgets(inbuf,MAXLINE,fpi))boom("Unexpected end of file - no DONE:",lineno);
+ inbuf[strlen(inbuf)-1]='\0'; /* step on the EOL character */
+ op = parseit(inbuf,&data);
+ switch(op){
+ case OPCOM: /* ignore comments*/
+ break;
+ case OPFONT:
+ /* If the font name includes "Narrow" condensed may not have been set */
+ if(0<= TR_findcasesub(data, "Narrow")){
+ tsp.co=1;
+ }
+ else {
+ tsp.co=0;
+ }
+ fontspec = TR_construct_fontspec(&tsp, data);
+ if((tsp.fi_idx = ftinfo_load_fontname(tri->fti, fontspec)) < 0 )boom("Font load failed",lineno);
+ free(fontspec);
+ break;
+ case OPESC:
+ if(1 != sscanf(data,"%lf",&escapement))boom("Invalid ESC:",lineno);
+ break;
+ case OPORI:
+ if(1 != sscanf(data,"%lf",&tsp.ori))boom("Invalid ORI:",lineno);
+ break;
+ case OPFS:
+ if(1 != sscanf(data,"%lf",&tsp.fs) || tsp.fs <= 0.0)boom("Invalid FS:",lineno);
+ tsp.fs *= fact;
+ break;
+ case OPXY:
+ if(2 != sscanf(data,"%lf,%lf",&tsp.x,&tsp.y) )boom("Invalid XY:",lineno);
+ tsp.x *= fact;
+ tsp.y *= fact;
+ break;
+ case OPTEXT:
+ tsp.string = (uint8_t *) U_strdup(data);
+ /* FreeType parameters match inkscape*/
+ status = trinfo_load_textrec(tri, &tsp, escapement,flags);
+ if(status==-1){ // change of escapement, emit what we have and reset
+ TR_layout_analyze(tri);
+ TR_layout_2_svg(tri);
+ flush_as_svg(tri, fpo);
+ tri = trinfo_clear(tri);
+ if(trinfo_load_textrec(tri, &tsp, escapement,flags)){ boom("Text load failed",lineno); }
+ }
+ else if(status){ boom("Text load failed",lineno); }
+ break;
+ case OPALN:
+ tsp.taln=0;
+ switch (*data++){
+ case 'L': tsp.taln |= ALILEFT; break;
+ case 'C': tsp.taln |= ALICENTER; break;
+ case 'R': tsp.taln |= ALIRIGHT; break;
+ default: boom("Invalid ALN:",lineno);
+ }
+ switch (*data++){
+ case 'T': tsp.taln |= ALITOP; break;
+ case 'L': tsp.taln |= ALIBASE; break;
+ case 'B': tsp.taln |= ALIBOT; break;
+ default: boom("Invalid ALN:",lineno);
+ }
+ break;
+ case OPLDIR:
+ tsp.ldir=0;
+ if(0==strcmp("LR",data)){ tsp.ldir=LDIR_LR; break;}
+ if(0==strcmp("RL",data)){ tsp.ldir=LDIR_RL; break;}
+ if(0==strcmp("TB",data)){ tsp.ldir=LDIR_TB; break;}
+ boom("Invalid LDIR:",lineno);
+ break;
+ case OPMUL:
+ if(1 != sscanf(data,"%lf",&fact) || fact <= 0.0)boom("Invalid MUL:",lineno);
+ (void) trinfo_load_qe(tri,fact);
+ break;
+ case OPITA:
+ if(1 != sscanf(data,"%d",&tsp.italics) || tsp.italics < 0 || tsp.italics>110)boom("Invalid ITA:",lineno);
+ break;
+ case OPWGT:
+ if(1 != sscanf(data,"%d",&tsp.weight) || tsp.weight < 0 || tsp.weight > 215)boom("Invalid WGT:",lineno);
+ break;
+ case OPDEC:
+ if(1 != sscanf(data,"%X",(unsigned int *) &tsp.decoration))boom("Invalid DEC:",lineno);
+ break;
+ case OPCND:
+ if(1 != sscanf(data,"%d",&tsp.condensed) || tsp.condensed < 50 || tsp.condensed > 200)boom("Invalid CND:",lineno);
+ break;
+ case OPBKG:
+ if(1 != sscanf(data,"%d",&bkmode) )boom("Invalid BKG:",lineno);
+ (void) trinfo_load_bk(tri,bkmode,bkcolor);
+ break;
+ case OPCLR:
+ if(1 != sscanf(data,"%x",&utmp32) )boom("Invalid CLR:",lineno);
+ tsp.color.Red = (utmp32 >> 16) & 0xFF;
+ tsp.color.Green = (utmp32 >> 8) & 0xFF;
+ tsp.color.Blue = (utmp32 >> 0) & 0xFF;
+ tsp.color.Reserved = 0;
+ break;
+ case OPDCLR:
+ if(1 != sscanf(data,"%x",&utmp32) )boom("Invalid DCLR:",lineno);
+ if(utmp32 >= 0x1000000){
+ tsp.decColor.Red = tsp.decColor.Green = tsp.decColor.Blue = tsp.decColor.Reserved = 0;
+ tsp.decoration &= ~TXTDECOR_CLRSET;
+ }
+ else {
+ tsp.decColor.Red = (utmp32 >> 16) & 0xFF;
+ tsp.decColor.Green = (utmp32 >> 8) & 0xFF;
+ tsp.decColor.Blue = (utmp32 >> 0) & 0xFF;
+ tsp.decColor.Reserved = 0;
+ tsp.decoration |= TXTDECOR_CLRSET;
+ }
+ break;
+ case OPBCLR:
+ if(1 != sscanf(data,"%x",&utmp32) )boom("Invalid BCLR:",lineno);
+ bkcolor.Red = (utmp32 >> 16) & 0xFF;
+ bkcolor.Green = (utmp32 >> 8) & 0xFF;
+ bkcolor.Blue = (utmp32 >> 0) & 0xFF;
+ bkcolor.Reserved = 0;
+ break;
+ case OPFLAGS:
+ if(1 != sscanf(data,"%d",&flags) )boom("Invalid FLAG:",lineno);
+ break;
+ case OPEMIT:
+ TR_layout_analyze(tri);
+ TR_layout_2_svg(tri);
+ flush_as_svg(tri, fpo);
+ tri = trinfo_clear(tri);
+ break;
+ case OPDONE:
+ TR_layout_analyze(tri);
+ TR_layout_2_svg(tri);
+ flush_as_svg(tri, fpo);
+ tri = trinfo_clear(tri);
+ ok = 0;
+ break;
+ case OPOOPS:
+ default:
+ boom("Input line cannot be parsed",lineno);
+ break;
+ }
+
+ }
+
+ if(fpo){
+ fpo=close_as_svg(tri, fpo);
+ }
+
+
+#ifdef DBG_LOOP
+ tri = trinfo_clear(tri);
+ ok = 1;
+ }
+#endif /* DBG_LOOP */
+
+ fclose(fpi);
+ tri = trinfo_release(tri);
+ free(infile);
+
+ exit(EXIT_SUCCESS);
+}
+#endif /* TEST */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/extension/internal/text_reassemble.h b/src/extension/internal/text_reassemble.h
new file mode 100644
index 000000000..6c1acafe5
--- /dev/null
+++ b/src/extension/internal/text_reassemble.h
@@ -0,0 +1,387 @@
+/**
+ @file text_reassemble.h libTERE headers.
+
+See text_reassemble.c for notes
+
+File: text_reassemble.h
+Version: 0.0.13
+Date: 06-FEB-2014
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2014 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _TEXT_REASSEMBLE_
+#define _TEXT_REASSEMBLE_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <fontconfig/fontconfig.h>
+#include <ft2build.h>
+#include <iconv.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+/** \cond */
+#define TEREMIN(A,B) (A < B ? A : B)
+#define TEREMAX(A,B) (A > B ? A : B)
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846 /* pi */
+#endif
+#define ALLOCINFO_CHUNK 32
+#define ALLOCOUT_CHUNK 8192
+#define TRPRINT trinfo_append_out
+/** \endcond */
+
+/** \defgroup color background options
+ Text is underwritten with the background color not at all,
+ by reassembled line, or by full assembly .
+ @{
+*/
+#define BKCLR_NONE 0x00 /**< text is not underwritten with background color (default) */
+#define BKCLR_FRAG 0x01 /**< each fragment of text is underwritten with background color */
+#define BKCLR_LINE 0x02 /**< each line of text is underwritten with background color */
+#define BKCLR_ALL 0x03 /**< entire assembly is underwritten with background color */
+/** @} */
+
+/** \defgroup decoration options
+ One of these values may be present in the decoration field.
+ Unused bits may be used by end user code.
+ These values are SVG specific. Other applications could use the text
+ decoration field for a different set of bits, so long as it provided its own
+ output function.
+ @{
+*/
+#define TXTDECOR_NONE 0x000 /**< text is not decorated (default) */
+#define TXTDECOR_UNDER 0x001 /**< underlined */
+#define TXTDECOR_OVER 0x002 /**< overlined */
+#define TXTDECOR_BLINK 0x004 /**< blinking text */
+#define TXTDECOR_STRIKE 0x008 /**< strike through */
+#define TXTDECOR_TMASK 0x00F /**< Mask for selecting bits above */
+
+#define TXTDECOR_SOLID 0x000 /**< draw as single solid line */
+#define TXTDECOR_DOUBLE 0x010 /**< draw as double solid line */
+#define TXTDECOR_DOTTED 0x020 /**< draw as single dotted line */
+#define TXTDECOR_DASHED 0x040 /**< draw as single dashed line */
+#define TXTDECOR_WAVY 0x080 /**< draw as single wavy line */
+#define TXTDECOR_LMASK 0x0F0 /**< Mask for selecting these bits */
+
+#define TXTDECOR_CLRSET 0x100 /**< decoration has its own color */
+
+/** @} */
+
+
+
+
+
+/** \defgroup text alignment types
+ Location of text's {X,Y} coordinate on bounding rectangle.
+ Values are compatible with Fontconfig.
+ @{
+*/
+#define ALILEFT 0x01 /**< text object horizontal alignment = left */
+#define ALICENTER 0x02 /**< text object horizontal alignment = center */
+#define ALIRIGHT 0x04 /**< text object horizontal alignment = right */
+#define ALIHORI 0x07 /**< text object horizontal alignment mask */
+#define ALITOP 0x08 /**< text object vertical alignment = top */
+#define ALIBASE 0x10 /**< text object vertical alignment = baseline */
+#define ALIBOT 0x20 /**< text object vertical alignment = bottom */
+#define ALIVERT 0x38 /**< text object vertical alignment mask */
+/** @} */
+
+/** \defgroup language direction types
+ @{
+*/
+#define LDIR_LR 0x00 /**< left to right */
+#define LDIR_RL 0x01 /**< right to left */
+#define LDIR_TB 0x02 /**< top to bottom */
+/** @} */
+
+/** \defgroup special processing flags
+ @{
+*/
+#define TR_EMFBOT 0x01 /**< use an approximation compatible with EMF file's "BOTTOM" text orientation, which is not the "bottom" for Freetype fonts */
+/** @} */
+
+/** \enum tr_classes
+classification of complexes
+ @{
+*/
+enum tr_classes {
+ TR_TEXT, /**< simple text object */
+ TR_LINE, /**< linear assembly of TR_TEXTs */
+ TR_PARA_UJ, /**< sequential assembly of TR_LINEs and TR_TEXTs into a paragraph -
+ unknown justification properties */
+ TR_PARA_LJ, /**< ditto, left justified */
+ TR_PARA_CJ, /**< ditto, center justified */
+ TR_PARA_RJ /**< ditto, right justified */
+ };
+/** @} */
+
+/**
+ \brief alt font entries.
+*/
+typedef struct {
+ uint32_t fi_idx; /**< index into FT_INFO fonts, for fonts added for missing glyphs */
+ uint32_t weight; /**< integer weight for alt fonts, kept sorted into descending order */
+} ALT_SPECS;
+
+/**
+ \brief Information for a font instance.
+*/
+typedef struct {
+ FcFontSet *fontset; /**< all matching fonts (for fallback on missing glyphs) */
+ ALT_SPECS *alts; /**< index into FT_INFO fonts, for fonts added for missing glyphs */
+ uint32_t space; /**< alts storage slots allocated */
+ uint32_t used; /**< alts storage slots in use */
+ FT_Face face; /**< font face structures (FT_FACE is a pointer!) */
+ uint8_t *file; /**< pointer to font paths to files */
+ uint8_t *fontspec; /**< pointer to a font specification (name:italics, etc.) */
+ FcPattern *fpat; /**< current font, must hang onto this or faces operations break */
+ double spcadv; /**< advance equal to a space, in points at font's face size */
+ double fsize; /**< font's face size in points */
+} FNT_SPECS;
+
+/**
+ \brief Information for all font instances.
+*/
+typedef struct {
+ FT_Library library; /**< Fontconfig handle */
+ FNT_SPECS *fonts; /**< Array of fontinfo structures */
+ uint32_t space; /**< storage slots allocated */
+ uint32_t used; /**< storage slots in use */
+} FT_INFO;
+
+typedef struct {
+ uint8_t Red; //!< Red color (0-255)
+ uint8_t Green; //!< Green color (0-255)
+ uint8_t Blue; //!< Blue color (0-255)
+ uint8_t Reserved; //!< Not used
+} TRCOLORREF;
+
+/**
+ \brief Information for a single text object
+*/
+typedef struct {
+ uint8_t *string; /**< UTF-8 text */
+ double ori; /**< Orientation, angle of characters with respect to baseline in degrees */
+ double fs; /**< font size of text */
+ double x; /**< x coordinate, relative to TR_INFO x,y, in points */
+ double y; /**< y coordinate, relative to TR_INFO x,y, in points */
+ double xkern; /**< x kern relative to preceding text chunk in complex (if any) */
+ double ykern; /**< y kern relative to preceding text chunk in complex (if any) */
+ double boff; /**< Y LL corner - boff finds baseline */
+ double vadvance; /**< Line spacing typically 1.25 or 1.2, only set on the first text
+ element in a complex */
+ TRCOLORREF color; /**< RGB */
+ int taln; /**< text alignment with respect to x,y */
+ int ldir; /**< language diretion LDIR_* */
+ int italics; /**< italics, as in FontConfig */
+ int weight; /**< weight, as in FontConfig */
+ int condensed; /**< condensed, as in FontConfig */
+ int decoration; /**< text decorations, ignored during assembly, used during output */
+ int spaces; /**< count of spaces converted from wide kerning (1 or 2) */
+ TRCOLORREF decColor; /**< text decoration color, ignored during assembly, used during output */
+ int co; /**< condensed override, if set Font name included narrow */
+ int rt_tidx; /**< index of rectangle that contains it */
+ int fi_idx; /**< index of the font it uses */
+} TCHUNK_SPECS;
+
+/**
+ \brief Information for all text objects.
+ Coordinates here are INTERNAL, after offset/rotate using values in TR_INFO.
+*/
+typedef struct {
+ TCHUNK_SPECS *chunks; /**< text chunks */
+ uint32_t space; /**< storage slots allocated */
+ uint32_t used; /**< storage slots in use */
+} TP_INFO;
+
+/**
+ \brief Information for a single bounding rectangle.
+ Coordinates here are INTERNAL, after offset/rotate using values in TR_INFO.
+*/
+typedef struct {
+ double xll; /**< x rectangle lower left corner */
+ double yll; /**< y " */
+ double xur; /**< x upper right corner */
+ double yur; /**< y " */
+ double xbearing; /**< x bearing of the leftmost character */
+} BRECT_SPECS;
+
+/**
+ \brief Information for all bounding rectangles.
+*/
+typedef struct {
+ BRECT_SPECS *rects; /**< bounding rectangles */
+ uint32_t space; /**< storage slots allocated */
+ uint32_t used; /**< storage slots in use */
+} BR_INFO;
+
+/**
+ \brief List of all members of a single complex.
+*/
+typedef struct {
+ int *members; /**< array of immediate children (for TR_PARA_* these are indicies
+ for TR_TEXT or TR_LINE complexes also in cxi. For TR_TEXT
+ and TR_LINE these are indices to the actual text in tpi.) */
+ uint32_t space; /**< storage slots allocated */
+ uint32_t used; /**< storage slots in use */
+} CHILD_SPECS;
+
+/**
+ \brief Information for a single complex.
+*/
+typedef struct {
+ int rt_cidx; /**< index of rectangle that contains all members */
+ enum tr_classes type; /**< classification of the complex */
+ CHILD_SPECS kids; /**< immediate child nodes of this complex, for type TR_TEXT the
+ idx refers to the tpi data. otherwise, cxi data */
+} CX_SPECS;
+
+/**
+ \brief Information for all complexes.
+*/
+typedef struct {
+ CX_SPECS *cx; /**< complexes */
+ uint32_t space; /**< storage slots allocated */
+ uint32_t used; /**< storage slots in use */
+ uint32_t phase1; /**< Number of complexes (lines + text fragments) entered in phase 1 */
+ uint32_t lines; /**< Number of lines in phase 1 */
+ uint32_t paras; /**< Number of complexes (paras) entered in phase 2 */
+} CX_INFO;
+
+/**
+ \brief Information for the entire text reassembly system.
+*/
+typedef struct {
+ FT_INFO *fti; /**< Font info storage */
+ TP_INFO *tpi; /**< Text Info/Position Info storage */
+ BR_INFO *bri; /**< Bounding Rectangle Info storage */
+ CX_INFO *cxi; /**< Complex Info storage */
+ uint8_t *out; /**< buffer to hold formatted output */
+ double qe; /**< quantization error in points. */
+ double esc; /**< escapement angle in DEGREES */
+ double x; /**< x coordinate of first text object, in points */
+ double y; /**< y coordinate of first text object, in points */
+ int dirty; /**< 1 if text records are loaded */
+ int use_kern; /**< 1 if kerning is used, 0 if not */
+ int load_flags; /**< FT_LOAD_NO_SCALE or FT_LOAD_TARGET_NORMAL */
+ int kern_mode; /**< FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED */
+ uint32_t outspace; /**< storage in output buffer allocated */
+ uint32_t outused; /**< storage in output buffer in use */
+ int usebk; /**< On output write the background color under the text */
+ TRCOLORREF bkcolor; /**< RGB background color */
+} TR_INFO;
+
+/* padding added to rectangles before overlap test */
+/**
+ \brief Information for one padding record. (Padding is added to bounding rectangles before overlap tests.)
+*/
+typedef struct {
+ double up; /**< to top */
+ double down; /**< to bottom */
+ double left; /**< to left */
+ double right; /**< to right */
+} RT_PAD;
+
+/** \cond */
+/*
+ iconv() has a funny cast on some older systems, on most recent ones
+ it is just char **. This tries to work around the issue. If you build this
+ on another funky system this code may need to be modified, or define ICONV_CAST
+ on the compile line(but it may be tricky).
+*/
+#ifdef SOL8
+#define ICONV_CAST (const char **)
+#endif //SOL8
+#if !defined(ICONV_CAST)
+#define ICONV_CAST (char **)
+#endif //ICONV_CAST
+/** \endcond */
+
+/* Prototypes */
+int TR_findcasesub(const char *string, const char *sub);
+char *TR_construct_fontspec(const TCHUNK_SPECS *tsp, const char *fontname);
+char *TR_reconstruct_fontspec(const char *fontspec, const char *fontname);
+int TR_find_alternate_font(FT_INFO *fti, FNT_SPECS **efsp, uint32_t wc);
+int TR_getadvance(FT_INFO *fti, FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int load_flags, int kern_mode, int *ymin, int *ymax);
+int TR_getkern2(FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int kern_mode);
+int TR_kern_gap(FNT_SPECS *fsp, TCHUNK_SPECS *tsp, TCHUNK_SPECS *ptsp, int kern_mode);
+void TR_rt_pad_set(RT_PAD *rt_pad, double up, double down, double left, double right);
+double TR_baseline(TR_INFO *tri, int src, double *AscMax, double *DscMax);
+int TR_check_set_vadvance(TR_INFO *tri, int src, int lines);
+int TR_layout_analyze(TR_INFO *tri);
+void TR_layout_2_svg(TR_INFO *tri);
+int TR_weight_FC_to_SVG(int weight);
+
+FT_INFO *ftinfo_init(void);
+int ftinfo_make_insertable(FT_INFO *fti);
+int ftinfo_insert(FT_INFO *fti, FNT_SPECS *fsp);
+FT_INFO *ftinfo_release(FT_INFO *fti);
+FT_INFO *ftinfo_clear(FT_INFO *fti);
+int ftinfo_find_loaded_by_spec(const FT_INFO *fti, const uint8_t *fname);
+int ftinfo_find_loaded_by_src(const FT_INFO *fti, const uint8_t *filename);
+int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec);
+void ftinfo_dump(const FT_INFO *fti);
+
+int fsp_alts_make_insertable(FNT_SPECS *fsp);
+int fsp_alts_insert(FNT_SPECS *fsp, uint32_t fi_idx);
+int fsp_alts_weight(FNT_SPECS *fsp, uint32_t a_idx);
+
+int csp_make_insertable(CHILD_SPECS *csp);
+int csp_insert(CHILD_SPECS *csp, int src);
+int csp_merge(CHILD_SPECS *dst, CHILD_SPECS *src);
+void csp_release(CHILD_SPECS *csp);
+void csp_clear(CHILD_SPECS *csp);
+
+CX_INFO *cxinfo_init(void);
+int cxinfo_make_insertable(CX_INFO *cxi);
+int cxinfo_insert(CX_INFO *cxi, int src, int src_rt_idx, enum tr_classes type);
+int cxinfo_append(CX_INFO *cxi, int src, enum tr_classes type);
+int cxinfo_merge(CX_INFO *cxi, int dst, int src, enum tr_classes type);
+int cxinfo_trim(CX_INFO *cxi);
+CX_INFO *cxinfo_release(CX_INFO *cxi);
+void cxinfo_dump(const TR_INFO *tri);
+
+TP_INFO *tpinfo_init(void);
+int tpinfo_make_insertable(TP_INFO *tpi);
+int tpinfo_insert(TP_INFO *tpi, const TCHUNK_SPECS *tsp);
+TP_INFO *tpinfo_release(TP_INFO *tpi);
+
+BR_INFO *brinfo_init(void);
+int brinfo_make_insertable(BR_INFO *bri);
+int brinfo_insert(BR_INFO *bri, const BRECT_SPECS *element);
+int brinfo_merge(BR_INFO *bri, int dst, int src);
+enum tr_classes
+ brinfo_pp_alignment(const BR_INFO *bri, int dst, int src, double slop, enum tr_classes type);
+int brinfo_overlap(const BR_INFO *bri, int dst, int src, RT_PAD *rp_dst, RT_PAD *rp_src);
+BR_INFO *brinfo_release(BR_INFO *bri);
+
+TR_INFO *trinfo_init(TR_INFO *tri);
+TR_INFO *trinfo_release(TR_INFO *tri);
+TR_INFO *trinfo_release_except_FC(TR_INFO *tri);
+TR_INFO *trinfo_clear(TR_INFO *tri);
+int trinfo_load_qe(TR_INFO *tri, double qe);
+int trinfo_load_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor);
+int trinfo_load_ft_opts(TR_INFO *tri, int use_kern, int load_flags, int kern_mode);
+int trinfo_load_textrec(TR_INFO *tri, const TCHUNK_SPECS *tsp, double escapement, int flags);
+int trinfo_check_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor);
+int trinfo_append_out(TR_INFO *tri, const char *src);
+
+int is_mn_unicode(int test);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _TEXT_REASSEMBLE_ */
diff --git a/src/extension/internal/vsd-input.cpp b/src/extension/internal/vsd-input.cpp
new file mode 100644
index 000000000..6fc79237b
--- /dev/null
+++ b/src/extension/internal/vsd-input.cpp
@@ -0,0 +1,339 @@
+/*
+ * This file came from libwpg as a source, their utility wpg2svg
+ * specifically. It has been modified to work as an Inkscape extension.
+ * The Inkscape extension code is covered by this copyright, but the
+ * rest is covered by the one bellow.
+ *
+ * Authors:
+ * Fridrich Strba (fridrich.strba@bluewin.ch)
+ *
+ * Copyright (C) 2012 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ *
+ */
+
+#include <stdio.h>
+#include "config.h"
+
+#include "vsd-input.h"
+
+#ifdef WITH_LIBVISIO
+
+#include <string>
+#include <cstring>
+
+#include <libvisio/libvisio.h>
+#include <libwpd-stream/libwpd-stream.h>
+
+#include <gtkmm/alignment.h>
+#include <gtkmm/comboboxtext.h>
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/frame.h>
+#include <gtkmm/scale.h>
+
+#include "extension/system.h"
+#include "extension/input.h"
+#include "document.h"
+
+#include "document-private.h"
+#include "document-undo.h"
+#include "inkscape.h"
+#include "util/units.h"
+
+#include "dialogs/dialog-events.h"
+#include <gtk/gtk.h>
+#include "ui/widget/spinbutton.h"
+#include "ui/widget/frame.h"
+#include <glibmm/i18n.h>
+
+#include <gdkmm/general.h>
+
+#include "svg-view.h"
+#include "svg-view-widget.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+
+class VsdImportDialog : public Gtk::Dialog {
+public:
+ VsdImportDialog(const std::vector<WPXString> &vec);
+ virtual ~VsdImportDialog();
+
+ bool showDialog();
+ unsigned getSelectedPage();
+ void getImportSettings(Inkscape::XML::Node *prefs);
+
+private:
+ void _setPreviewPage(unsigned page);
+
+ // Signal handlers
+#if !WITH_GTKMM_3_0
+ bool _onExposePreview(GdkEventExpose *event);
+#endif
+
+ void _onPageNumberChanged();
+
+ class Gtk::Button * cancelbutton;
+ class Gtk::Button * okbutton;
+ class Gtk::Label * _labelSelect;
+ class Inkscape::UI::Widget::SpinButton * _pageNumberSpin;
+ class Gtk::Label * _labelTotalPages;
+ class Gtk::VBox * vbox1;
+ class Gtk::VBox * vbox2;
+ class Gtk::Widget * _previewArea;
+
+ const std::vector<WPXString> &_vec; // Document to be imported
+ unsigned _current_page; // Current selected page
+ int _preview_width, _preview_height; // Size of the preview area
+};
+
+VsdImportDialog::VsdImportDialog(const std::vector<WPXString> &vec)
+ : _vec(vec), _current_page(1)
+{
+ int num_pages = _vec.size();
+ if ( num_pages <= 1 )
+ return;
+ cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel")));
+ okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok")));
+ _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:")));
+
+ // Page number
+#if WITH_GTKMM_3_0
+ Glib::RefPtr<Gtk::Adjustment> _pageNumberSpin_adj = Gtk::Adjustment::create(1, 1, _vec.size(), 1, 10, 0);
+ _pageNumberSpin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(_pageNumberSpin_adj, 1, 1));
+#else
+ Gtk::Adjustment *_pageNumberSpin_adj = Gtk::manage(
+ new class Gtk::Adjustment(1, 1, _vec.size(), 1, 10, 0));
+ _pageNumberSpin = Gtk::manage(new class Inkscape::UI::Widget::SpinButton(*_pageNumberSpin_adj, 1, 1));
+#endif
+ _labelTotalPages = Gtk::manage(new class Gtk::Label());
+ gchar *label_text = g_strdup_printf(_("out of %i"), num_pages);
+ _labelTotalPages->set_label(label_text);
+ g_free(label_text);
+
+ vbox1 = Gtk::manage(new class Gtk::VBox(false, 4));
+ SPDocument *doc = SPDocument::createNewDocFromMem(_vec[0].cstr(), strlen(_vec[0].cstr()), 0);
+ _previewArea = Glib::wrap(sp_svg_view_widget_new(doc));
+
+ vbox2 = Gtk::manage(new class Gtk::VBox(false, 4));
+ cancelbutton->set_can_focus();
+ cancelbutton->set_can_default();
+ cancelbutton->set_relief(Gtk::RELIEF_NORMAL);
+ okbutton->set_can_focus();
+ okbutton->set_can_default();
+ okbutton->set_relief(Gtk::RELIEF_NORMAL);
+ this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END);
+ _labelSelect->set_line_wrap(false);
+ _labelSelect->set_use_markup(false);
+ _labelSelect->set_selectable(false);
+ _pageNumberSpin->set_can_focus();
+ _pageNumberSpin->set_update_policy(Gtk::UPDATE_ALWAYS);
+ _pageNumberSpin->set_numeric(true);
+ _pageNumberSpin->set_digits(0);
+ _pageNumberSpin->set_wrap(false);
+ _labelTotalPages->set_line_wrap(false);
+ _labelTotalPages->set_use_markup(false);
+ _labelTotalPages->set_selectable(false);
+ vbox2->pack_start(*_previewArea, Gtk::PACK_SHRINK, 0);
+ this->get_vbox()->set_homogeneous(false);
+ this->get_vbox()->set_spacing(0);
+ this->get_vbox()->pack_start(*vbox2);
+ this->set_title(_("Page Selector"));
+ this->set_modal(true);
+ sp_transientize(GTK_WIDGET(this->gobj())); //Make transient
+ this->property_window_position().set_value(Gtk::WIN_POS_NONE);
+ this->set_resizable(true);
+ this->property_destroy_with_parent().set_value(false);
+ this->get_action_area()->add(*_labelSelect);
+ this->add_action_widget(*_pageNumberSpin, -7);
+ this->get_action_area()->add(*_labelTotalPages);
+ this->add_action_widget(*cancelbutton, -6);
+ this->add_action_widget(*okbutton, -5);
+ cancelbutton->show();
+ okbutton->show();
+ _labelSelect->show();
+ _pageNumberSpin->show();
+ _labelTotalPages->show();
+ vbox1->show();
+ _previewArea->show();
+ vbox2->show();
+
+ // Connect signals
+ _pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &VsdImportDialog::_onPageNumberChanged));
+}
+
+VsdImportDialog::~VsdImportDialog() {}
+
+bool VsdImportDialog::showDialog()
+{
+ show();
+ gint b = run();
+ hide();
+ if ( b == Gtk::RESPONSE_OK ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+unsigned VsdImportDialog::getSelectedPage()
+{
+ return _current_page;
+}
+
+void VsdImportDialog::_onPageNumberChanged()
+{
+ unsigned page = static_cast<unsigned>(_pageNumberSpin->get_value_as_int());
+ _current_page = CLAMP(page, 1U, _vec.size());
+ _setPreviewPage(_current_page);
+}
+
+/**
+ * \brief Renders the given page's thumbnail
+ */
+void VsdImportDialog::_setPreviewPage(unsigned page)
+{
+ SPDocument *doc = SPDocument::createNewDocFromMem(_vec[page-1].cstr(), strlen(_vec[page-1].cstr()), 0);
+ Gtk::Widget * tmpPreviewArea = Glib::wrap(sp_svg_view_widget_new(doc));
+ std::swap(_previewArea, tmpPreviewArea);
+ if (tmpPreviewArea) {
+ _previewArea->set_size_request( tmpPreviewArea->get_width(), tmpPreviewArea->get_height() );
+ delete tmpPreviewArea;
+ }
+ vbox2->pack_start(*_previewArea, Gtk::PACK_SHRINK, 0);
+ _previewArea->show_now();
+}
+
+SPDocument *VsdInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri)
+{
+ WPXFileStream input(uri);
+
+ if (!libvisio::VisioDocument::isSupported(&input)) {
+ return NULL;
+ }
+
+ libvisio::VSDStringVector output;
+ if (!libvisio::VisioDocument::generateSVG(&input, output)) {
+ return NULL;
+ }
+
+ if (output.empty()) {
+ return NULL;
+ }
+
+ std::vector<WPXString> tmpSVGOutput;
+ for (unsigned i=0; i<output.size(); ++i) {
+ WPXString tmpString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+ tmpString.append(output[i]);
+ tmpSVGOutput.push_back(tmpString);
+ }
+
+ unsigned page_num = 1;
+
+ // If only one page is present, import that one without bothering user
+ if (tmpSVGOutput.size() > 1) {
+ VsdImportDialog *dlg = 0;
+ if (inkscape_use_gui()) {
+ dlg = new VsdImportDialog(tmpSVGOutput);
+ if (!dlg->showDialog()) {
+ delete dlg;
+ return NULL;
+ }
+ }
+
+ // Get needed page
+ if (dlg) {
+ page_num = dlg->getSelectedPage();
+ if (page_num < 1)
+ page_num = 1;
+ if (page_num > tmpSVGOutput.size())
+ page_num = tmpSVGOutput.size();
+ }
+ }
+
+ SPDocument * doc = SPDocument::createNewDocFromMem(tmpSVGOutput[page_num-1].cstr(), strlen(tmpSVGOutput[page_num-1].cstr()), TRUE);
+
+ // Set viewBox if it doesn't exist
+ if (!doc->getRoot()->viewBox_set) {
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit())));
+ }
+
+ return doc;
+}
+
+#include "clear-n_.h"
+
+void VsdInput::init(void)
+{
+ /* VSD */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("VSD Input") "</name>\n"
+ "<id>org.inkscape.input.vsd</id>\n"
+ "<input>\n"
+ "<extension>.vsd</extension>\n"
+ "<mimetype>application/vnd.visio</mimetype>\n"
+ "<filetypename>" N_("Microsoft Visio Diagram (*.vsd)") "</filetypename>\n"
+ "<filetypetooltip>" N_("File format used by Microsoft Visio 6 and later") "</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>", new VsdInput());
+
+ /* VDX */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("VDX Input") "</name>\n"
+ "<id>org.inkscape.input.vdx</id>\n"
+ "<input>\n"
+ "<extension>.vdx</extension>\n"
+ "<mimetype>application/vnd.visio</mimetype>\n"
+ "<filetypename>" N_("Microsoft Visio XML Diagram (*.vdx)") "</filetypename>\n"
+ "<filetypetooltip>" N_("File format used by Microsoft Visio 2010 and later") "</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>", new VsdInput());
+
+ /* VSDM */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("VSDM Input") "</name>\n"
+ "<id>org.inkscape.input.vsdm</id>\n"
+ "<input>\n"
+ "<extension>.vsdm</extension>\n"
+ "<mimetype>application/vnd.visio</mimetype>\n"
+ "<filetypename>" N_("Microsoft Visio 2013 drawing (*.vsdm)") "</filetypename>\n"
+ "<filetypetooltip>" N_("File format used by Microsoft Visio 2013 and later") "</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>", new VsdInput());
+
+ /* VSDX */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("VSDX Input") "</name>\n"
+ "<id>org.inkscape.input.vsdx</id>\n"
+ "<input>\n"
+ "<extension>.vsdx</extension>\n"
+ "<mimetype>application/vnd.visio</mimetype>\n"
+ "<filetypename>" N_("Microsoft Visio 2013 drawing (*.vsdx)") "</filetypename>\n"
+ "<filetypetooltip>" N_("File format used by Microsoft Visio 2013 and later") "</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>", new VsdInput());
+
+ return;
+
+} // init
+
+} } } /* namespace Inkscape, Extension, Implementation */
+#endif /* WITH_LIBVISIO */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/vsd-input.h b/src/extension/internal/vsd-input.h
new file mode 100644
index 000000000..3414e0ec9
--- /dev/null
+++ b/src/extension/internal/vsd-input.h
@@ -0,0 +1,58 @@
+/*
+ * This code abstracts the libwpg interfaces into the Inkscape
+ * input extension interface.
+ *
+ * Authors:
+ * Fridrich Strba (fridrich.strba@bluewin.ch)
+ *
+ * Copyright (C) 2012 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef __EXTENSION_INTERNAL_VSDOUTPUT_H__
+#define __EXTENSION_INTERNAL_VSDOUTPUT_H__
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef WITH_LIBVISIO
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
+#include <gtkmm/dialog.h>
+
+#include "../implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class VsdInput : public Inkscape::Extension::Implementation::Implementation {
+ VsdInput () { };
+public:
+ SPDocument *open( Inkscape::Extension::Input *mod,
+ const gchar *uri );
+ static void init( void );
+
+};
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+#endif /* WITH_LIBVISIO */
+#endif /* __EXTENSION_INTERNAL_VSDOUTPUT_H__ */
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp
new file mode 100644
index 000000000..ef95dbe45
--- /dev/null
+++ b/src/extension/internal/wmf-inout.cpp
@@ -0,0 +1,3135 @@
+/** @file
+ * @brief Windows-only Enhanced Metafile input and output.
+ */
+/* Authors:
+ * Ulf Erikson <ulferikson@users.sf.net>
+ * Jon A. Cruz <jon@joncruz.org>
+ * David Mathog
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2006-2008 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ *
+ * References:
+ * - How to Create & Play Enhanced Metafiles in Win32
+ * http://support.microsoft.com/kb/q145999/
+ * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
+ * http://support.microsoft.com/kb/q66949/
+ * - Metafile Functions
+ * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
+ * - Metafile Structures
+ * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+//#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <libuemf/symbol_convert.h>
+
+#include "sp-root.h"
+#include "sp-path.h"
+#include "style.h"
+#include "print.h"
+#include "extension/system.h"
+#include "extension/print.h"
+#include "extension/db.h"
+#include "extension/input.h"
+#include "extension/output.h"
+#include "display/drawing.h"
+#include "display/drawing-item.h"
+#include "util/units.h"
+#include "clear-n_.h"
+#include "document.h"
+#include "shape-editor.h"
+#include "sp-namedview.h"
+#include "document-undo.h"
+#include "inkscape.h"
+
+
+#include "wmf-inout.h"
+#include "wmf-print.h"
+
+#define PRINT_WMF "org.inkscape.print.wmf"
+
+#ifndef U_PS_JOIN_MASK
+#define U_PS_JOIN_MASK (U_PS_JOIN_BEVEL|U_PS_JOIN_MITER|U_PS_JOIN_ROUND)
+#endif
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+
+static U_RECT16 rc_old;
+static bool clipset = false;
+static uint32_t BLTmode=0;
+
+Wmf::Wmf (void) // The null constructor
+{
+ return;
+}
+
+
+Wmf::~Wmf (void) //The destructor
+{
+ return;
+}
+
+
+bool
+Wmf::check (Inkscape::Extension::Extension * /*module*/)
+{
+ if (NULL == Inkscape::Extension::db.get(PRINT_WMF))
+ return FALSE;
+ return TRUE;
+}
+
+
+void
+Wmf::print_document_to_file(SPDocument *doc, const gchar *filename)
+{
+ Inkscape::Extension::Print *mod;
+ SPPrintContext context;
+ const gchar *oldconst;
+ gchar *oldoutput;
+ unsigned int ret;
+
+ doc->ensureUpToDate();
+
+ mod = Inkscape::Extension::get_print(PRINT_WMF);
+ oldconst = mod->get_param_string("destination");
+ oldoutput = g_strdup(oldconst);
+ mod->set_param_string("destination", filename);
+
+/* Start */
+ context.module = mod;
+ /* fixme: This has to go into module constructor somehow */
+ /* Create new arena */
+ mod->base = doc->getRoot();
+ Inkscape::Drawing drawing;
+ mod->dkey = SPItem::display_key_new(1);
+ mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY);
+ drawing.setRoot(mod->root);
+ /* Print document */
+ ret = mod->begin(doc);
+ if (ret) {
+ g_free(oldoutput);
+ throw Inkscape::Extension::Output::save_failed();
+ }
+ mod->base->invoke_print(&context);
+ ret = mod->finish();
+ /* Release arena */
+ mod->base->invoke_hide(mod->dkey);
+ mod->base = NULL;
+ mod->root = NULL; // deleted by invoke_hide
+/* end */
+
+ mod->set_param_string("destination", oldoutput);
+ g_free(oldoutput);
+
+ return;
+}
+
+
+void
+Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
+{
+ Inkscape::Extension::Extension * ext;
+
+ ext = Inkscape::Extension::db.get(PRINT_WMF);
+ if (ext == NULL)
+ return;
+
+ bool new_val = mod->get_param_bool("textToPath");
+ bool new_FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); // character position bug
+ // reserve FixPPT2 for opacity bug. Currently WMF does not export opacity values
+ bool new_FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); // dashed line bug
+ bool new_FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); // gradient bug
+ bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard WMF hatch
+
+ TableGen( //possibly regenerate the unicode-convert tables
+ mod->get_param_bool("TnrToSymbol"),
+ mod->get_param_bool("TnrToWingdings"),
+ mod->get_param_bool("TnrToZapfDingbats"),
+ mod->get_param_bool("UsePUA")
+ );
+
+ ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintWmf::init or a mysterious failure will result!
+ ext->set_param_bool("FixPPTDashLine",new_FixPPTDashLine);
+ ext->set_param_bool("FixPPTGrad2Polys",new_FixPPTGrad2Polys);
+ ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch);
+ ext->set_param_bool("textToPath", new_val);
+
+ print_document_to_file(doc, filename);
+
+ return;
+}
+
+
+/* WMF has no worldTransform, so this always returns 1.0. Retain it to keep WMF and WMF in sync as much as possible.*/
+double Wmf::current_scale(PWMF_CALLBACK_DATA /*d*/){
+ return 1.0;
+}
+
+/* WMF has no worldTransform, so this always returns an Identity rotation matrix, but the offsets may have values.*/
+std::string Wmf::current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset){
+ std::stringstream cxform;
+ double scale = current_scale(d);
+ cxform << "\"matrix(";
+ cxform << 1.0/scale; cxform << ",";
+ cxform << 0.0; cxform << ",";
+ cxform << 0.0; cxform << ",";
+ cxform << 1.0/scale; cxform << ",";
+ if(useoffset){ cxform << x; cxform << ","; cxform << y; }
+ else { cxform << "0,0"; }
+ cxform << ")\"";
+ return(cxform.str());
+}
+
+/* WMF has no worldTransform, so this always returns 0. Retain it to keep WMF and WMF in sync as much as possible.*/
+double Wmf::current_rotation(PWMF_CALLBACK_DATA /*d*/){
+ return 0.0;
+}
+
+/* Add another 100 blank slots to the hatches array.
+*/
+void Wmf::enlarge_hatches(PWMF_CALLBACK_DATA d){
+ d->hatches.size += 100;
+ d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *));
+}
+
+/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
+*/
+int Wmf::in_hatches(PWMF_CALLBACK_DATA d, char *test){
+ int i;
+ for(i=0; i<d->hatches.count; i++){
+ if(strcmp(test,d->hatches.strings[i])==0)return(i+1);
+ }
+ return(0);
+}
+
+/* (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one
+ does not exist it is added to the hatches list and also entered into <defs>.
+ This is also used to add the path part of the hatches, which they reference with a xlink:href
+*/
+uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){
+ char hatchname[64]; // big enough
+ char hpathname[64]; // big enough
+ char hbkname[64]; // big enough
+ char tmpcolor[8];
+ char bkcolor[8];
+ uint32_t idx;
+
+ switch(hatchType){
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor));
+ break;
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
+ break;
+ default:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor));
+ break;
+ }
+
+ /* For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch.
+ This will be used late to compose, or recompose the transparent or opaque final hatch.*/
+
+ std::string refpath; // used to reference later the path pieces which are about to be created
+ sprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor);
+ idx = in_hatches(d,hpathname);
+ if(!idx){ // add path/color if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hpathname);
+
+ *(d->defs) += "\n";
+ switch(hatchType){
+ case U_HS_HORIZONTAL:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_VERTICAL:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_FDIAGONAL:
+ *(d->defs) += " <line id=\"sub";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_BDIAGONAL:
+ *(d->defs) += " <line id=\"sub";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_CROSS:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_DIAGCROSS:
+ *(d->defs) += " <line id=\"subfd";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ *(d->defs) += " <line id=\"subbd";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_SOLIDCLR:
+ case U_HS_DITHEREDCLR:
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ default:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += ";stroke:none";
+ *(d->defs) += "\" />\n";
+ break;
+ }
+ }
+
+ // References to paths possibly just created above. These will be used in the actual patterns.
+ switch(hatchType){
+ case U_HS_HORIZONTAL:
+ case U_HS_VERTICAL:
+ case U_HS_CROSS:
+ case U_HS_SOLIDCLR:
+ case U_HS_DITHEREDCLR:
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ default:
+ refpath += " <use xlink:href=\"#";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ break;
+ case U_HS_FDIAGONAL:
+ case U_HS_BDIAGONAL:
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\" />\n";
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\" />\n";
+ break;
+ case U_HS_DIAGCROSS:
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\"/>\n";
+ break;
+ }
+
+ if(d->dc[d->level].bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR){
+ sprintf(hatchname,"WMFhatch%d_%s",hatchType,tmpcolor);
+ sprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor);
+ idx = in_hatches(d,hatchname);
+ if(!idx){ // add it if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hatchname);
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += hatchname;
+ *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n";
+ *(d->defs) += refpath;
+ *(d->defs) += " </pattern>\n";
+ idx = d->hatches.count;
+ }
+ }
+ else { // bkMode==U_OPAQUE
+ /* Set up an object in the defs for this background, if there is not one already there */
+ sprintf(bkcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
+ sprintf(hbkname,"WMFhbkclr_%s",bkcolor);
+ idx = in_hatches(d,hbkname);
+ if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name.
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hbkname);
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <rect id=\"";
+ *(d->defs) += hbkname;
+ *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
+ *(d->defs) += bkcolor;
+ *(d->defs) += "\" />\n";
+ }
+
+ // this is the pattern, its name will show up in Inkscape's pattern selector
+ sprintf(hatchname,"WMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor);
+ idx = in_hatches(d,hatchname);
+ if(!idx){ // add it if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hatchname);
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += hatchname;
+ *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n";
+ *(d->defs) += " <use xlink:href=\"#";
+ *(d->defs) += hbkname;
+ *(d->defs) += "\" />\n";
+ *(d->defs) += refpath;
+ *(d->defs) += " </pattern>\n";
+ idx = d->hatches.count;
+ }
+ }
+ return(idx-1);
+}
+
+/* Add another 100 blank slots to the images array.
+*/
+void Wmf::enlarge_images(PWMF_CALLBACK_DATA d){
+ d->images.size += 100;
+ d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *));
+}
+
+/* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1)
+*/
+int Wmf::in_images(PWMF_CALLBACK_DATA d, char *test){
+ int i;
+ for(i=0; i<d->images.count; i++){
+ if(strcmp(test,d->images.strings[i])==0)return(i+1);
+ }
+ return(0);
+}
+
+/* (Conditionally) add an image from a DIB. If a matching image already exists nothing happens. If one
+ does not exist it is added to the images list and also entered into <defs>.
+
+*/
+uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsage){
+
+ uint32_t idx;
+ char imagename[64]; // big enough
+ char xywh[64]; // big enough
+ int dibparams = U_BI_UNKNOWN; // type of image not yet determined
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // DIB color table
+ int32_t width, height, colortype, numCt, invert; // if needed these values will be set by wget_DIB_params
+ if(iUsage == U_DIB_RGB_COLORS){
+ // next call returns pointers and values, but allocates no memory
+ dibparams = wget_DIB_params(dib, &px, &ct, &numCt, &width, &height, &colortype, &invert);
+ if(dibparams == U_BI_RGB){
+ if(!DIB_to_RGBA(
+ px, // DIB pixel array
+ ct, // DIB color table
+ numCt, // DIB color table number of entries
+ &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ width, // Width of pixel array in record
+ height, // Height of pixel array in record
+ colortype, // DIB BitCount Enumeration
+ numCt, // Color table used if not 0
+ invert // If DIB rows are in opposite order from RGBA rows
+ )){
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ width, height, // of the SRC bitmap
+ rgba_px
+ );
+ free(rgba_px);
+ }
+ }
+ }
+
+ gchar *base64String=NULL;
+ if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ // image was binary png or jpg in source file
+ base64String = g_base64_encode((guchar*) px, numCt );
+ }
+ else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine
+ base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ }
+ else { // failed conversion, insert the common bad image picture
+ width = 3;
+ height = 4;
+ base64String = bad_image_png();
+ }
+ idx = in_images(d, (char *) base64String);
+ if(!idx){ // add it if not already present - we looked at the actual data for comparison
+ if(d->images.count == d->images.size){ enlarge_images(d); }
+ idx = d->images.count;
+ d->images.strings[d->images.count++]=strdup(base64String);
+
+ sprintf(imagename,"WMFimage%d",idx++);
+ sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <image id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n";
+ if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; }
+ else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; }
+ *(d->defs) += base64String;
+ *(d->defs) += "\"\n";
+ *(d->defs) += " preserveAspectRatio=\"none\"\n";
+ *(d->defs) += " />\n";
+
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ref\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
+ *(d->defs) += " >\n";
+ *(d->defs) += " <use id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ign\" ";
+ *(d->defs) += " xlink:href=\"#";
+ *(d->defs) += imagename;
+ *(d->defs) += "\" />\n";
+ *(d->defs) += " ";
+ *(d->defs) += " </pattern>\n";
+ }
+ g_free(base64String); //wait until this point to free because it might be a duplicate image
+ return(idx-1);
+}
+
+/* (Conditionally) add an image from a Bitmap16. If a matching image already exists nothing happens. If one
+ does not exist it is added to the images list and also entered into <defs>.
+
+*/
+uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px){
+
+ uint32_t idx;
+ char imagename[64]; // big enough
+ char xywh[64]; // big enough
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ const U_RGBQUAD *ct = NULL; // color table, always NULL here
+ int32_t width, height, colortype, numCt, invert;
+ numCt = 0;
+ width = Bm16.Width; // bitmap width in pixels.
+ height = Bm16.Height; // bitmap height in scan lines.
+ colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration
+ invert = 0;
+ if(colortype < 16)return(U_WMR_INVALID); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead.
+
+ if(!DIB_to_RGBA(// This is not really a dib, but close enough so that it still works.
+ px, // DIB pixel array
+ ct, // DIB color table (always NULL here)
+ numCt, // DIB color table number of entries (always 0)
+ &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ width, // Width of pixel array
+ height, // Height of pixel array
+ colortype, // DIB BitCount Enumeration
+ numCt, // Color table used if not 0
+ invert // If DIB rows are in opposite order from RGBA rows
+ )){
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ width, height, // of the SRC bitmap
+ rgba_px
+ );
+ free(rgba_px);
+ }
+
+ gchar *base64String=NULL;
+ if(mempng.buffer){ // image was Bm16 in source file, converted to png in this routine
+ base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ }
+ else { // failed conversion, insert the common bad image picture
+ width = 3;
+ height = 4;
+ base64String = bad_image_png();
+ }
+
+ idx = in_images(d, (char *) base64String);
+ if(!idx){ // add it if not already present - we looked at the actual data for comparison
+ if(d->images.count == d->images.size){ enlarge_images(d); }
+ idx = d->images.count;
+ d->images.strings[d->images.count++]=g_strdup(base64String);
+
+ sprintf(imagename,"WMFimage%d",idx++);
+ sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <image id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n";
+ *(d->defs) += " xlink:href=\"data:image/png;base64,";
+ *(d->defs) += base64String;
+ *(d->defs) += "\"\n";
+ *(d->defs) += " preserveAspectRatio=\"none\"\n";
+ *(d->defs) += " />\n";
+
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ref\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
+ *(d->defs) += " >\n";
+ *(d->defs) += " <use id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ign\" ";
+ *(d->defs) += " xlink:href=\"#";
+ *(d->defs) += imagename;
+ *(d->defs) += "\" />\n";
+ *(d->defs) += " </pattern>\n";
+ }
+ g_free(base64String); //wait until this point to free because it might be a duplicate image
+ return(idx-1);
+}
+
+void
+Wmf::output_style(PWMF_CALLBACK_DATA d)
+{
+// SVGOStringStream tmp_id;
+ SVGOStringStream tmp_style;
+ char tmp[1024] = {0};
+
+ float fill_rgb[3];
+ sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb );
+ float stroke_rgb[3];
+ sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb);
+
+ // for U_WMR_BITBLT with no image, try to approximate some of these operations/
+ // Assume src color is "white"
+ if(d->dwRop3){
+ switch(d->dwRop3){
+ case U_PATINVERT: // treat all of these as black
+ case U_SRCINVERT:
+ case U_DSTINVERT:
+ case U_BLACKNESS:
+ case U_SRCERASE:
+ case U_NOTSRCCOPY:
+ fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0;
+ break;
+ case U_SRCCOPY: // treat all of these as white
+ case U_NOTSRCERASE:
+ case U_PATCOPY:
+ case U_WHITENESS:
+ fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0;
+ break;
+ case U_SRCPAINT: // use the existing color
+ case U_SRCAND:
+ case U_MERGECOPY:
+ case U_MERGEPAINT:
+ case U_PATPAINT:
+ default:
+ break;
+ }
+ d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT
+ }
+
+ // Implement some of these, the ones where the original screen color does not matter.
+ // The options that merge screen and pen colors cannot be done correctly because we
+ // have no way of knowing what color is already on the screen. For those just pass the
+ // pen color through.
+ switch(d->dwRop2){
+ case U_R2_BLACK:
+ fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0;
+ stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0;
+ break;
+ case U_R2_NOTMERGEPEN:
+ case U_R2_MASKNOTPEN:
+ break;
+ case U_R2_NOTCOPYPEN:
+ fill_rgb[0] = 1.0 - fill_rgb[0];
+ fill_rgb[1] = 1.0 - fill_rgb[1];
+ fill_rgb[2] = 1.0 - fill_rgb[2];
+ stroke_rgb[0] = 1.0 - stroke_rgb[0];
+ stroke_rgb[1] = 1.0 - stroke_rgb[1];
+ stroke_rgb[2] = 1.0 - stroke_rgb[2];
+ break;
+ case U_R2_MASKPENNOT:
+ case U_R2_NOT:
+ case U_R2_XORPEN:
+ case U_R2_NOTMASKPEN:
+ case U_R2_NOTXORPEN:
+ case U_R2_NOP:
+ case U_R2_MERGENOTPEN:
+ case U_R2_COPYPEN:
+ case U_R2_MASKPEN:
+ case U_R2_MERGEPENNOT:
+ case U_R2_MERGEPEN:
+ break;
+ case U_R2_WHITE:
+ fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0;
+ stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0;
+ break;
+ default:
+ break;
+ }
+
+
+// tmp_id << "\n\tid=\"" << (d->id++) << "\"";
+// *(d->outsvg) += tmp_id.str().c_str();
+ *(d->outsvg) += "\n\tstyle=\"";
+ if (!d->dc[d->level].fill_set || ( d->mask & U_DRAW_NOFILL)) { // nofill are lines and arcs
+ tmp_style << "fill:none;";
+ } else {
+ switch(d->dc[d->level].fill_mode){
+ // both of these use the url(#) method
+ case DRAW_PATTERN:
+ snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]);
+ tmp_style << tmp;
+ break;
+ case DRAW_IMAGE:
+ snprintf(tmp, 1023, "fill:url(#WMFimage%d_ref); ",d->dc[d->level].fill_idx);
+ tmp_style << tmp;
+ break;
+ case DRAW_PAINT:
+ default: // <-- this should never happen, but just in case...
+ snprintf(
+ tmp, 1023,
+ "fill:#%02x%02x%02x;",
+ SP_COLOR_F_TO_U(fill_rgb[0]),
+ SP_COLOR_F_TO_U(fill_rgb[1]),
+ SP_COLOR_F_TO_U(fill_rgb[2])
+ );
+ tmp_style << tmp;
+ break;
+ }
+ snprintf(
+ tmp, 1023,
+ "fill-rule:%s;",
+ (d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero")
+ );
+ tmp_style << tmp;
+ tmp_style << "fill-opacity:1;";
+
+ // if the stroke is the same as the fill, and the right size not to change the end size of the object, do not do it separately
+ if(
+ (d->dc[d->level].fill_set ) &&
+ (d->dc[d->level].stroke_set ) &&
+ (d->dc[d->level].style.stroke_width.value == 1 ) &&
+ (d->dc[d->level].fill_mode == d->dc[d->level].stroke_mode) &&
+ (
+ (d->dc[d->level].fill_mode != DRAW_PAINT) ||
+ (
+ (fill_rgb[0]==stroke_rgb[0]) &&
+ (fill_rgb[1]==stroke_rgb[1]) &&
+ (fill_rgb[2]==stroke_rgb[2])
+ )
+ )
+ ){
+ d->dc[d->level].stroke_set = false;
+ }
+ }
+
+ if (!d->dc[d->level].stroke_set) {
+ tmp_style << "stroke:none;";
+ } else {
+ switch(d->dc[d->level].stroke_mode){
+ // both of these use the url(#) method
+ case DRAW_PATTERN:
+ snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]);
+ tmp_style << tmp;
+ break;
+ case DRAW_IMAGE:
+ snprintf(tmp, 1023, "stroke:url(#WMFimage%d_ref); ",d->dc[d->level].stroke_idx);
+ tmp_style << tmp;
+ break;
+ case DRAW_PAINT:
+ default: // <-- this should never happen, but just in case...
+ snprintf(
+ tmp, 1023,
+ "stroke:#%02x%02x%02x;",
+ SP_COLOR_F_TO_U(stroke_rgb[0]),
+ SP_COLOR_F_TO_U(stroke_rgb[1]),
+ SP_COLOR_F_TO_U(stroke_rgb[2])
+ );
+ tmp_style << tmp;
+ break;
+ }
+ if(d->dc[d->level].style.stroke_width.value){
+ tmp_style << "stroke-width:" <<
+ MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
+ }
+ else { // In a WMF a 0 width pixel means "1 pixel"
+ tmp_style << "stroke-width:" << pix_to_abs_size( d, 1 ) << "px;";
+ }
+
+ tmp_style << "stroke-linecap:" <<
+ (
+ d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" :
+ d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" :
+ d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" :
+ "unknown"
+ ) << ";";
+
+ tmp_style << "stroke-linejoin:" <<
+ (
+ d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" :
+ d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" :
+ d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" :
+ "unknown"
+ ) << ";";
+
+ // Set miter limit if known, even if it is not needed immediately (not miter)
+ tmp_style << "stroke-miterlimit:" <<
+ MAX( 2.0, d->dc[d->level].style.stroke_miterlimit.value ) << ";";
+
+ if (d->dc[d->level].style.stroke_dasharray.set &&
+ !d->dc[d->level].style.stroke_dasharray.values.empty())
+ {
+ tmp_style << "stroke-dasharray:";
+ for (unsigned i=0; i<d->dc[d->level].style.stroke_dasharray.values.size(); i++) {
+ if (i)
+ tmp_style << ",";
+ tmp_style << d->dc[d->level].style.stroke_dasharray.values[i];
+ }
+ tmp_style << ";";
+ tmp_style << "stroke-dashoffset:0;";
+ } else {
+ tmp_style << "stroke-dasharray:none;";
+ }
+ tmp_style << "stroke-opacity:1;";
+ }
+ tmp_style << "\" ";
+ if (clipset)
+ tmp_style << "\n\tclip-path=\"url(#clipWmfPath" << d->id << ")\" ";
+ clipset = false;
+
+ *(d->outsvg) += tmp_style.str().c_str();
+}
+
+
+double
+Wmf::_pix_x_to_point(PWMF_CALLBACK_DATA d, double px)
+{
+ double scale = (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0);
+ double tmp;
+ tmp = ((((double) (px - d->dc[d->level].winorg.x))*scale) + d->dc[d->level].vieworg.x) * d->D2PscaleX;
+ tmp -= d->ulCornerOutX; //The WMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
+ return(tmp);
+}
+
+double
+Wmf::_pix_y_to_point(PWMF_CALLBACK_DATA d, double py)
+{
+ double scale = (d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0);
+ double tmp;
+ tmp = ((((double) (py - d->dc[d->level].winorg.y))*scale) * d->E2IdirY + d->dc[d->level].vieworg.y) * d->D2PscaleY;
+ tmp -= d->ulCornerOutY; //The WMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
+ return(tmp);
+}
+
+
+double
+Wmf::pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double /*py*/)
+{
+ double x = _pix_x_to_point(d, px);
+ return x;
+}
+
+double
+Wmf::pix_to_y_point(PWMF_CALLBACK_DATA d, double /*px*/, double py)
+{
+ double y = _pix_y_to_point(d, py);
+ return y;
+
+}
+
+double
+Wmf::pix_to_abs_size(PWMF_CALLBACK_DATA d, double px)
+{
+ double ppx = fabs(px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0) * d->D2PscaleX * current_scale(d));
+ return ppx;
+}
+
+/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of WMF x,y coordinates
+*/
+std::string Wmf::pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y){
+ std::stringstream cxform;
+ cxform << pix_to_x_point(d,x,y);
+ cxform << ",";
+ cxform << pix_to_y_point(d,x,y);
+ return(cxform.str());
+}
+
+
+void
+Wmf::select_pen(PWMF_CALLBACK_DATA d, int index)
+{
+ int width;
+ char *record = NULL;
+ U_PEN up;
+
+ if (index < 0 && index >= d->n_obj){ return; }
+ record = d->wmf_obj[index].record;
+ if(!record){ return; }
+ d->dc[d->level].active_pen = index;
+
+ (void) U_WMRCREATEPENINDIRECT_get(record, &up);
+ width = up.Widthw[0]; // width is stored in the first 16 bits of the 32.
+
+ switch (up.Style & U_PS_STYLE_MASK) {
+ case U_PS_DASH:
+ case U_PS_DOT:
+ case U_PS_DASHDOT:
+ case U_PS_DASHDOTDOT:
+ {
+ int penstyle = (up.Style & U_PS_STYLE_MASK);
+ if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values)))
+ d->dc[d->level].style.stroke_dasharray.values.clear();
+ if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 3 );
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ }
+ if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ }
+ if (penstyle==U_PS_DASHDOTDOT) {
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ d->dc[d->level].style.stroke_dasharray.values.push_back( 1 );
+ }
+
+ d->dc[d->level].style.stroke_dasharray.set = 1;
+ break;
+ }
+
+ case U_PS_SOLID:
+ default:
+ {
+ d->dc[d->level].style.stroke_dasharray.set = 0;
+ break;
+ }
+ }
+
+ switch (up.Style & U_PS_ENDCAP_MASK) {
+ case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = 1; break; }
+ case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = 2; break; }
+ case U_PS_ENDCAP_FLAT:
+ default: { d->dc[d->level].style.stroke_linecap.computed = 0; break; }
+ }
+
+ switch (up.Style & U_PS_JOIN_MASK) {
+ case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = 2; break; }
+ case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = 0; break; }
+ case U_PS_JOIN_ROUND:
+ default: { d->dc[d->level].style.stroke_linejoin.computed = 1; break; }
+ }
+
+
+ double pen_width;
+ if (up.Style == U_PS_NULL) {
+ d->dc[d->level].stroke_set = false;
+ pen_width =0.0;
+ } else if (width) {
+ d->dc[d->level].stroke_set = true;
+ int cur_level = d->level;
+ d->level = d->wmf_obj[index].level; // this object may have been defined in some other DC.
+ pen_width = pix_to_abs_size( d, width );
+ d->level = cur_level;
+ } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
+ d->dc[d->level].stroke_set = true;
+ int cur_level = d->level;
+ d->level = d->wmf_obj[index].level; // this object may have been defined in some other DC.
+ pen_width = pix_to_abs_size( d, 1 );
+ d->level = cur_level;
+ }
+ d->dc[d->level].style.stroke_width.value = pen_width;
+
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(up.Color) );
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(up.Color) );
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(up.Color) );
+ d->dc[d->level].style.stroke.value.color.set( r, g, b );
+}
+
+
+void
+Wmf::select_brush(PWMF_CALLBACK_DATA d, int index)
+{
+ uint8_t iType;
+ char *record;
+ const char *membrush;
+
+ if (index < 0 || index >= d->n_obj)return;
+ record = d->wmf_obj[index].record;
+ if(!record)return;
+ d->dc[d->level].active_brush = index;
+
+ iType = *(uint8_t *)(record + offsetof(U_METARECORD, iType ) );
+ if(iType == U_WMR_CREATEBRUSHINDIRECT){
+ U_WLOGBRUSH lb;
+ (void) U_WMRCREATEBRUSHINDIRECT_get(record, &membrush);
+ memcpy(&lb, membrush, U_SIZE_WLOGBRUSH);
+ if(lb.Style == U_BS_SOLID){
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(lb.Color) );
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(lb.Color) );
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(lb.Color) );
+ d->dc[d->level].style.fill.value.color.set( r, g, b );
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ d->dc[d->level].fill_set = true;
+ }
+ else if(lb.Style == U_BS_HATCHED){
+ d->dc[d->level].fill_idx = add_hatch(d, lb.Hatch, lb.Color);
+ d->dc[d->level].fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
+ d->dc[d->level].fill_mode = DRAW_PATTERN;
+ d->dc[d->level].fill_set = true;
+ }
+ else if(lb.Style == U_BS_NULL){
+ d->dc[d->level].fill_mode = DRAW_PAINT; // set it to something
+ d->dc[d->level].fill_set = false;
+ }
+ }
+ else if(iType == U_WMR_DIBCREATEPATTERNBRUSH){
+ uint32_t tidx;
+ uint16_t Style;
+ uint16_t cUsage;
+ const char *Bm16h; // Pointer to Bitmap16 header (px follows)
+ const char *dib; // Pointer to DIB
+ (void) U_WMRDIBCREATEPATTERNBRUSH_get(record, &Style, &cUsage, &Bm16h, &dib);
+ if(dib || Bm16h){
+ if(dib){ tidx = add_dib_image(d, dib, cUsage); }
+ else if(Bm16h){
+ U_BITMAP16 Bm16;
+ const char *px;
+ memcpy(&Bm16, Bm16h, U_SIZE_BITMAP16);
+ px = Bm16h + U_SIZE_BITMAP16;
+ tidx = add_bm16_image(d, Bm16, px);
+ }
+ if(tidx == U_WMR_INVALID){ // Problem with the image, for instance, an unsupported bitmap16 type
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
+ d->dc[d->level].style.fill.value.color.set( r, g, b );
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ }
+ else {
+ d->dc[d->level].fill_idx = tidx;
+ d->dc[d->level].fill_mode = DRAW_IMAGE;
+ }
+ d->dc[d->level].fill_set = true;
+ }
+ else {
+ g_message("Please send WMF file to developers - select_brush U_WMR_DIBCREATEPATTERNBRUSH not bm16 or dib, not handled");
+ }
+ }
+ else if(iType == U_WMR_CREATEPATTERNBRUSH){
+ uint32_t tidx;
+ int cbPx;
+ U_BITMAP16 Bm16h;
+ const char *px;
+ if(U_WMRCREATEPATTERNBRUSH_get(record, &Bm16h, &cbPx, &px)){
+ tidx = add_bm16_image(d, Bm16h, px);
+ if(tidx == 0xFFFFFFFF){ // Problem with the image, for instance, an unsupported bitmap16 type
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
+ d->dc[d->level].style.fill.value.color.set( r, g, b );
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ }
+ else {
+ d->dc[d->level].fill_idx = tidx;
+ d->dc[d->level].fill_mode = DRAW_IMAGE;
+ }
+ d->dc[d->level].fill_set = true;
+ }
+ }
+}
+
+
+void
+Wmf::select_font(PWMF_CALLBACK_DATA d, int index)
+{
+ char *record = NULL;
+ const char *memfont;
+ const char *facename;
+ U_FONT font;
+
+ if (index < 0 || index >= d->n_obj)return;
+ record = d->wmf_obj[index].record;
+ if (!record)return;
+ d->dc[d->level].active_font = index;
+
+
+ (void) U_WMRCREATEFONTINDIRECT_get(record, &memfont);
+ memcpy(&font,memfont,U_SIZE_FONT_CORE); //make sure it is in a properly aligned structure before touching it
+ facename = memfont + U_SIZE_FONT_CORE;
+
+ /* The logfont information always starts with a U_LOGFONT structure but the U_WMRCREATEFONTINDIRECT
+ is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont
+ is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored
+ */
+ int cur_level = d->level;
+ d->level = d->wmf_obj[index].level;
+ double font_size = pix_to_abs_size( d, font.Height );
+ /* snap the font_size to the nearest 1/32nd of a point.
+ (The size is converted from Pixels to points, snapped, and converted back.)
+ See the notes where d->D2Pscale[XY] are set for the reason why.
+ Typically this will set the font to the desired exact size. If some peculiar size
+ was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */
+ font_size = round(20.0 * 0.8 * font_size)/(20.0 * 0.8);
+ d->level = cur_level;
+ d->dc[d->level].style.font_size.computed = font_size;
+ d->dc[d->level].style.font_weight.value =
+ font.Weight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 :
+ font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 :
+ font.Weight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 :
+ font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 :
+ font.Weight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 :
+ font.Weight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 :
+ font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 :
+ font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 :
+ font.Weight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 :
+ font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL :
+ font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD :
+ font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER :
+ font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER :
+ U_FW_NORMAL;
+ d->dc[d->level].style.font_style.value = (font.Italic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL);
+ d->dc[d->level].style.text_decoration_line.underline = font.Underline;
+ d->dc[d->level].style.text_decoration_line.line_through = font.StrikeOut;
+ d->dc[d->level].style.text_decoration_line.set = true;
+ d->dc[d->level].style.text_decoration_line.inherit = false;
+
+ // malformed WMF with empty filename may exist, ignore font change if encountered
+ if(d->dc[d->level].font_name)free(d->dc[d->level].font_name);
+ if(*facename){
+ d->dc[d->level].font_name = strdup(facename);
+ }
+ else { // Malformed WMF might specify an empty font name
+ d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
+ }
+ d->dc[d->level].style.baseline_shift.value = round((double)((font.Escapement + 3600) % 3600) / 10.0); // use baseline_shift instead of text_transform to avoid overflow
+}
+
+/* Find the first free hole where an object may be stored.
+ If there are not any return -1. This is a big error, possibly from a corrupt WMF file.
+*/
+int Wmf::insertable_object(PWMF_CALLBACK_DATA d)
+{
+ int index = d->low_water; // Start looking from here, it may already have been filled
+ while(index < d->n_obj && d->wmf_obj[index].record != NULL){ index++; }
+ if(index >= d->n_obj)return(-1); // this is a big problem, percolate it back up so the program can get out of this gracefully
+ d->low_water = index; // Could probably be index+1
+ return(index);
+}
+
+void
+Wmf::delete_object(PWMF_CALLBACK_DATA d, int index)
+{
+ if (index >= 0 && index < d->n_obj) {
+ // If the active object is deleted set default draw values
+ if(index == d->dc[d->level].active_pen){ // Use default pen: solid, black, 1 pixel wide
+ d->dc[d->level].active_pen = -1;
+ d->dc[d->level].style.stroke_dasharray.set = 0;
+ d->dc[d->level].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE
+ d->dc[d->level].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER;
+ d->dc[d->level].stroke_set = true;
+ d->dc[d->level].style.stroke_width.value = 1.0;
+ d->dc[d->level].style.stroke.value.color.set( 0, 0, 0 );
+ }
+ else if(index == d->dc[d->level].active_brush){
+ d->dc[d->level].active_brush = -1;
+ d->dc[d->level].fill_set = false;
+ }
+ else if(index == d->dc[d->level].active_font){
+ d->dc[d->level].active_font = -1;
+ if(d->dc[d->level].font_name){ free(d->dc[d->level].font_name);}
+ d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
+ d->dc[d->level].style.font_size.computed = 16.0;
+ d->dc[d->level].style.font_weight.value = SP_CSS_FONT_WEIGHT_400;
+ d->dc[d->level].style.font_style.value = SP_CSS_FONT_STYLE_NORMAL;
+ d->dc[d->level].style.text_decoration_line.underline = 0;
+ d->dc[d->level].style.text_decoration_line.line_through = 0;
+ d->dc[d->level].style.baseline_shift.value = 0;
+ }
+
+
+ d->wmf_obj[index].type = 0;
+// We are keeping a copy of the WMR rather than just a structure. Currently that is not necessary as the entire
+// WMF is read in at once and is stored in a big malloc. However, in past versions it was handled
+// reord by record, and we might need to do that again at some point in the future if we start running into WMF
+// files too big to fit into memory.
+ if (d->wmf_obj[index].record)
+ free(d->wmf_obj[index].record);
+ d->wmf_obj[index].record = NULL;
+ if(index < d->low_water)d->low_water = index;
+ }
+}
+
+
+// returns the new index, or -1 on error.
+int Wmf::insert_object(PWMF_CALLBACK_DATA d, int type, const char *record)
+{
+ int index = insertable_object(d);
+ if(index>=0){
+ d->wmf_obj[index].type = type;
+ d->wmf_obj[index].level = d->level;
+ d->wmf_obj[index].record = wmr_dup(record);
+ }
+ return(index);
+}
+
+
+/**
+ \fn create a UTF-32LE buffer and fill it with UNICODE unknown character
+ \param count number of copies of the Unicode unknown character to fill with
+*/
+uint32_t *Wmf::unknown_chars(size_t count){
+ uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1));
+ if(!res)throw "Inkscape fatal memory allocation error - cannot continue";
+ for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; }
+ res[count]=0;
+ return res;
+}
+
+/**
+ \brief store SVG for an image given the pixmap and various coordinate information
+ \param d
+ \param dib packed DIB in memory
+ \param dx (double) destination x in inkscape pixels
+ \param dy (double) destination y in inkscape pixels
+ \param dw (double) destination width in inkscape pixels
+ \param dh (double) destination height in inkscape pixels
+ \param sx (int) source x in src image pixels
+ \param sy (int) source y in src image pixels
+ \param iUsage
+*/
+void Wmf::common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib,
+ double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage){
+
+ SVGOStringStream tmp_image;
+ int dibparams = U_BI_UNKNOWN; // type of image not yet determined
+
+ tmp_image << "\n\t <image\n";
+ tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ char *sub_px = NULL; // RGBA pixels, subarray
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // color table
+ int32_t width, height, colortype, numCt, invert; // if needed these values will be set in wget_DIB_params
+ if(iUsage == U_DIB_RGB_COLORS){
+ // next call returns pointers and values, but allocates no memory
+ dibparams = wget_DIB_params(dib, &px, &ct, &numCt, &width, &height, &colortype, &invert);
+ if(dibparams == U_BI_RGB){
+ if(sw == 0 || sh == 0){
+ sw = width;
+ sh = height;
+ }
+ if(!DIB_to_RGBA(
+ px, // DIB pixel array
+ ct, // DIB color table
+ numCt, // DIB color table number of entries
+ &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ width, // Width of pixel array
+ height, // Height of pixel array
+ colortype, // DIB BitCount Enumeration
+ numCt, // Color table used if not 0
+ invert // If DIB rows are in opposite order from RGBA rows
+ )){
+ sub_px = RGBA_to_RGBA( // returns either a subset (side effect: frees rgba_px) or NULL (for subset == entire image)
+ rgba_px, // full pixel array from DIB
+ width, // Width of pixel array
+ height, // Height of pixel array
+ sx,sy, // starting point in pixel array
+ &sw,&sh // columns/rows to extract from the pixel array (output array size)
+ );
+
+ if(!sub_px)sub_px=rgba_px;
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ sw, sh, // size of the extracted pixel array
+ sub_px
+ );
+ free(sub_px);
+ }
+ }
+ }
+
+ gchar *base64String=NULL;
+ if(dibparams == U_BI_JPEG){ // image was binary jpg in source file
+ tmp_image << " xlink:href=\"data:image/jpeg;base64,";
+ base64String = g_base64_encode((guchar*) px, numCt );
+ }
+ else if(dibparams==U_BI_PNG){ // image was binary png in source file
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ base64String = g_base64_encode((guchar*) px, numCt );
+ }
+ else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ }
+ else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ base64String = bad_image_png();
+ }
+ tmp_image << base64String;
+ g_free(base64String);
+
+ tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
+ tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets.
+ tmp_image << " preserveAspectRatio=\"none\"\n";
+ tmp_image << "/> \n";
+
+ *(d->outsvg) += tmp_image.str().c_str();
+ *(d->path) = "";
+}
+
+/**
+ \brief store SVG for an image given the pixmap and various coordinate information
+ \param d
+ \param Bm16 core Bitmap16 header
+ \param px pointer to Bitmap16 image data
+ \param dx (double) destination x in inkscape pixels
+ \param dy (double) destination y in inkscape pixels
+ \param dw (double) destination width in inkscape pixels
+ \param dh (double) destination height in inkscape pixels
+ \param sx (int) source x in src image pixels
+ \param sy (int) source y in src image pixels
+ \param iUsage
+*/
+void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px,
+ double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh){
+
+ SVGOStringStream tmp_image;
+
+ tmp_image << "\n\t <image\n";
+ tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ char *sub_px = NULL; // RGBA pixels, subarray
+ const U_RGBQUAD *ct = NULL; // color table
+ int32_t width, height, colortype, numCt, invert;
+
+ numCt = 0;
+ width = Bm16.Width; // bitmap width in pixels.
+ height = Bm16.Height; // bitmap height in scan lines.
+ colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration
+ invert = 0;
+
+ if(sw == 0 || sh == 0){
+ sw = width;
+ sh = height;
+ }
+
+ if(colortype < 16)return; // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead.
+
+ if(!DIB_to_RGBA(// This is not really a dib, but close enough so that it still works.
+ px, // DIB pixel array
+ ct, // DIB color table (always NULL here)
+ numCt, // DIB color table number of entries (always 0)
+ &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ width, // Width of pixel array
+ height, // Height of pixel array
+ colortype, // DIB BitCount Enumeration
+ numCt, // Color table used if not 0
+ invert // If DIB rows are in opposite order from RGBA rows
+ )){
+ sub_px = RGBA_to_RGBA( // returns either a subset (side effect: frees rgba_px) or NULL (for subset == entire image)
+ rgba_px, // full pixel array from DIB
+ width, // Width of pixel array
+ height, // Height of pixel array
+ sx,sy, // starting point in pixel array
+ &sw,&sh // columns/rows to extract from the pixel array (output array size)
+ );
+
+ if(!sub_px)sub_px=rgba_px;
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ sw, sh, // size of the extracted pixel array
+ sub_px
+ );
+ free(sub_px);
+ }
+
+ gchar *base64String=NULL;
+ if(mempng.buffer){ // image was Bm16 in source file, converted to png in this routine
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ }
+ else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ base64String = bad_image_png();
+ }
+ tmp_image << base64String;
+ g_free(base64String);
+
+ tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
+ tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets.
+ tmp_image << " preserveAspectRatio=\"none\"\n";
+ tmp_image << "/> \n";
+
+ *(d->outsvg) += tmp_image.str().c_str();
+ *(d->path) = "";
+}
+
+/**
+ \fn myMetaFileProc(char *contents, unsigned int length, PWMF_CALLBACK_DATA lpData)
+ \returns 1 on success, 0 on error
+ \param contents binary contents of an WMF file
+ \param length length in bytes of contents
+ \param d Inkscape data structures returned by this call
+*/
+//THis was a callback, just build it into a normal function
+int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK_DATA d)
+{
+ uint32_t off=0;
+ uint32_t wmr_mask;
+ int OK =1;
+ TCHUNK_SPECS tsp;
+ uint8_t iType;
+ int nSize; // size of the current record, in bytes, or an error value if <=0
+ const char *blimit = contents + length; // 1 byte past the end of the last record
+
+ /* variables used to retrieve data from WMF records */
+ uint16_t utmp16;
+ U_POINT16 pt16; // any point
+ U_RECT16 rc; // any rectangle, usually a bounding rectangle
+ U_POINT16 Dst; // Destination coordinates
+ U_POINT16 cDst; // Destination w,h, if different from Src
+ U_POINT16 Src; // Source coordinates
+ U_POINT16 cSrc; // Source w,h, if different from Dst
+ U_POINT16 cwh; // w,h, if Src and Dst use the same values
+ uint16_t cUsage; // colorusage enumeration
+ uint32_t dwRop3; // raster operations, these are only barely supported here
+ const char *dib; // DIB style image structure
+ U_BITMAP16 Bm16; // Bitmap16 style image structure
+ const char *px; // Image for Bm16
+ uint16_t cPts; // number of points in the next variable
+ const char *points; // any list of U_POINT16, may not be aligned
+ int16_t tlen; // length of returned text, in bytes
+ const char *text; // returned text, Latin1 encoded
+ uint16_t Opts;
+ const int16_t *dx; // character spacing for one text mode, inkscape ignores this
+ double left, right, top, bottom; // values used, because a bounding rect can have values reversed L<->R, T<->B
+
+ uint16_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written
+ U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
+
+ /* initialize the tsp for text reassembly */
+ tsp.string = NULL;
+ tsp.ori = 0.0; /* degrees */
+ tsp.fs = 12.0; /* font size */
+ tsp.x = 0.0;
+ tsp.y = 0.0;
+ tsp.boff = 0.0; /* offset to baseline from LL corner of bounding rectangle, changes with fs and taln*/
+ tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */
+ tsp.taln = ALILEFT + ALIBASE;
+ tsp.ldir = LDIR_LR;
+ tsp.spaces = 0; // this field is only used for debugging
+ tsp.color.Red = 0; /* RGB Black */
+ tsp.color.Green = 0; /* RGB Black */
+ tsp.color.Blue = 0; /* RGB Black */
+ tsp.color.Reserved = 0; /* not used */
+ tsp.italics = 0;
+ tsp.weight = 80;
+ tsp.decoration = TXTDECOR_NONE;
+ tsp.condensed = 100;
+ tsp.co = 0;
+ tsp.fi_idx = -1; /* set to an invalid */
+ tsp.rt_tidx = -1; /* set to an invalid */
+
+ SVGOStringStream dbg_str;
+
+ /* There is very little information in WMF headers, get what is there. In many cases pretty much everything will have to
+ default. If there is no placeable header we know pretty much nothing about the size of the page, in which case
+ assume that it is 1440 WMF pixels/inch and make the page A4 landscape. That is almost certainly the wrong page size
+ but it has to be set to something, and nothing horrible happens if the drawing goes off the page. */
+ {
+
+ U_WMRPLACEABLE Placeable;
+ U_WMRHEADER Header;
+ off = 0;
+ nSize = wmfheader_get(contents, blimit, &Placeable, &Header);
+ if(!nSize)return(0);
+ if(!Header.nObjects){ Header.nObjects = 256; }// there _may_ be WMF files with no objects, more likely it is corrupt. Try to use it anyway.
+ d->n_obj = Header.nObjects;
+ d->wmf_obj = new WMF_OBJECT[d->n_obj];
+ d->low_water = 0; // completely empty at this point, so start searches at 0
+
+ // Init the new wmf_obj list elements to null, provided the
+ // dynamic allocation succeeded.
+ if ( d->wmf_obj != NULL )
+ {
+ for( int i=0; i < d->n_obj; ++i )
+ d->wmf_obj[i].record = NULL;
+ } //if
+
+ if(!Placeable.Inch){ Placeable.Inch= 1440; }
+ if(!Placeable.Dst.right && !Placeable.Dst.left){ // no page size has been supplied
+ // This is gross, scan forward looking for a SETWINDOWEXT record, use the first one found to
+ // define the page size
+ int hold_nSize = off = nSize;
+ Placeable.Dst.left = 0;
+ Placeable.Dst.top = 0;
+ while(OK){
+ nSize = U_WMRRECSAFE_get(contents + off, blimit);
+ if(nSize){
+ iType = *(uint8_t *)(contents + off + offsetof(U_METARECORD, iType ) );
+ if(iType == U_WMR_SETWINDOWEXT){
+ OK=0;
+ (void) U_WMRSETWINDOWEXT_get(contents + off, &Dst);
+ Placeable.Dst.right = Dst.x;
+ Placeable.Dst.bottom = Dst.y;
+ }
+ else if(iType == U_WMR_EOF){
+ OK=0;
+ // Really messed up WMF, have to set the page to something, make it A4 horizontal
+ Placeable.Dst.right = round(((double) Placeable.Inch) * 297.0/25.4);
+ Placeable.Dst.bottom = round(((double) Placeable.Inch) * 210.0/25.4);
+ }
+ else {
+ off += nSize;
+ }
+ }
+ }
+ off=0;
+ nSize = hold_nSize;
+ OK=1;
+ }
+
+ // drawing size in WMF pixels
+ d->PixelsInX = Placeable.Dst.right - Placeable.Dst.left + 1;
+ d->PixelsInY = Placeable.Dst.bottom - Placeable.Dst.top + 1;
+
+ /*
+ Set values for Window and ViewPort extents to 0 - not defined yet.
+ */
+ d->dc[d->level].sizeView.x = d->dc[d->level].sizeWnd.x = 0;
+ d->dc[d->level].sizeView.y = d->dc[d->level].sizeWnd.y = 0;
+
+ /* Upper left corner in device units, usually both 0, but not always.
+ If a placeable header is used, and later a windoworg/windowext are found, then
+ the placeable information will be ignored.
+ */
+ d->ulCornerInX = Placeable.Dst.left;
+ d->ulCornerInY = Placeable.Dst.top;
+
+ d->E2IdirY = 1.0; // assume MM_ANISOTROPIC, if not, this will be changed later
+ d->D2PscaleX = d->D2PscaleY = Inkscape::Util::Quantity::convert(1, "in", "px")/(double) Placeable.Inch;
+ trinfo_load_qe(d->tri, d->D2PscaleX); /* quantization error that will affect text positions */
+
+ // drawing size in Inkscape pixels
+ d->PixelsOutX = d->PixelsInX * d->D2PscaleX;
+ d->PixelsOutY = d->PixelsInY * d->D2PscaleY;
+
+ // Upper left corner in Inkscape units
+ d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX;
+ d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY;
+
+ d->dc[0].style.stroke_width.value = pix_to_abs_size( d, 1 ); // This could not be set until the size of the WMF was known
+ dbg_str << "<!-- U_WMR_HEADER -->\n";
+
+ *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
+
+ SVGOStringStream tmp_outdef;
+ tmp_outdef << "<svg\n";
+ tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
+ tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n";
+ tmp_outdef << " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n";
+ tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role
+ tmp_outdef << " version=\"1.0\"\n";
+
+ tmp_outdef <<
+ " width=\"" << Inkscape::Util::Quantity::convert(d->PixelsOutX, "px", "mm") << "mm\"\n" <<
+ " height=\"" << Inkscape::Util::Quantity::convert(d->PixelsOutY, "px", "mm") << "mm\">\n";
+ *(d->outdef) += tmp_outdef.str().c_str();
+ *(d->outdef) += "<defs>"; // temporary end of header
+
+ // d->defs holds any defines which are read in.
+
+
+ }
+
+
+
+ while(OK){
+ if(off>=length)return(0); //normally should exit from while after WMREOF sets OK to false.
+ contents += nSize; // pointer to the start of the next record
+ off += nSize; // offset from beginning of buffer to the start of the next record
+
+ SVGOStringStream tmp_path;
+ SVGOStringStream tmp_str;
+
+ /* Check that the current record size is OK, abort if not.
+ Pointer math might wrap, so check both sides of the range.
+ Some of the records will reset this with the same value,others will not
+ return a value at this time. */
+ nSize = U_WMRRECSAFE_get(contents, blimit);
+ if(!nSize)break;
+
+ iType = *(uint8_t *)(contents + offsetof(U_METARECORD, iType ) );
+
+// Uncomment the following to track down toxic records
+// std::cout << "record type: " << (int) iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
+
+ wmr_mask = U_wmr_properties(iType);
+ if(wmr_mask == U_WMR_INVALID){ throw "Inkscape fatal programming error at U_wmr_properties"; }
+
+/* Uncomment the following to track down text problems */
+//std::cout << "tri->dirty:"<< d->tri->dirty << " wmr_mask: " << std::hex << wmr_mask << std::dec << std::endl;
+
+ // incompatible change to text drawing detected (color or background change) forces out existing text
+ // OR
+ // next record is valid type and forces pending text to be drawn immediately
+ if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((wmr_mask != U_WMR_INVALID) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty)){
+ TR_layout_analyze(d->tri);
+ TR_layout_2_svg(d->tri);
+ SVGOStringStream ts;
+ ts << d->tri->out;
+ *(d->outsvg) += ts.str().c_str();
+ d->tri = trinfo_clear(d->tri);
+ }
+ if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag
+ d->dc[d->level].bkMode = tbkMode;
+ memcpy(&(d->dc[d->level].bkColor),&tbkColor, sizeof(U_COLORREF));
+
+ if(d->dc[d->level].dirty & DIRTY_TEXT){
+ // U_COLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing...
+ if(tbkMode == U_TRANSPARENT){ (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); }
+ else { (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); } // Opaque
+ }
+
+ /* It is possible to have a series of EMF records that would result in
+ the following creating hash patterns which are never used. For instance, if
+ there were a series of records that changed the background color but did nothing
+ else.
+ */
+ if((d->dc[d->level].fill_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_FILL)){
+ select_brush(d, d->dc[d->level].fill_recidx);
+ }
+
+ d->dc[d->level].dirty = 0;
+ }
+
+//std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl;
+/*
+std::cout << "BEFORE DRAW"
+ << " test0 " << ( d->mask & U_DRAW_VISIBLE)
+ << " test1 " << ( d->mask & U_DRAW_FORCE)
+ << " test2 " << (wmr_mask & U_DRAW_ALTERS)
+ << " test3 " << (wmr_mask & U_DRAW_VISIBLE)
+ << " test4 " << !(d->mask & U_DRAW_ONLYTO)
+ << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) )
+ << std::endl;
+*/
+
+ if(
+ (wmr_mask != U_WMR_INVALID) && // next record is valid type
+ (d->mask & U_DRAW_VISIBLE) && // This record is drawable
+ (
+ (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH
+ (wmr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way
+ ( (wmr_mask & U_DRAW_VISIBLE) && // Next record is visible...
+ (
+ ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible
+ ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) )// *TO records can only be followed by other *TO records
+ )
+ )
+ )
+ ){
+// std::cout << "PATH DRAW at TOP <<+++++++++++++++++++++++++++++++++++++" << std::endl;
+ *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!!!
+ output_style(d);
+ *(d->outsvg) += "\n\t";
+ *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!!
+ *(d->outsvg) += *(d->path);
+ *(d->outsvg) += " \" /> \n";
+ *(d->path) = ""; //reset the path
+ // reset the flags
+ d->mask = 0;
+ d->drawtype = 0;
+ }
+// std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl;
+ switch (iType)
+ {
+ case U_WMR_EOF:
+ {
+ dbg_str << "<!-- U_WMR_EOF -->\n";
+
+ *(d->outsvg) = *(d->outdef) + *(d->defs) + "\n</defs>\n\n" + *(d->outsvg) + "</svg>\n";
+ OK=0;
+ break;
+ }
+ case U_WMR_SETBKCOLOR:
+ {
+ dbg_str << "<!-- U_WMR_SETBKCOLOR -->\n";
+ nSize = U_WMRSETBKCOLOR_get(contents, &tbkColor);
+ if(memcmp(&tbkColor, &(d->dc[d->level].bkColor), sizeof(U_COLORREF))){
+ d->dc[d->level].dirty |= DIRTY_TEXT;
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ tbkMode = d->dc[d->level].bkMode;
+ }
+ break;
+ }
+ case U_WMR_SETBKMODE:{
+ dbg_str << "<!-- U_WMR_SETBKMODE -->\n";
+ nSize = U_WMRSETBKMODE_get(contents, &tbkMode);
+ if(tbkMode != d->dc[d->level].bkMode){
+ d->dc[d->level].dirty |= DIRTY_TEXT;
+ if(tbkMode != d->dc[d->level].bkMode){
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ }
+ memcpy(&tbkColor,&(d->dc[d->level].bkColor),sizeof(U_COLORREF));
+ }
+ break;
+ }
+ case U_WMR_SETMAPMODE:
+ {
+ dbg_str << "<!-- U_WMR_SETMAPMODE -->\n";
+ nSize = U_WMRSETMAPMODE_get(contents, &utmp16);
+ switch (utmp16){
+ case U_MM_TEXT:
+ default:
+ // Use all values from the header.
+ break;
+ /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex
+ and show up in ScaleIn[XY]
+ */
+ case U_MM_LOMETRIC: // 1 LU = 0.1 mm,
+ case U_MM_HIMETRIC: // 1 LU = 0.01 mm
+ case U_MM_LOENGLISH: // 1 LU = 0.1 in
+ case U_MM_HIENGLISH: // 1 LU = 0.01 in
+ case U_MM_TWIPS: // 1 LU = 1/1440 in
+ d->E2IdirY = -1.0;
+ // Use d->D2Pscale[XY] values from the header.
+ break;
+ case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX
+ case U_MM_ANISOTROPIC:
+ break;
+ }
+ break;
+ }
+ case U_WMR_SETROP2:
+ {
+ dbg_str << "<!-- U_WMR_SETROP2 -->\n";
+ nSize = U_WMRSETROP2_get(contents, &utmp16);
+ d->dwRop2 = utmp16;
+ break;
+ }
+ case U_WMR_SETRELABS: dbg_str << "<!-- U_WMR_SETRELABS -->\n"; break;
+ case U_WMR_SETPOLYFILLMODE:
+ {
+ dbg_str << "<!-- U_WMR_SETPOLYFILLMODE -->\n";
+ nSize = U_WMRSETPOLYFILLMODE_get(contents, &utmp16);
+ d->dc[d->level].style.fill_rule.value = (utmp16 == U_ALTERNATE ? 0 : utmp16 == U_WINDING ? 1 : 0);
+ break;
+ }
+ case U_WMR_SETSTRETCHBLTMODE:
+ {
+ dbg_str << "<!-- U_WMR_SETSTRETCHBLTMODE -->\n";
+ nSize = U_WMRSETSTRETCHBLTMODE_get(contents, &utmp16);
+ BLTmode = utmp16;
+ break;
+ }
+ case U_WMR_SETTEXTCHAREXTRA: dbg_str << "<!-- U_WMR_SETTEXTCHAREXTRA -->\n"; break;
+ case U_WMR_SETTEXTCOLOR:
+ {
+ dbg_str << "<!-- U_WMR_SETTEXTCOLOR -->\n";
+ nSize = U_WMRSETTEXTCOLOR_get(contents, &(d->dc[d->level].textColor));
+ if(tbkMode != d->dc[d->level].bkMode){
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ }
+ // not text_dirty, because multicolored complex text is supported in libTERE
+ break;
+ }
+ case U_WMR_SETTEXTJUSTIFICATION: dbg_str << "<!-- U_WMR_SETTEXTJUSTIFICATION -->\n"; break;
+ case U_WMR_SETWINDOWORG:
+ {
+ dbg_str << "<!-- U_WMR_SETWINDOWORG -->\n";
+ nSize = U_WMRSETWINDOWORG_get(contents, &d->dc[d->level].winorg);
+ d->ulCornerOutX = 0.0; // In the examples seen to date if this record is used with a placeable header, that header is ignored
+ d->ulCornerOutY = 0.0;
+ break;
+ }
+ case U_WMR_SETWINDOWEXT:
+ {
+ dbg_str << "<!-- U_WMR_SETWINDOWEXT -->\n";
+
+ nSize = U_WMRSETWINDOWEXT_get(contents, &d->dc[d->level].sizeWnd);
+
+ if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) {
+ d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
+ if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) {
+ d->dc[d->level].sizeWnd.x = d->PixelsOutX;
+ d->dc[d->level].sizeWnd.y = d->PixelsOutY;
+ }
+ }
+ else {
+ /* There are a lot WMF files in circulation with the x,y values in the setwindowext reversed. If this is detected, swap them.
+ There is a remote possibility that the strange scaling this implies was intended, and those will be rendered incorrectly */
+ double Ox = d->PixelsOutX;
+ double Oy = d->PixelsOutY;
+ double Wx = d->dc[d->level].sizeWnd.x;
+ double Wy = d->dc[d->level].sizeWnd.y;
+ if(Wx != Wy && Geom::are_near(Ox/Wy, Oy/Wx, 1.01/MIN(Wx,Wy)) ){
+ int tmp;
+ tmp = d->dc[d->level].sizeWnd.x;
+ d->dc[d->level].sizeWnd.x = d->dc[d->level].sizeWnd.y;
+ d->dc[d->level].sizeWnd.y = tmp;
+ }
+ }
+
+ if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) {
+ /* Previously it used sizeWnd, but that always resulted in scale = 1 if no viewport ever appeared, and in most files, it did not */
+ d->dc[d->level].sizeView.x = d->PixelsInX - 1;
+ d->dc[d->level].sizeView.y = d->PixelsInY - 1;
+ }
+
+ /* scales logical to WMF pixels, transfer a negative sign on Y, if any */
+ if (d->dc[d->level].sizeWnd.x && d->dc[d->level].sizeWnd.y) {
+ d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.x / (double) d->dc[d->level].sizeWnd.x;
+ d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.y / (double) d->dc[d->level].sizeWnd.y;
+ if(d->dc[d->level].ScaleInY < 0){
+ d->dc[d->level].ScaleInY *= -1.0;
+ d->E2IdirY = -1.0;
+ }
+ }
+ else {
+ d->dc[d->level].ScaleInX = 1;
+ d->dc[d->level].ScaleInY = 1;
+ }
+ break;
+ }
+ case U_WMR_SETVIEWPORTORG:
+ {
+ dbg_str << "<!-- U_WMR_SETWINDOWORG -->\n";
+ nSize = U_WMRSETVIEWPORTORG_get(contents, &d->dc[d->level].vieworg);
+ break;
+ }
+ case U_WMR_SETVIEWPORTEXT:
+ {
+ dbg_str << "<!-- U_WMR_SETVIEWPORTEXTEX -->\n";
+
+ nSize = U_WMRSETVIEWPORTEXT_get(contents, &d->dc[d->level].sizeView);
+
+ if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) {
+ d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
+ if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) {
+ d->dc[d->level].sizeView.x = d->PixelsOutX;
+ d->dc[d->level].sizeView.y = d->PixelsOutY;
+ }
+ }
+
+ if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) {
+ d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
+ }
+
+ /* scales logical to WMF pixels, transfer a negative sign on Y, if any */
+ if (d->dc[d->level].sizeWnd.x && d->dc[d->level].sizeWnd.y) {
+ d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.x / (double) d->dc[d->level].sizeWnd.x;
+ d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.y / (double) d->dc[d->level].sizeWnd.y;
+ if(d->dc[d->level].ScaleInY < 0){
+ d->dc[d->level].ScaleInY *= -1.0;
+ d->E2IdirY = -1.0;
+ }
+ }
+ else {
+ d->dc[d->level].ScaleInX = 1;
+ d->dc[d->level].ScaleInY = 1;
+ }
+ break;
+ }
+ case U_WMR_OFFSETWINDOWORG: dbg_str << "<!-- U_WMR_OFFSETWINDOWORG -->\n"; break;
+ case U_WMR_SCALEWINDOWEXT: dbg_str << "<!-- U_WMR_SCALEWINDOWEXT -->\n"; break;
+ case U_WMR_OFFSETVIEWPORTORG: dbg_str << "<!-- U_WMR_OFFSETVIEWPORTORG -->\n"; break;
+ case U_WMR_SCALEVIEWPORTEXT: dbg_str << "<!-- U_WMR_SCALEVIEWPORTEXT -->\n"; break;
+ case U_WMR_LINETO:
+ {
+ dbg_str << "<!-- U_WMR_LINETO -->\n";
+
+ nSize = U_WMRLINETO_get(contents, &pt16);
+
+ d->mask |= wmr_mask;
+
+ tmp_path << "\n\tL " << pix_to_xy( d, pt16.x, pt16.y) << " ";
+ break;
+ }
+ case U_WMR_MOVETO:
+ {
+ dbg_str << "<!-- U_WMR_MOVETO -->\n";
+
+ nSize = U_WMRLINETO_get(contents, &pt16);
+
+ d->mask |= wmr_mask;
+
+ d->dc[d->level].cur = pt16;
+
+ tmp_path <<
+ "\n\tM " << pix_to_xy( d, pt16.x, pt16.y ) << " ";
+ break;
+ }
+ case U_WMR_EXCLUDECLIPRECT: dbg_str << "<!-- U_WMR_EXCLUDECLIPRECT -->\n"; break;
+ case U_WMR_INTERSECTCLIPRECT:
+ {
+ dbg_str << "<!-- U_WMR_INTERSECTCLIPRECT -->\n";
+
+ nSize = U_WMRINTERSECTCLIPRECT_get(contents, &rc);
+ clipset = true;
+ if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom))
+ break;
+ rc_old = rc;
+
+ double dx = pix_to_x_point( d, rc.left, rc.top );
+ double dy = pix_to_y_point( d, rc.left, rc.top );
+ double dw = pix_to_abs_size( d, rc.right - rc.left + 1);
+ double dh = pix_to_abs_size( d, rc.bottom - rc.top + 1);
+
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n<clipPath\n\tclipPathUnits=\"userSpaceOnUse\" ";
+ tmp_rectangle << "\nid=\"clipWmfPath" << ++(d->id) << "\" >";
+ tmp_rectangle << "\n<rect ";
+ tmp_rectangle << "\n x=\"" << dx << "\" ";
+ tmp_rectangle << "\n y=\"" << dy << "\" ";
+ tmp_rectangle << "\n width=\"" << dw << "\" ";
+ tmp_rectangle << "\n height=\"" << dh << "\" />";
+ tmp_rectangle << "\n</clipPath>";
+
+ *(d->outdef) += tmp_rectangle.str().c_str();
+ *(d->path) = "";
+ break;
+ }
+ case U_WMR_ARC:
+ {
+ dbg_str << "<!-- U_WMR_ARC -->\n";
+ U_POINT16 ArcStart, ArcEnd;
+ nSize = U_WMRARC_get(contents, &ArcStart, &ArcEnd, &rc);
+
+ U_PAIRF center,start,end,size;
+ int f1;
+ int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
+ int stat = wmr_arc_points(rc, ArcStart, ArcEnd,&f1, f2, &center, &start, &end, &size);
+ if(!stat){
+ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ d->mask |= wmr_mask;
+ }
+ else {
+ dbg_str << "<!-- ARC record is invalid -->\n";
+ }
+ break;
+ }
+ case U_WMR_ELLIPSE:
+ {
+ dbg_str << "<!-- U_WMR_ELLIPSE -->\n";
+
+ nSize = U_WMRELLIPSE_get(contents, &rc);
+
+ double cx = pix_to_x_point( d, (rc.left + rc.right)/2.0, (rc.bottom + rc.top)/2.0 );
+ double cy = pix_to_y_point( d, (rc.left + rc.right)/2.0, (rc.bottom + rc.top)/2.0 );
+ double rx = pix_to_abs_size( d, fabs(rc.right - rc.left )/2.0 );
+ double ry = pix_to_abs_size( d, fabs(rc.top - rc.bottom)/2.0 );
+
+ SVGOStringStream tmp_ellipse;
+ tmp_ellipse << "cx=\"" << cx << "\" ";
+ tmp_ellipse << "cy=\"" << cy << "\" ";
+ tmp_ellipse << "rx=\"" << rx << "\" ";
+ tmp_ellipse << "ry=\"" << ry << "\" ";
+
+ d->mask |= wmr_mask;
+
+ *(d->outsvg) += " <ellipse ";
+ output_style(d);
+ *(d->outsvg) += "\n\t";
+ *(d->outsvg) += tmp_ellipse.str().c_str();
+ *(d->outsvg) += "/> \n";
+ *(d->path) = "";
+ break;
+ }
+ case U_WMR_FLOODFILL: dbg_str << "<!-- U_WMR_EXTFLOODFILL -->\n"; break;
+ case U_WMR_PIE:
+ {
+ dbg_str << "<!-- U_WMR_PIE -->\n";
+ U_POINT16 ArcStart, ArcEnd;
+ nSize = U_WMRPIE_get(contents, &ArcStart, &ArcEnd, &rc);
+ U_PAIRF center,start,end,size;
+ int f1;
+ int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
+ if(!wmr_arc_points(rc, ArcStart, ArcEnd, &f1, f2, &center, &start, &end, &size)){
+ tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y);
+ tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ tmp_path << " z ";
+ d->mask |= wmr_mask;
+ }
+ else {
+ dbg_str << "<!-- PIE record is invalid -->\n";
+ }
+ break;
+ }
+ case U_WMR_RECTANGLE:
+ {
+ dbg_str << "<!-- U_WMR_RECTANGLE -->\n";
+
+ nSize = U_WMRRECTANGLE_get(contents, &rc);
+ U_sanerect16(rc, &left, &top, &right, &bottom);
+
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n\tM " << pix_to_xy( d, left , top ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, right, top ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, right, bottom ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, left, bottom ) << " ";
+ tmp_rectangle << "\n\tz";
+
+ d->mask |= wmr_mask;
+
+ tmp_path << tmp_rectangle.str().c_str();
+ break;
+ }
+ case U_WMR_ROUNDRECT:
+ {
+ dbg_str << "<!-- U_WMR_ROUNDRECT -->\n";
+
+ int16_t Height,Width;
+ nSize = U_WMRROUNDRECT_get(contents, &Width, &Height, &rc);
+ U_sanerect16(rc, &left, &top, &right, &bottom);
+ double f = 4.*(sqrt(2) - 1)/3;
+ double f1 = 1.0 - f;
+ double cnx = Width/2;
+ double cny = Height/2;
+
+
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n"
+ << " M "
+ << pix_to_xy(d, left , top + cny )
+ << "\n";
+ tmp_rectangle << " C "
+ << pix_to_xy(d, left , top + cny*f1 )
+ << " "
+ << pix_to_xy(d, left + cnx*f1 , top )
+ << " "
+ << pix_to_xy(d, left + cnx , top )
+ << "\n";
+ tmp_rectangle << " L "
+ << pix_to_xy(d, right - cnx , top )
+ << "\n";
+ tmp_rectangle << " C "
+ << pix_to_xy(d, right - cnx*f1 , top )
+ << " "
+ << pix_to_xy(d, right , top + cny*f1 )
+ << " "
+ << pix_to_xy(d, right , top + cny )
+ << "\n";
+ tmp_rectangle << " L "
+ << pix_to_xy(d, right , bottom - cny )
+ << "\n";
+ tmp_rectangle << " C "
+ << pix_to_xy(d, right , bottom - cny*f1 )
+ << " "
+ << pix_to_xy(d, right - cnx*f1 , bottom )
+ << " "
+ << pix_to_xy(d, right - cnx , bottom )
+ << "\n";
+ tmp_rectangle << " L "
+ << pix_to_xy(d, left + cnx , bottom )
+ << "\n";
+ tmp_rectangle << " C "
+ << pix_to_xy(d, left + cnx*f1 , bottom )
+ << " "
+ << pix_to_xy(d, left , bottom - cny*f1 )
+ << " "
+ << pix_to_xy(d, left , bottom - cny )
+ << "\n";
+ tmp_rectangle << " z\n";
+
+
+ d->mask |= wmr_mask;
+
+ tmp_path << tmp_rectangle.str().c_str();
+ break;
+ }
+ case U_WMR_PATBLT:
+ {
+ dbg_str << "<!-- U_WMR_PATBLT -->\n";
+ // Treat this like any other rectangle, ie, ignore the dwRop3
+ nSize = U_WMRPATBLT_get(contents, &Dst, &cwh, &dwRop3);
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n\tM " << pix_to_xy( d, Dst.x , Dst.y ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x + cwh.x, Dst.y ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x + cwh.x, Dst.y + cwh.y ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x, Dst.y + cwh.y ) << " ";
+ tmp_rectangle << "\n\tz";
+
+ d->mask |= wmr_mask;
+
+ tmp_path << tmp_rectangle.str().c_str();
+ break;
+ }
+ case U_WMR_SAVEDC:
+ {
+ dbg_str << "<!-- U_WMR_SAVEDC -->\n";
+
+ if (d->level < WMF_MAX_DC) {
+ d->dc[d->level + 1] = d->dc[d->level];
+ if(d->dc[d->level].font_name){
+ d->dc[d->level + 1].font_name = strdup(d->dc[d->level].font_name); // or memory access problems because font name pointer duplicated
+ }
+ d->level = d->level + 1;
+ }
+ break;
+ }
+ case U_WMR_SETPIXEL: dbg_str << "<!-- U_WMR_SETPIXEL -->\n"; break;
+ case U_WMR_OFFSETCLIPRGN: dbg_str << "<!-- U_WMR_OFFSETCLIPRGN/POLYLINE -->\n"; break;
+ // U_WMR_TEXTOUT should be here, but has been moved down to merge with U_WMR_EXTTEXTOUT
+ case U_WMR_BITBLT:
+ {
+ dbg_str << "<!-- U_WMR_BITBLT -->\n";
+ nSize = U_WMRBITBLT_get(contents,&Dst,&cwh,&Src,&dwRop3,&Bm16,&px);
+ if(!px){
+ if(dwRop3 == U_NOOP)break; /* GDI applications apparently often end with this as a sort of flush(), nothing should be drawn */
+ int32_t dx = Dst.x;
+ int32_t dy = Dst.y;
+ int32_t dw = cwh.x;
+ int32_t dh = cwh.y;
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " ";
+ tmp_rectangle << "\n\tz";
+
+ d->mask |= wmr_mask;
+ d->dwRop3 = dwRop3; // we will try to approximate SOME of these
+ d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that
+
+ tmp_path << tmp_rectangle.str().c_str();
+ }
+ else { /* Not done yet, Bm16 image present */ }
+ double dx = pix_to_x_point( d, Dst.x, Dst.y);
+ double dy = pix_to_y_point( d, Dst.x, Dst.y);
+ double dw = pix_to_abs_size( d, cwh.x);
+ double dh = pix_to_abs_size( d, cwh.y);
+ //source position within the bitmap, in pixels
+ int sx = Src.x;
+ int sy = Src.y;
+ int sw = 0; // extract all of the image
+ int sh = 0;
+ if(sx<0)sx=0;
+ if(sy<0)sy=0;
+ common_bm16_to_image(d,Bm16,px,dx,dy,dw,dh,sx,sy,sw,sh);
+ break;
+ }
+ case U_WMR_STRETCHBLT:
+ {
+ dbg_str << "<!-- U_WMR_STRETCHBLT -->\n";
+ nSize = U_WMRSTRETCHBLT_get(contents,&Dst,&cDst,&Src,&cSrc,&dwRop3,&Bm16,&px);
+ if(!px){
+ if(dwRop3 == U_NOOP)break; /* GDI applications apparently often end with this as a sort of flush(), nothing should be drawn */
+ int32_t dx = Dst.x;
+ int32_t dy = Dst.y;
+ int32_t dw = cDst.x;
+ int32_t dh = cDst.y;
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " ";
+ tmp_rectangle << "\n\tz";
+
+ d->mask |= wmr_mask;
+ d->dwRop3 = dwRop3; // we will try to approximate SOME of these
+ d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that
+
+ tmp_path << tmp_rectangle.str().c_str();
+ }
+ else { /* Not done yet, Bm16 image present */ }
+ double dx = pix_to_x_point( d, Dst.x, Dst.y);
+ double dy = pix_to_y_point( d, Dst.x, Dst.y);
+ double dw = pix_to_abs_size( d, cDst.x);
+ double dh = pix_to_abs_size( d, cDst.y);
+ //source position within the bitmap, in pixels
+ int sx = Src.x;
+ int sy = Src.y;
+ int sw = cSrc.x; // extract the specified amount of the image
+ int sh = cSrc.y;
+ if(sx<0)sx=0;
+ if(sy<0)sy=0;
+ common_bm16_to_image(d,Bm16,px,dx,dy,dw,dh,sx,sy,sw,sh);
+ break;
+ }
+ case U_WMR_POLYGON:
+ case U_WMR_POLYLINE:
+ {
+ dbg_str << "<!-- U_WMR_POLYGON/POLYLINE -->\n";
+ nSize = U_WMRPOLYGON_get(contents, &cPts, &points);
+ uint32_t i;
+
+ if (cPts < 2)break;
+
+ d->mask |= wmr_mask;
+ memcpy(&pt16,points,U_SIZE_POINT16); points += U_SIZE_POINT16;
+
+ tmp_str << "\n\tM " << pix_to_xy( d, pt16.x, pt16.y) << " ";
+
+ for (i=1; i<cPts; i++) {
+ memcpy(&pt16,points,U_SIZE_POINT16); points+=U_SIZE_POINT16;
+ tmp_str << "\n\tL " << pix_to_xy( d, pt16.x, pt16.y) << " ";
+ }
+
+ tmp_path << tmp_str.str().c_str();
+ if(iType==U_WMR_POLYGON){ tmp_path << " z"; }
+
+ break;
+ }
+ case U_WMR_ESCAPE: // only 3 types of escape are implemented
+ {
+ dbg_str << "<!-- U_WMR_ESCAPE -->\n";
+ uint16_t Escape, elen;
+ nSize = U_WMRESCAPE_get(contents, &Escape, &elen, &text);
+ if(elen>=4){
+ uint32_t utmp4;
+ memcpy(&utmp4, text ,4);
+ if(Escape == U_MFE_SETLINECAP){
+ switch (utmp4 & U_PS_ENDCAP_MASK) {
+ case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = 1; break; }
+ case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = 2; break; }
+ case U_PS_ENDCAP_FLAT:
+ default: { d->dc[d->level].style.stroke_linecap.computed = 0; break; }
+ }
+ }
+ else if(Escape == U_MFE_SETLINEJOIN){
+ switch (utmp4 & U_PS_JOIN_MASK) {
+ case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = 2; break; }
+ case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = 0; break; }
+ case U_PS_JOIN_ROUND:
+ default: { d->dc[d->level].style.stroke_linejoin.computed = 1; break; }
+ }
+ }
+ else if(Escape == U_MFE_SETMITERLIMIT){
+ //The function takes a float but uses a 32 bit int in the record.
+ float miterlimit = utmp4;
+ d->dc[d->level].style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size
+ if (d->dc[d->level].style.stroke_miterlimit.value < 2)
+ d->dc[d->level].style.stroke_miterlimit.value = 2.0;
+ }
+ }
+ break;
+ }
+ case U_WMR_RESTOREDC:
+ {
+ dbg_str << "<!-- U_WMR_RESTOREDC -->\n";
+
+ int16_t DC;
+ nSize = U_WMRRESTOREDC_get(contents, &DC);
+ int old_level = d->level;
+ if (DC >= 0) {
+ if (DC < d->level)
+ d->level = DC;
+ }
+ else {
+ if (d->level + DC >= 0)
+ d->level = d->level + DC;
+ }
+ while (old_level > d->level) {
+ if (!d->dc[old_level].style.stroke_dasharray.values.empty() && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dasharray.values!=d->dc[old_level-1].style.stroke_dasharray.values))){
+ d->dc[old_level].style.stroke_dasharray.values.clear();
+ }
+ if(d->dc[old_level].font_name){
+ free(d->dc[old_level].font_name); // else memory leak
+ d->dc[old_level].font_name = NULL;
+ }
+ old_level--;
+ }
+ break;
+ }
+ case U_WMR_FILLREGION: dbg_str << "<!-- U_WMR_FILLREGION -->\n"; break;
+ case U_WMR_FRAMEREGION: dbg_str << "<!-- U_WMR_FRAMEREGION -->\n"; break;
+ case U_WMR_INVERTREGION: dbg_str << "<!-- U_WMR_INVERTREGION -->\n"; break;
+ case U_WMR_PAINTREGION: dbg_str << "<!-- U_WMR_PAINTREGION -->\n"; break;
+ case U_WMR_SELECTCLIPREGION:
+ {
+ dbg_str << "<!-- U_WMR_EXTSELECTCLIPRGN -->\n";
+ nSize = U_WMRSELECTCLIPREGION_get(contents, &utmp16);
+ if (utmp16 == U_RGN_COPY)
+ clipset = false;
+ break;
+ }
+ case U_WMR_SELECTOBJECT:
+ {
+ dbg_str << "<!-- U_WMR_SELECTOBJECT -->\n";
+
+ nSize = U_WMRSELECTOBJECT_get(contents, &utmp16);
+ unsigned int index = utmp16;
+
+ // WMF has no stock objects
+ if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) {
+ switch (d->wmf_obj[index].type)
+ {
+ case U_WMR_CREATEPENINDIRECT:
+ select_pen(d, index);
+ break;
+ case U_WMR_CREATEBRUSHINDIRECT:
+ case U_WMR_DIBCREATEPATTERNBRUSH:
+ case U_WMR_CREATEPATTERNBRUSH: // <- this one did not display properly on XP, DIBCREATEPATTERNBRUSH works
+ select_brush(d, index);
+ break;
+ case U_WMR_CREATEFONTINDIRECT:
+ select_font(d, index);
+ break;
+ case U_WMR_CREATEPALETTE:
+ case U_WMR_CREATEBITMAPINDIRECT:
+ case U_WMR_CREATEBITMAP:
+ case U_WMR_CREATEREGION:
+ /* these do not do anything, but their objects must be kept in the count */
+ break;
+ }
+ }
+ break;
+ }
+ case U_WMR_SETTEXTALIGN:
+ {
+ dbg_str << "<!-- U_WMR_SETTEXTALIGN -->\n";
+ nSize = U_WMRSETTEXTALIGN_get(contents, &(d->dc[d->level].textAlign));
+ break;
+ }
+ case U_WMR_DRAWTEXT: dbg_str << "<!-- U_WMR_DRAWTEXT -->\n"; break;
+ case U_WMR_CHORD:
+ {
+ dbg_str << "<!-- U_WMR_CHORD -->\n";
+ U_POINT16 ArcStart, ArcEnd;
+ nSize = U_WMRCHORD_get(contents, &ArcStart, &ArcEnd, &rc);
+ U_PAIRF center,start,end,size;
+ int f1;
+ int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
+ if(!wmr_arc_points(rc, ArcStart, ArcEnd, &f1, f2, &center, &start, &end, &size)){
+ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ tmp_path << " z ";
+ d->mask |= wmr_mask;
+ }
+ else {
+ dbg_str << "<!-- CHORD record is invalid -->\n";
+ }
+ break;
+ }
+ case U_WMR_SETMAPPERFLAGS: dbg_str << "<!-- U_WMR_SETMAPPERFLAGS -->\n"; break;
+ case U_WMR_TEXTOUT:
+ case U_WMR_EXTTEXTOUT:
+ {
+ if(iType == U_WMR_TEXTOUT){
+ dbg_str << "<!-- U_WMR_TEXTOUT -->\n";
+ nSize = U_WMRTEXTOUT_get(contents, &Dst, &tlen, &text);
+ Opts=0;
+ }
+ else {
+ dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n";
+ nSize = U_WMREXTTEXTOUT_get(contents, &Dst, &tlen, &Opts, &text, &dx, &rc );
+ }
+ uint32_t fOptions = Opts;
+
+ double x1,y1;
+ int cChars;
+ x1 = Dst.x;
+ y1 = Dst.y;
+ cChars = tlen;
+
+ if (d->dc[d->level].textAlign & U_TA_UPDATECP) {
+ x1 = d->dc[d->level].cur.x;
+ y1 = d->dc[d->level].cur.y;
+ }
+
+ double x = pix_to_x_point(d, x1, y1);
+ double y = pix_to_y_point(d, x1, y1);
+
+ /* Rotation issues are handled entirely in libTERE now */
+
+ uint32_t *dup_wt = NULL;
+
+ dup_wt = U_Latin1ToUtf32le(text, cChars, NULL);
+ if(!dup_wt)dup_wt = unknown_chars(cChars);
+
+ msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats
+
+ if(NonToUnicode(dup_wt, d->dc[d->level].font_name)){
+ free(d->dc[d->level].font_name);
+ d->dc[d->level].font_name = strdup("Times New Roman");
+ }
+
+ char *ansi_text;
+ ansi_text = (char *) U_Utf32leToUtf8((uint32_t *)dup_wt, 0, NULL);
+ free(dup_wt);
+ // Empty text or starts with an invalid escape/control sequence, which is bogus text. Throw it out before g_markup_escape_text can make things worse
+ if(*((uint8_t *)ansi_text) <= 0x1F){
+ free(ansi_text);
+ ansi_text=NULL;
+ }
+
+ if (ansi_text) {
+
+ SVGOStringStream ts;
+
+ gchar *escaped_text = g_markup_escape_text(ansi_text, -1);
+
+ tsp.x = x*0.8; // TERE expects sizes in points
+ tsp.y = y*0.8;
+ tsp.color.Red = d->dc[d->level].textColor.Red;
+ tsp.color.Green = d->dc[d->level].textColor.Green;
+ tsp.color.Blue = d->dc[d->level].textColor.Blue;
+ tsp.color.Reserved = 0;
+ switch(d->dc[d->level].style.font_style.value){
+ case SP_CSS_FONT_STYLE_OBLIQUE:
+ tsp.italics = FC_SLANT_OBLIQUE; break;
+ case SP_CSS_FONT_STYLE_ITALIC:
+ tsp.italics = FC_SLANT_ITALIC; break;
+ default:
+ case SP_CSS_FONT_STYLE_NORMAL:
+ tsp.italics = FC_SLANT_ROMAN; break;
+ }
+ switch(d->dc[d->level].style.font_weight.value){
+ case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break;
+ case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break;
+ case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break;
+ case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break;
+ case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
+ case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break;
+ case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break;
+ case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
+ default: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ }
+ // WMF only supports two types of text decoration
+ tsp.decoration = TXTDECOR_NONE;
+ if(d->dc[d->level].style.text_decoration_line.underline){ tsp.decoration |= TXTDECOR_UNDER; }
+ if(d->dc[d->level].style.text_decoration_line.line_through){ tsp.decoration |= TXTDECOR_STRIKE;}
+
+ // WMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left
+ tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER :
+ (((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT :
+ ALIRIGHT);
+ tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE :
+ ((d->dc[d->level].textAlign & U_TA_BOTTOM) ? ALIBOT :
+ ALITOP));
+
+ // language direction can be encoded two ways, U_TA_RTLREADING is preferred
+ if( (fOptions & U_ETO_RTLREADING) || (d->dc[d->level].textAlign & U_TA_RTLREADING) ){ tsp.ldir = LDIR_RL; }
+ else{ tsp.ldir = LDIR_LR; }
+
+ tsp.condensed = FC_WIDTH_NORMAL; // Not implemented well in libTERE (yet)
+ tsp.ori = d->dc[d->level].style.baseline_shift.value; // For now orientation is always the same as escapement
+ // There is no world transform, so ori need not be further rotated
+ tsp.string = (uint8_t *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear().
+ tsp.fs = d->dc[d->level].style.font_size.computed * 0.8; // Font size in points
+ char *fontspec = TR_construct_fontspec(&tsp, d->dc[d->level].font_name);
+ tsp.fi_idx = ftinfo_load_fontname(d->tri->fti,fontspec);
+ free(fontspec);
+ // when font name includes narrow it may not be set to "condensed". Narrow fonts do not work well anyway though
+ // as the metrics from fontconfig may not match, or the font may not be present.
+ if(0<= TR_findcasesub(d->dc[d->level].font_name, (char *) "Narrow")){ tsp.co=1; }
+ else { tsp.co=0; }
+
+ int status;
+
+ status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement
+ if(status==-1){ // change of escapement, emit what we have and reset
+ TR_layout_analyze(d->tri);
+ TR_layout_2_svg(d->tri);
+ ts << d->tri->out;
+ *(d->outsvg) += ts.str().c_str();
+ d->tri = trinfo_clear(d->tri);
+ (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
+ }
+
+ g_free(escaped_text);
+ free(ansi_text);
+ }
+
+ break;
+ }
+ case U_WMR_SETDIBTODEV: dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n"; break;
+ case U_WMR_SELECTPALETTE: dbg_str << "<!-- U_WMR_SELECTPALETTE -->\n"; break;
+ case U_WMR_REALIZEPALETTE: dbg_str << "<!-- U_WMR_REALIZEPALETTE -->\n"; break;
+ case U_WMR_ANIMATEPALETTE: dbg_str << "<!-- U_WMR_ANIMATEPALETTE -->\n"; break;
+ case U_WMR_SETPALENTRIES: dbg_str << "<!-- U_WMR_SETPALENTRIES -->\n"; break;
+ case U_WMR_POLYPOLYGON:
+ {
+ dbg_str << "<!-- U_WMR_POLYPOLYGON16 -->\n";
+ uint16_t nPolys;
+ const uint16_t *aPolyCounts;
+ const char *Points;
+ int cpts; /* total number of points in Points*/
+ nSize = U_WMRPOLYPOLYGON_get(contents, &nPolys, &aPolyCounts, &Points);
+ int n, i, j;
+
+ d->mask |= wmr_mask;
+
+ U_POINT16 apt;
+ for (n=cpts=0; n < nPolys; n++) { cpts += aPolyCounts[n]; }
+ i = 0; // offset in BYTES
+ cpts *= U_SIZE_POINT16; // limit for offset i, in BYTES
+
+ for (n=0; n < nPolys && i<cpts; n++) {
+ SVGOStringStream poly_path;
+
+ memcpy(&apt, Points + i, U_SIZE_POINT16); // points may not be aligned, copy them this way
+
+ poly_path << "\n\tM " << pix_to_xy( d, apt.x, apt.y) << " ";
+ i += U_SIZE_POINT16;
+
+ for (j=1; j < aPolyCounts[n] && i < cpts; j++) {
+ memcpy(&apt, Points + i, U_SIZE_POINT16); // points may not be aligned, copy them this way
+ poly_path << "\n\tL " << pix_to_xy( d, apt.x, apt.y) << " ";
+ i += U_SIZE_POINT16;
+ }
+
+ tmp_str << poly_path.str().c_str();
+ tmp_str << " z";
+ tmp_str << " \n";
+ }
+
+ tmp_path << tmp_str.str().c_str();
+
+ break;
+ }
+ case U_WMR_RESIZEPALETTE: dbg_str << "<!-- U_WMR_RESIZEPALETTE -->\n"; break;
+ case U_WMR_3A:
+ case U_WMR_3B:
+ case U_WMR_3C:
+ case U_WMR_3D:
+ case U_WMR_3E:
+ case U_WMR_3F:
+ {
+ dbg_str << "<!-- U_WMR_3A..3F -->\n";
+ break;
+ }
+ case U_WMR_DIBBITBLT:
+ {
+ dbg_str << "<!-- U_WMR_DIBBITBLT -->\n";
+ nSize = U_WMRDIBBITBLT_get(contents, &Dst, &cwh, &Src, &dwRop3, &dib);
+
+ // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at
+ // least it leaves objects where the operations should have been.
+ if (!dib) {
+ // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead
+
+ if(dwRop3 == U_NOOP)break; /* GDI applications apparently often end with this as a sort of flush(), nothing should be drawn */
+ int32_t dx = Dst.x;
+ int32_t dy = Dst.y;
+ int32_t dw = cwh.x;
+ int32_t dh = cwh.y;
+ SVGOStringStream tmp_rectangle;
+ tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " ";
+ tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " ";
+ tmp_rectangle << "\n\tz";
+
+ d->mask |= wmr_mask;
+ d->dwRop3 = dwRop3; // we will try to approximate SOME of these
+ d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that
+
+ tmp_path << tmp_rectangle.str().c_str();
+ }
+ else {
+ double dx = pix_to_x_point( d, Dst.x, Dst.y);
+ double dy = pix_to_y_point( d, Dst.x, Dst.y);
+ double dw = pix_to_abs_size( d, cDst.x);
+ double dh = pix_to_abs_size( d, cDst.y);
+ //source position within the bitmap, in pixels
+ int sx = Src.x;
+ int sy = Src.y;
+ int sw = 0; // extract all of the image
+ int sh = 0;
+ if(sx<0)sx=0;
+ if(sy<0)sy=0;
+ // usageSrc not defined, implicitly it must be U_DIB_RGB_COLORS
+ common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh,U_DIB_RGB_COLORS);
+ }
+ break;
+ }
+ case U_WMR_DIBSTRETCHBLT:
+ {
+ dbg_str << "<!-- U_WMR_DIBSTRETCHBLT -->\n";
+ nSize = U_WMRDIBSTRETCHBLT_get(contents, &Dst, &cDst, &Src, &cSrc, &dwRop3, &dib);
+ // Always grab image, ignore modes.
+ if (dib) {
+ double dx = pix_to_x_point( d, Dst.x, Dst.y);
+ double dy = pix_to_y_point( d, Dst.x, Dst.y);
+ double dw = pix_to_abs_size( d, cDst.x);
+ double dh = pix_to_abs_size( d, cDst.y);
+ //source position within the bitmap, in pixels
+ int sx = Src.x;
+ int sy = Src.y;
+ int sw = cSrc.x; // extract the specified amount of the image
+ int sh = cSrc.y;
+ // usageSrc not defined, implicitly it must be U_DIB_RGB_COLORS
+ common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh, U_DIB_RGB_COLORS);
+ }
+ break;
+ }
+ case U_WMR_DIBCREATEPATTERNBRUSH:
+ {
+ dbg_str << "<!-- U_WMR_DIBCREATEPATTERNBRUSH -->\n";
+ insert_object(d, U_WMR_DIBCREATEPATTERNBRUSH, contents);
+ break;
+ }
+ case U_WMR_STRETCHDIB:
+ {
+ dbg_str << "<!-- U_WMR_STRETCHDIB -->\n";
+ nSize = U_WMRSTRETCHDIB_get(contents, &Dst, &cDst, &Src, &cSrc, &cUsage, &dwRop3, &dib);
+ double dx = pix_to_x_point( d, Dst.x, Dst.y );
+ double dy = pix_to_y_point( d, Dst.x, Dst.y );
+ double dw = pix_to_abs_size( d, cDst.x);
+ double dh = pix_to_abs_size( d, cDst.y);
+ int sx = Src.x; //source position within the bitmap, in pixels
+ int sy = Src.y;
+ int sw = cSrc.x; // extract the specified amount of the image
+ int sh = cSrc.y;
+ uint32_t iUsageSrc;
+ iUsageSrc = cUsage;
+ common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh,iUsageSrc);
+
+ break;
+ }
+ case U_WMR_44:
+ case U_WMR_45:
+ case U_WMR_46:
+ case U_WMR_47:
+ {
+ dbg_str << "<!-- U_WMR_44..47 -->\n";
+ break;
+ }
+ case U_WMR_EXTFLOODFILL: dbg_str << "<!-- U_WMR_EXTFLOODFILL -->\n"; break;
+ case U_WMR_49:
+ case U_WMR_4A:
+ case U_WMR_4B:
+ case U_WMR_4C:
+ case U_WMR_4D:
+ case U_WMR_4E:
+ case U_WMR_4F:
+ case U_WMR_50:
+ case U_WMR_51:
+ case U_WMR_52:
+ case U_WMR_53:
+ case U_WMR_54:
+ case U_WMR_55:
+ case U_WMR_56:
+ case U_WMR_57:
+ case U_WMR_58:
+ case U_WMR_59:
+ case U_WMR_5A:
+ case U_WMR_5B:
+ case U_WMR_5C:
+ case U_WMR_5D:
+ case U_WMR_5E:
+ case U_WMR_5F:
+ case U_WMR_60:
+ case U_WMR_61:
+ case U_WMR_62:
+ case U_WMR_63:
+ case U_WMR_64:
+ case U_WMR_65:
+ case U_WMR_66:
+ case U_WMR_67:
+ case U_WMR_68:
+ case U_WMR_69:
+ case U_WMR_6A:
+ case U_WMR_6B:
+ case U_WMR_6C:
+ case U_WMR_6D:
+ case U_WMR_6E:
+ case U_WMR_6F:
+ case U_WMR_70:
+ case U_WMR_71:
+ case U_WMR_72:
+ case U_WMR_73:
+ case U_WMR_74:
+ case U_WMR_75:
+ case U_WMR_76:
+ case U_WMR_77:
+ case U_WMR_78:
+ case U_WMR_79:
+ case U_WMR_7A:
+ case U_WMR_7B:
+ case U_WMR_7C:
+ case U_WMR_7D:
+ case U_WMR_7E:
+ case U_WMR_7F:
+ case U_WMR_80:
+ case U_WMR_81:
+ case U_WMR_82:
+ case U_WMR_83:
+ case U_WMR_84:
+ case U_WMR_85:
+ case U_WMR_86:
+ case U_WMR_87:
+ case U_WMR_88:
+ case U_WMR_89:
+ case U_WMR_8A:
+ case U_WMR_8B:
+ case U_WMR_8C:
+ case U_WMR_8D:
+ case U_WMR_8E:
+ case U_WMR_8F:
+ case U_WMR_90:
+ case U_WMR_91:
+ case U_WMR_92:
+ case U_WMR_93:
+ case U_WMR_94:
+ case U_WMR_95:
+ case U_WMR_96:
+ case U_WMR_97:
+ case U_WMR_98:
+ case U_WMR_99:
+ case U_WMR_9A:
+ case U_WMR_9B:
+ case U_WMR_9C:
+ case U_WMR_9D:
+ case U_WMR_9E:
+ case U_WMR_9F:
+ case U_WMR_A0:
+ case U_WMR_A1:
+ case U_WMR_A2:
+ case U_WMR_A3:
+ case U_WMR_A4:
+ case U_WMR_A5:
+ case U_WMR_A6:
+ case U_WMR_A7:
+ case U_WMR_A8:
+ case U_WMR_A9:
+ case U_WMR_AA:
+ case U_WMR_AB:
+ case U_WMR_AC:
+ case U_WMR_AD:
+ case U_WMR_AE:
+ case U_WMR_AF:
+ case U_WMR_B0:
+ case U_WMR_B1:
+ case U_WMR_B2:
+ case U_WMR_B3:
+ case U_WMR_B4:
+ case U_WMR_B5:
+ case U_WMR_B6:
+ case U_WMR_B7:
+ case U_WMR_B8:
+ case U_WMR_B9:
+ case U_WMR_BA:
+ case U_WMR_BB:
+ case U_WMR_BC:
+ case U_WMR_BD:
+ case U_WMR_BE:
+ case U_WMR_BF:
+ case U_WMR_C0:
+ case U_WMR_C1:
+ case U_WMR_C2:
+ case U_WMR_C3:
+ case U_WMR_C4:
+ case U_WMR_C5:
+ case U_WMR_C6:
+ case U_WMR_C7:
+ case U_WMR_C8:
+ case U_WMR_C9:
+ case U_WMR_CA:
+ case U_WMR_CB:
+ case U_WMR_CC:
+ case U_WMR_CD:
+ case U_WMR_CE:
+ case U_WMR_CF:
+ case U_WMR_D0:
+ case U_WMR_D1:
+ case U_WMR_D2:
+ case U_WMR_D3:
+ case U_WMR_D4:
+ case U_WMR_D5:
+ case U_WMR_D6:
+ case U_WMR_D7:
+ case U_WMR_D8:
+ case U_WMR_D9:
+ case U_WMR_DA:
+ case U_WMR_DB:
+ case U_WMR_DC:
+ case U_WMR_DD:
+ case U_WMR_DE:
+ case U_WMR_DF:
+ case U_WMR_E0:
+ case U_WMR_E1:
+ case U_WMR_E2:
+ case U_WMR_E3:
+ case U_WMR_E4:
+ case U_WMR_E5:
+ case U_WMR_E6:
+ case U_WMR_E7:
+ case U_WMR_E8:
+ case U_WMR_E9:
+ case U_WMR_EA:
+ case U_WMR_EB:
+ case U_WMR_EC:
+ case U_WMR_ED:
+ case U_WMR_EE:
+ case U_WMR_EF:
+ {
+ dbg_str << "<!-- U_WMR_EXTFLOODFILL..EF -->\n";
+ break;
+ }
+ case U_WMR_DELETEOBJECT:
+ {
+ dbg_str << "<!-- U_WMR_DELETEOBJECT -->\n";
+ nSize = U_WMRDELETEOBJECT_get(contents, &utmp16);
+ delete_object(d, utmp16);
+ break;
+ }
+ case U_WMR_F1:
+ case U_WMR_F2:
+ case U_WMR_F3:
+ case U_WMR_F4:
+ case U_WMR_F5:
+ case U_WMR_F6:
+ {
+ dbg_str << "<!-- F1..F6 -->\n";
+ break;
+ }
+ case U_WMR_CREATEPALETTE:
+ {
+ dbg_str << "<!-- U_WMR_CREATEPALETTE -->\n";
+ insert_object(d, U_WMR_CREATEPALETTE, contents);
+ break;
+ }
+ case U_WMR_F8: dbg_str << "<!-- F8 -->\n"; break;
+ case U_WMR_CREATEPATTERNBRUSH:
+ {
+ dbg_str << "<!-- U_WMR_CREATEPATTERNBRUSH -->\n";
+ insert_object(d, U_WMR_CREATEPATTERNBRUSH, contents);
+ break;
+ }
+ case U_WMR_CREATEPENINDIRECT:
+ {
+ dbg_str << "<!-- U_WMR_EXTCREATEPEN -->\n";
+ insert_object(d, U_WMR_CREATEPENINDIRECT, contents);
+ break;
+ }
+ case U_WMR_CREATEFONTINDIRECT:
+ {
+ dbg_str << "<!-- U_WMR_CREATEFONTINDIRECT -->\n";
+ insert_object(d, U_WMR_CREATEFONTINDIRECT, contents);
+ break;
+ }
+ case U_WMR_CREATEBRUSHINDIRECT:
+ {
+ dbg_str << "<!-- U_WMR_CREATEBRUSHINDIRECT -->\n";
+ insert_object(d, U_WMR_CREATEBRUSHINDIRECT, contents);
+ break;
+ }
+ case U_WMR_CREATEBITMAPINDIRECT:
+ {
+ dbg_str << "<!-- U_WMR_CREATEBITMAPINDIRECT -->\n";
+ insert_object(d, U_WMR_CREATEBITMAPINDIRECT, contents);
+ break;
+ }
+ case U_WMR_CREATEBITMAP:
+ {
+ dbg_str << "<!-- U_WMR_CREATEBITMAP -->\n";
+ insert_object(d, U_WMR_CREATEBITMAP, contents);
+ break;
+ }
+ case U_WMR_CREATEREGION:
+ {
+ dbg_str << "<!-- U_WMR_CREATEREGION -->\n";
+ insert_object(d, U_WMR_CREATEREGION, contents);
+ break;
+ }
+ default:
+ dbg_str << "<!-- U_WMR_??? -->\n";
+ break;
+ } //end of switch
+// When testing, uncomment the following to place a comment for each processed WMR record in the SVG
+// *(d->outsvg) += dbg_str.str().c_str();
+ *(d->path) += tmp_path.str().c_str();
+ if(!nSize){ OK=0; std::cout << "nSize == 0, oops!!!" << std::endl; } // There was some problem with this record, it is not safe to continue
+
+ } //end of while
+// When testing, uncomment the following to show the final SVG derived from the WMF
+// std::cout << *(d->outsvg) << std::endl;
+ (void) U_wmr_properties(U_WMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
+
+ return 1;
+}
+
+void Wmf::free_wmf_strings(WMF_STRINGS name){
+ if(name.count){
+ for(int i=0; i< name.count; i++){ free(name.strings[i]); }
+ free(name.strings);
+ }
+}
+
+SPDocument *
+Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
+{
+
+ WMF_CALLBACK_DATA d;
+
+ memset(&d, 0, sizeof(WMF_CALLBACK_DATA));
+
+ for(int i = 0; i < WMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with
+ memset(&(d.dc[i]),0,sizeof(WMF_DEVICE_CONTEXT));
+ }
+ // set default drawing objects, these are active if no object has been selected
+ d.dc[0].active_pen = -1; // -1 when the default is used instead of a selected object
+ d.dc[0].active_brush = -1;
+ d.dc[0].active_font = -1;
+ // Default font, WMF spec says device can pick whatever it wants. WMF files that do not specify a font are unlikely to look very good!
+ d.dc[0].font_name = strdup("Arial");
+ d.dc[0].style.font_size.computed = 16.0;
+ d.dc[0].style.font_weight.value = SP_CSS_FONT_WEIGHT_400;
+ d.dc[0].style.font_style.value = SP_CSS_FONT_STYLE_NORMAL;
+ d.dc[0].style.text_decoration_line.underline = 0;
+ d.dc[0].style.text_decoration_line.line_through = 0;
+ d.dc[0].style.baseline_shift.value = 0;
+ d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black)
+ d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white)
+ d.dc[0].bkMode = U_TRANSPARENT;
+ d.dc[0].dirty = 0;
+ // Default pen, WMF files that do not specify a pen are unlikely to look very good!
+ d.dc[0].style.stroke_dasharray.set = 0;
+ d.dc[0].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE;
+ d.dc[0].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER;
+ d.dc[0].stroke_set = true;
+ d.dc[0].style.stroke_width.value = 1.0; // will be reset to something reasonable once WMF draying size is known
+ d.dc[0].style.stroke.value.color.set( 0, 0, 0 );
+ // Default brush = none, WMF files that do not specify a brush are unlikely to look very good!
+ d.dc[0].fill_set = false;
+
+ if (uri == NULL) {
+ return NULL;
+ }
+
+ d.outsvg = new Glib::ustring("");
+ d.path = new Glib::ustring("");
+ d.outdef = new Glib::ustring("");
+ d.defs = new Glib::ustring("");
+ d.mask = 0;
+ d.drawtype = 0;
+ d.arcdir = U_AD_COUNTERCLOCKWISE;
+ d.dwRop2 = U_R2_COPYPEN;
+ d.dwRop3 = 0;
+ d.E2IdirY = 1.0;
+ d.D2PscaleX = 1.0;
+ d.D2PscaleY = 1.0;
+ d.hatches.size = 0;
+ d.hatches.count = 0;
+ d.hatches.strings = NULL;
+ d.images.size = 0;
+ d.images.count = 0;
+ d.images.strings = NULL;
+
+ // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
+
+ *(d.defs) += "\n";
+ *(d.defs) += " <pattern id=\"WMFhbasepattern\" \n";
+ *(d.defs) += " patternUnits=\"userSpaceOnUse\"\n";
+ *(d.defs) += " width=\"6\" \n";
+ *(d.defs) += " height=\"6\" \n";
+ *(d.defs) += " x=\"0\" \n";
+ *(d.defs) += " y=\"0\"> \n";
+ *(d.defs) += " </pattern> \n";
+
+
+ size_t length;
+ char *contents;
+ if(wmf_readdata(uri, &contents, &length))return(NULL);
+
+ // set up the text reassembly system
+ if(!(d.tri = trinfo_init(NULL)))return(NULL);
+ (void) trinfo_load_ft_opts(d.tri, 1,
+ FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP,
+ FT_KERNING_UNSCALED);
+
+ (void) myMetaFileProc(contents,length, &d);
+ free(contents);
+
+// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
+
+ SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE);
+
+ delete d.outsvg;
+ delete d.path;
+ delete d.outdef;
+ delete d.defs;
+ free_wmf_strings(d.hatches);
+ free_wmf_strings(d.images);
+
+ if (d.wmf_obj) {
+ int i;
+ for (i=0; i<d.n_obj; i++)
+ delete_object(&d, i);
+ delete[] d.wmf_obj;
+ }
+
+ d.dc[0].style.stroke_dasharray.values.clear();
+
+ for(int i=0; i<=d.level;i++){
+ if(d.dc[i].font_name)free(d.dc[i].font_name);
+ }
+
+ d.tri = trinfo_release_except_FC(d.tri);
+
+ // Set viewBox if it doesn't exist
+ if (doc && !doc->getRoot()->viewBox_set) {
+ bool saved = Inkscape::DocumentUndo::getUndoSensitive(doc);
+ Inkscape::DocumentUndo::setUndoSensitive(doc, false);
+
+ doc->ensureUpToDate();
+
+ // Set document unit
+ Inkscape::XML::Node *repr = sp_document_namedview(doc, 0)->getRepr();
+ Inkscape::SVGOStringStream os;
+ Inkscape::Util::Unit const* doc_unit = doc->getWidth().unit;
+ os << doc_unit->abbr;
+ repr->setAttribute("inkscape:document-units", os.str().c_str());
+
+ // Set viewBox
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc_unit), doc->getHeight().value(doc_unit)));
+ doc->ensureUpToDate();
+
+ // Scale and translate objects
+ double scale = Inkscape::Util::Quantity::convert(1, "px", doc_unit);
+ ShapeEditor::blockSetItem(true);
+ double dh;
+ if(SP_ACTIVE_DOCUMENT){ // for file menu open or import, or paste from clipboard
+ dh = SP_ACTIVE_DOCUMENT->getHeight().value("px");
+ }
+ else { // for open via --file on command line
+ dh = doc->getHeight().value("px");
+ }
+ doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh));
+ ShapeEditor::blockSetItem(false);
+
+ Inkscape::DocumentUndo::setUndoSensitive(doc, saved);
+ }
+
+ return doc;
+}
+
+
+void
+Wmf::init (void)
+{
+ /* WMF in */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("WMF Input") "</name>\n"
+ "<id>org.inkscape.input.wmf</id>\n"
+ "<input>\n"
+ "<extension>.wmf</extension>\n"
+ "<mimetype>image/x-wmf</mimetype>\n"
+ "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"
+ "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"
+ "<output_extension>org.inkscape.output.wmf</output_extension>\n"
+ "</input>\n"
+ "</inkscape-extension>", new Wmf());
+
+ /* WMF out */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>" N_("WMF Output") "</name>\n"
+ "<id>org.inkscape.output.wmf</id>\n"
+ "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"TnrToSymbol\" gui-text=\"" N_("Map Unicode to Symbol font") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"TnrToWingdings\" gui-text=\"" N_("Map Unicode to Wingdings") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"TnrToZapfDingbats\" gui-text=\"" N_("Map Unicode to Zapf Dingbats") "\" type=\"boolean\">true</param>\n"
+ "<param name=\"UsePUA\" gui-text=\"" N_("Use MS Unicode PUA (0xF020-0xF0FF) for converted characters") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTCharPos\" gui-text=\"" N_("Compensate for PPT font bug") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTDashLine\" gui-text=\"" N_("Convert dashed/dotted lines to single lines") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTGrad2Polys\" gui-text=\"" N_("Convert gradients to colored polygon series") "\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTPatternAsHatch\" gui-text=\"" N_("Map all fill patterns to standard WMF hatches") "\" type=\"boolean\">false</param>\n"
+ "<output>\n"
+ "<extension>.wmf</extension>\n"
+ "<mimetype>image/x-wmf</mimetype>\n"
+ "<filetypename>" N_("Windows Metafile (*.wmf)") "</filetypename>\n"
+ "<filetypetooltip>" N_("Windows Metafile") "</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>", new Wmf());
+
+ return;
+}
+
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h
new file mode 100644
index 000000000..3d23ca749
--- /dev/null
+++ b/src/extension/internal/wmf-inout.h
@@ -0,0 +1,180 @@
+/** @file
+ * @brief Windows Metafile Input/Output
+ */
+/* Authors:
+ * Ulf Erikson <ulferikson@users.sf.net>
+ *
+ * Copyright (C) 2006-2008 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+#ifndef SEEN_EXTENSION_INTERNAL_WMF_H
+#define SEEN_EXTENSION_INTERNAL_WMF_H
+
+#include <libuemf/uwmf.h>
+#include "extension/internal/metafile-inout.h" // picks up PNG
+#include "extension/implementation/implementation.h"
+#include "style.h"
+#include "text_reassemble.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+#define DIRTY_NONE 0x00
+#define DIRTY_TEXT 0x01
+#define DIRTY_FILL 0x02
+#define DIRTY_STROKE 0x04 // not used currently
+
+typedef struct {
+ int type;
+ int level;
+ char *record;
+} WMF_OBJECT, *PWMF_OBJECT;
+
+typedef struct {
+ int size; // number of slots allocated in strings
+ int count; // number of slots used in strings
+ char **strings; // place to store strings
+} WMF_STRINGS, *PWMF_STRINGS;
+
+typedef struct wmf_device_context {
+ struct SPStyle style;
+ char *font_name;
+ bool stroke_set;
+ int stroke_mode; // enumeration from drawmode, not used if fill_set is not True
+ int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
+ int stroke_recidx;// record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change
+ bool fill_set;
+ int fill_mode; // enumeration from drawmode, not used if fill_set is not True
+ int fill_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
+ int fill_recidx; // record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change
+ int dirty; // holds the dirty bits for text, stroke, fill
+ int active_pen; // used when the active object is deleted to set the default values, -1 is none active
+ int active_brush; // ditto
+ int active_font; // ditto. also used to hold object number in case font needs to be remade due to textcolor change.
+ U_POINT16 sizeWnd;
+ U_POINT16 sizeView;
+ U_POINT16 winorg;
+ U_POINT16 vieworg;
+ double ScaleInX, ScaleInY;
+ double ScaleOutX, ScaleOutY;
+ uint16_t bkMode;
+ U_COLORREF bkColor;
+ U_COLORREF textColor;
+ uint16_t textAlign;
+ U_POINT16 cur;
+} WMF_DEVICE_CONTEXT, *PWMF_DEVICE_CONTEXT;
+
+#define WMF_MAX_DC 128
+
+
+// like this causes a mysterious crash on the return from Wmf::open
+//typedef struct emf_callback_data {
+// this fixes it, so some confusion between this struct and the one in emf-inout???
+//typedef struct wmf_callback_data {
+// as does this
+typedef struct {
+ Glib::ustring *outsvg;
+ Glib::ustring *path;
+ Glib::ustring *outdef;
+ Glib::ustring *defs;
+
+ WMF_DEVICE_CONTEXT dc[WMF_MAX_DC+1]; // FIXME: This should be dynamic..
+ int level;
+
+ double E2IdirY; // WMF Y direction relative to Inkscape Y direction. Will be negative for MM_LOMETRIC etc.
+ double D2PscaleX,D2PscaleY; // WMF device to Inkscape Page scale.
+ float PixelsInX, PixelsInY; // size of the drawing, in WMF device pixels
+ float PixelsOutX, PixelsOutY; // size of the drawing, in Inkscape pixels
+ double ulCornerInX,ulCornerInY; // Upper left corner, from header rclBounds, in logical units
+ double ulCornerOutX,ulCornerOutY; // Upper left corner, in Inkscape pixels
+ uint32_t mask; // Draw properties
+ int arcdir; // U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2
+
+ uint32_t dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested)
+ uint32_t dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested)
+
+ unsigned int id;
+ unsigned int drawtype; // one of 0 or U_WMR_FILLPATH, U_WMR_STROKEPATH, U_WMR_STROKEANDFILLPATH
+ // both of these end up in <defs> under the names shown here. These structures allow duplicates to be avoided.
+ WMF_STRINGS hatches; // hold pattern names, all like WMFhatch#_$$$$$$ where # is the WMF hatch code and $$$$$$ is the color
+ WMF_STRINGS images; // hold images, all like Image#, where # is the slot the image lives.
+ TR_INFO *tri; // Text Reassembly data structure
+
+
+ int n_obj;
+ int low_water; // first object slot which _might_ be unoccupied. Everything below is filled.
+ PWMF_OBJECT wmf_obj;
+} WMF_CALLBACK_DATA, *PWMF_CALLBACK_DATA;
+
+class Wmf : public Metafile
+{
+
+public:
+ Wmf(); // Empty constructor
+
+ virtual ~Wmf();//Destructor
+
+ bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now)
+
+ void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename
+ SPDocument *doc,
+ gchar const *filename);
+
+ virtual SPDocument *open( Inkscape::Extension::Input *mod,
+ const gchar *uri );
+
+ static void init(void);//Initialize the class
+
+private:
+protected:
+ static void print_document_to_file(SPDocument *doc, const gchar *filename);
+ static double current_scale(PWMF_CALLBACK_DATA d);
+ static std::string current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset);
+ static double current_rotation(PWMF_CALLBACK_DATA d);
+ static void enlarge_hatches(PWMF_CALLBACK_DATA d);
+ static int in_hatches(PWMF_CALLBACK_DATA d, char *test);
+ static uint32_t add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor);
+ static void enlarge_images(PWMF_CALLBACK_DATA d);
+ static int in_images(PWMF_CALLBACK_DATA d, char *test);
+ static uint32_t add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsage);
+ static uint32_t add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px);
+ static void output_style(PWMF_CALLBACK_DATA d);
+ static double _pix_x_to_point(PWMF_CALLBACK_DATA d, double px);
+ static double _pix_y_to_point(PWMF_CALLBACK_DATA d, double py);
+ static double pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double py);
+ static double pix_to_y_point(PWMF_CALLBACK_DATA d, double px, double py);
+ static double pix_to_abs_size(PWMF_CALLBACK_DATA d, double px);
+ static std::string pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y);
+ static void select_brush(PWMF_CALLBACK_DATA d, int index);
+ static void select_font(PWMF_CALLBACK_DATA d, int index);
+ static void select_pen(PWMF_CALLBACK_DATA d, int index);
+ static int insertable_object(PWMF_CALLBACK_DATA d);
+ static void delete_object(PWMF_CALLBACK_DATA d, int index);
+ static int insert_object(PWMF_CALLBACK_DATA d, int type, const char *record);
+ static uint32_t *unknown_chars(size_t count);
+ static void common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib,
+ double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage);
+ static void common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px,
+ double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh);
+ static int myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK_DATA d);
+ static void free_wmf_strings(WMF_STRINGS name);
+
+};
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+
+#endif /* EXTENSION_INTERNAL_WMF_H */
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp
new file mode 100644
index 000000000..5a552ad83
--- /dev/null
+++ b/src/extension/internal/wmf-print.cpp
@@ -0,0 +1,1578 @@
+/** @file
+ * @brief Windows Metafile printing
+ */
+/* Authors:
+ * Ulf Erikson <ulferikson@users.sf.net>
+ * Jon A. Cruz <jon@joncruz.org>
+ * Abhishek Sharma
+ * David Mathog
+ *
+ * Copyright (C) 2006-2009 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+/*
+ * References:
+ * - How to Create & Play Enhanced Metafiles in Win32
+ * http://support.microsoft.com/kb/q145999/
+ * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
+ * http://support.microsoft.com/kb/q66949/
+ * - Metafile Functions
+ * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
+ * - Metafile Structures
+ * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+
+#include "2geom/sbasis-to-bezier.h"
+#include "2geom/svg-elliptical-arc.h"
+
+#include "2geom/path.h"
+#include "2geom/pathvector.h"
+#include "2geom/rect.h"
+#include "2geom/bezier-curve.h"
+#include "2geom/hvlinesegment.h"
+#include "helper/geom.h"
+#include "helper/geom-curves.h"
+#include "sp-item.h"
+
+#include "style.h"
+#include "inkscape-version.h"
+#include "sp-root.h"
+
+#include "util/units.h"
+
+#include "extension/system.h"
+#include "extension/print.h"
+#include "document.h"
+#include "path-prefix.h"
+#include "sp-pattern.h"
+#include "sp-image.h"
+#include "sp-gradient.h"
+#include "sp-radial-gradient.h"
+#include "sp-linear-gradient.h"
+#include "display/cairo-utils.h"
+
+#include "splivarot.h" // pieces for union on shapes
+#include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path
+#include "display/canvas-bpath.h" // for SPWindRule
+
+#include "wmf-print.h"
+
+#include <string.h>
+#include <libuemf/symbol_convert.h>
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+#define PXPERMETER 2835
+#define MAXDISP 2.0 // This should be set in the output dialog. This is ok for experimenting, no more than 2 pixel deviation. Not actually used at present
+
+
+/* globals */
+static double PX2WORLD; // value set in begin()
+static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch;
+static WMFTRACK *wt = NULL;
+static WMFHANDLES *wht = NULL;
+
+void PrintWmf::smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *rtl, int *ndx, float scale)
+{
+ float fdx;
+ int i;
+ int16_t *ladx;
+ const char *cptr = &string[strlen(string) + 1]; // this works because of the first fake terminator
+
+ *adx = NULL;
+ *ky = 0.0; // set a default value
+ sscanf(cptr, "%7d", ndx);
+ if (!*ndx) {
+ return; // this could happen with an empty string
+ }
+ cptr += 7;
+ ladx = (int16_t *) malloc(*ndx * sizeof(int16_t));
+ if (!ladx) {
+ g_error("Out of memory");
+ }
+ *adx = ladx;
+ for (i = 0; i < *ndx; i++, cptr += 7, ladx++) {
+ sscanf(cptr, "%7f", &fdx);
+ *ladx = (int16_t) round(fdx * scale);
+ }
+ cptr++; // skip 2nd fake terminator
+ sscanf(cptr, "%7f", &fdx);
+ *ky = fdx;
+ cptr += 7; // advance over ky and its space
+ sscanf(cptr, "%07d", rtl);
+}
+
+PrintWmf::PrintWmf()
+{
+ // all of the class variables are initialized elsewhere, many in PrintWmf::Begin,
+}
+
+
+unsigned int PrintWmf::setup(Inkscape::Extension::Print * /*mod*/)
+{
+ return TRUE;
+}
+
+
+unsigned int PrintWmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
+{
+ char *rec;
+ gchar const *utf8_fn = mod->get_param_string("destination");
+
+ // Typically PX2WORLD is 1200/90, using inkscape's default dpi
+ PX2WORLD = 1200.0 / Inkscape::Util::Quantity::convert(1.0, "in", "px");
+ FixPPTCharPos = mod->get_param_bool("FixPPTCharPos");
+ FixPPTDashLine = mod->get_param_bool("FixPPTDashLine");
+ FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys");
+ FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch");
+
+ (void) wmf_start(utf8_fn, 1000000, 250000, &wt); // Initialize the wt structure
+ (void) wmf_htable_create(128, 128, &wht); // Initialize the wht structure
+
+ // WMF header the only things that can be set are the page size in inches (w,h) and the dpi
+ // width and height in px
+ _width = doc->getWidth().value("px");
+ _height = doc->getHeight().value("px");
+
+ // initialize a few global variables
+ hbrush = hpen = 0;
+ htextalignment = U_TA_BASELINE | U_TA_LEFT;
+ use_stroke = use_fill = simple_shape = usebk = false;
+
+ Inkscape::XML::Node *nv = sp_repr_lookup_name(doc->rroot, "sodipodi:namedview");
+ if (nv) {
+ const char *p1 = nv->attribute("pagecolor");
+ char *p2;
+ uint32_t lc = strtoul(&p1[1], &p2, 16); // it looks like "#ABC123"
+ if (*p2) {
+ lc = 0;
+ }
+ gv.bgc = _gethexcolor(lc);
+ gv.rgb[0] = (float) U_RGBAGetR(gv.bgc) / 255.0;
+ gv.rgb[1] = (float) U_RGBAGetG(gv.bgc) / 255.0;
+ gv.rgb[2] = (float) U_RGBAGetB(gv.bgc) / 255.0;
+ }
+
+ bool pageBoundingBox;
+ pageBoundingBox = mod->get_param_bool("pageBoundingBox");
+
+ Geom::Rect d;
+ if (pageBoundingBox) {
+ d = Geom::Rect::from_xywh(0, 0, _width, _height);
+ } else {
+ SPItem *doc_item = doc->getRoot();
+ Geom::OptRect bbox = doc_item->desktopVisualBounds();
+ if (bbox) {
+ d = *bbox;
+ }
+ }
+
+ d *= Geom::Scale(Inkscape::Util::Quantity::convert(1, "px", "in")); // 90 dpi inside inkscape, wmf file will be 1200 dpi
+
+ /* -1/1200 in next two lines so that WMF read in will write out again at exactly the same size */
+ float dwInchesX = d.width() - 1.0 / 1200.0;
+ float dwInchesY = d.height() - 1.0 / 1200.0;
+ int dwPxX = round(dwInchesX * 1200.0);
+ int dwPxY = round(dwInchesY * 1200.0);
+#if 0
+ float dwInchesX = d.width();
+ float dwInchesY = d.height();
+ int dwPxX = round(d.width() * 1200.0);
+ int dwPxY = round(d.height() * 1200.0);
+#endif
+
+ U_PAIRF *ps = U_PAIRF_set(dwInchesX, dwInchesY);
+ rec = U_WMRHEADER_set(ps, 1200); // Example: drawing is A4 horizontal, 1200 dpi
+ if (!rec) {
+ g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE");
+ }
+ (void) wmf_header_append((U_METARECORD *)rec, wt, 1);
+ free(ps);
+
+ rec = U_WMRSETWINDOWEXT_set(point16_set(dwPxX, dwPxY));
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWEXT");
+ }
+
+ rec = U_WMRSETWINDOWORG_set(point16_set(0, 0));
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWORG");
+ }
+
+ rec = U_WMRSETMAPMODE_set(U_MM_ANISOTROPIC);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE");
+ }
+
+ /* set some parameters, else the program that reads the WMF may default to other values */
+
+ rec = U_WMRSETBKMODE_set(U_TRANSPARENT);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at U_WMRSETBKMODE");
+ }
+
+ hpolyfillmode = U_WINDING;
+ rec = U_WMRSETPOLYFILLMODE_set(U_WINDING);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at U_WMRSETPOLYFILLMODE");
+ }
+
+ // Text alignment: (only changed if RTL text is encountered )
+ // - (x,y) coordinates received by this filter are those of the point where the text
+ // actually starts, and already takes into account the text object's alignment;
+ // - for this reason, the WMF text alignment must always be TA_BASELINE|TA_LEFT.
+ rec = U_WMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTALIGN_set");
+ }
+
+ htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0;
+ rec = U_WMRSETTEXTCOLOR_set(U_RGB(0, 0, 0));
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTCOLOR_set");
+ }
+
+ rec = U_WMRSETROP2_set(U_R2_COPYPEN);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at U_WMRSETROP2");
+ }
+
+ hmiterlimit = 5;
+ rec = wmiterlimit_set(5);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at wmiterlimit_set");
+ }
+
+
+ // create a pen as object 0. We never use it (except by mistake). Its purpose it to make all of the other object indices >=1
+ U_PEN up = U_PEN_set(U_PS_SOLID, 1, colorref_set(0, 0, 0));
+ uint32_t Pen;
+ rec = wcreatepenindirect_set(&Pen, wht, up);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set");
+ }
+
+ // create a null pen. If no specific pen is set, this is used
+ up = U_PEN_set(U_PS_NULL, 1, colorref_set(0, 0, 0));
+ rec = wcreatepenindirect_set(&hpen_null, wht, up);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set");
+ }
+ destroy_pen(); // make this pen active
+
+ // create a null brush. If no specific brush is set, this is used
+ U_WLOGBRUSH lb = U_WLOGBRUSH_set(U_BS_NULL, U_RGB(0, 0, 0), U_HS_HORIZONTAL);
+ rec = wcreatebrushindirect_set(&hbrush_null, wht, lb);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::begin at wcreatebrushindirect_set");
+ }
+ destroy_brush(); // make this brush active
+
+ return 0;
+}
+
+
+unsigned int PrintWmf::finish(Inkscape::Extension::Print * /*mod*/)
+{
+ char *rec;
+ if (!wt) {
+ return 0;
+ }
+
+ // get rid of null brush
+ rec = wdeleteobject_set(&hbrush_null, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null brush");
+ }
+
+ // get rid of null pen
+ rec = wdeleteobject_set(&hpen_null, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null pen");
+ }
+
+ // get rid of object 0, which was a pen that was used to shift the other object indices to >=1.
+ hpen = 0;
+ rec = wdeleteobject_set(&hpen, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set filler object");
+ }
+
+ rec = U_WMREOF_set(); // generate the EOF record
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::finish");
+ }
+ (void) wmf_finish(wt); // Finalize and write out the WMF
+ wmf_free(&wt); // clean up
+ wmf_htable_free(&wht); // clean up
+
+ return 0;
+}
+
+
+unsigned int PrintWmf::comment(Inkscape::Extension::Print * /*module*/, const char * /*comment*/)
+{
+ if (!wt) {
+ return 0;
+ }
+
+ // earlier versions had flush of fill here, but it never executed and was removed
+
+ return 0;
+}
+
+
+// fcolor is defined when gradients are being expanded, it is the color of one stripe or ring.
+int PrintWmf::create_brush(SPStyle const *style, U_COLORREF *fcolor)
+{
+ float rgb[3];
+ char *rec;
+ U_WLOGBRUSH lb;
+ uint32_t brush, fmode;
+ MFDrawMode fill_mode;
+ Inkscape::Pixbuf *pixbuf;
+ uint32_t brushStyle;
+ int hatchType;
+ U_COLORREF hatchColor;
+ U_COLORREF bkColor;
+ uint32_t width = 0; // quiets a harmless compiler warning, initialization not otherwise required.
+ uint32_t height = 0;
+
+ if (!wt) {
+ return 0;
+ }
+
+ // set a default fill in case we can't figure out a better way to do it
+ fmode = U_ALTERNATE;
+ fill_mode = DRAW_PAINT;
+ brushStyle = U_BS_SOLID;
+ hatchType = U_HS_SOLIDCLR;
+ bkColor = U_RGB(0, 0, 0);
+ if (fcolor) {
+ hatchColor = *fcolor;
+ } else {
+ hatchColor = U_RGB(0, 0, 0);
+ }
+
+ if (!fcolor && style) {
+ if (style->fill.isColor()) {
+ fill_mode = DRAW_PAINT;
+ float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
+ if (opacity <= 0.0) {
+ opacity = 0.0; // basically the same as no fill
+ }
+
+ sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
+ hatchColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]);
+
+ fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE);
+ } else if (SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))) { // must be paint-server
+ SPPaintServer *paintserver = style->fill.value.href->getObject();
+ SPPattern *pat = SP_PATTERN(paintserver);
+ double dwidth = pattern_width(pat);
+ double dheight = pattern_height(pat);
+ width = dwidth;
+ height = dheight;
+ brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor);
+ if (pixbuf) {
+ fill_mode = DRAW_IMAGE;
+ } else { // pattern
+ fill_mode = DRAW_PATTERN;
+ if (hatchType == -1) { // Not a standard hatch, so force it to something
+ hatchType = U_HS_CROSS;
+ hatchColor = U_RGB(0xFF, 0xC3, 0xC3);
+ }
+ }
+ if (FixPPTPatternAsHatch) {
+ if (hatchType == -1) { // image or unclassified
+ fill_mode = DRAW_PATTERN;
+ hatchType = U_HS_DIAGCROSS;
+ hatchColor = U_RGB(0xFF, 0xC3, 0xC3);
+ }
+ }
+ brushStyle = U_BS_HATCHED;
+ } else if (SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))) { // must be a gradient
+ // currently we do not do anything with gradients, the code below just sets the color to the average of the stops
+ SPPaintServer *paintserver = style->fill.value.href->getObject();
+ SPLinearGradient *lg = NULL;
+ SPRadialGradient *rg = NULL;
+
+ if (SP_IS_LINEARGRADIENT(paintserver)) {
+ lg = SP_LINEARGRADIENT(paintserver);
+ SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
+ fill_mode = DRAW_LINEAR_GRADIENT;
+ } else if (SP_IS_RADIALGRADIENT(paintserver)) {
+ rg = SP_RADIALGRADIENT(paintserver);
+ SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
+ fill_mode = DRAW_RADIAL_GRADIENT;
+ } else {
+ // default fill
+ }
+
+ if (rg) {
+ if (FixPPTGrad2Polys) {
+ return hold_gradient(rg, fill_mode);
+ } else {
+ hatchColor = avg_stop_color(rg);
+ }
+ } else if (lg) {
+ if (FixPPTGrad2Polys) {
+ return hold_gradient(lg, fill_mode);
+ } else {
+ hatchColor = avg_stop_color(lg);
+ }
+ }
+ }
+ } else { // if (!style)
+ // default fill
+ }
+
+ switch (fill_mode) {
+ case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices
+ case DRAW_RADIAL_GRADIENT: // ditto
+ case DRAW_PAINT:
+ case DRAW_PATTERN:
+ // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output.
+ if (usebk) {
+ rec = U_WMRSETBKCOLOR_set(bkColor);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKCOLOR_set");
+ }
+ rec = U_WMRSETBKMODE_set(U_OPAQUE);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKMODE_set");
+ }
+ }
+ lb = U_WLOGBRUSH_set(brushStyle, hatchColor, hatchType);
+ rec = wcreatebrushindirect_set(&brush, wht, lb);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::create_brush at createbrushindirect_set");
+ }
+ break;
+ case DRAW_IMAGE:
+ char *px;
+ char *rgba_px;
+ uint32_t cbPx;
+ uint32_t colortype;
+ U_RGBQUAD *ct;
+ int numCt;
+ U_BITMAPINFOHEADER Bmih;
+ U_BITMAPINFO *Bmi;
+ rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!!
+ colortype = U_BCBM_COLOR32;
+ (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1);
+ // Not sure why the next swap is needed because the preceding does it, and the code is identical
+ // to that in stretchdibits_set, which does not need this.
+ swapRBinRGBA(px, width * height);
+ Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
+ Bmi = bitmapinfo_set(Bmih, ct);
+ rec = wcreatedibpatternbrush_srcdib_set(&brush, wht, U_DIB_RGB_COLORS, Bmi, cbPx, px);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::create_brush at createdibpatternbrushpt_set");
+ }
+ free(px);
+ free(Bmi); // ct will be NULL because of colortype
+ break;
+ }
+
+ hbrush = brush; // need this later for destroy_brush
+ rec = wselectobject_set(brush, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::create_brush at wselectobject_set");
+ }
+
+ if (fmode != hpolyfillmode) {
+ hpolyfillmode = fmode;
+ rec = U_WMRSETPOLYFILLMODE_set(fmode);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETPOLYFILLMODE_set");
+ }
+ }
+
+ return 0;
+}
+
+
+void PrintWmf::destroy_brush()
+{
+ char *rec;
+ // WMF lets any object be deleted whenever, and the chips fall where they may...
+ if (hbrush) {
+ rec = wdeleteobject_set(&hbrush, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::destroy_brush");
+ }
+ hbrush = 0;
+ }
+
+ // (re)select the null brush
+
+ rec = wselectobject_set(hbrush_null, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::destroy_brush");
+ }
+}
+
+
+int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
+{
+ char *rec = NULL;
+ uint32_t pen;
+ uint32_t penstyle;
+ U_COLORREF penColor;
+ U_PEN up;
+ int modstyle;
+
+ if (!wt) {
+ return 0;
+ }
+
+ // set a default stroke in case we can't figure out a better way to do it
+ penstyle = U_PS_SOLID;
+ modstyle = 0;
+ penColor = U_RGB(0, 0, 0);
+ uint32_t linewidth = 1;
+
+ if (style) { // override some or all of the preceding
+ float rgb[3];
+
+ // WMF does not support hatched, bitmap, or gradient pens, just set the color.
+ sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
+ penColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]);
+
+ using Geom::X;
+ using Geom::Y;
+
+ Geom::Point zero(0, 0);
+ Geom::Point one(1, 1);
+ Geom::Point p0(zero * transform);
+ Geom::Point p1(one * transform);
+ Geom::Point p(p1 - p0);
+
+ double scale = sqrt((p[X] * p[X]) + (p[Y] * p[Y])) / sqrt(2);
+
+ if (!style->stroke_width.computed) {
+ return 0; //if width is 0 do not (reset) the pen, it should already be NULL_PEN
+ }
+ linewidth = MAX(1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD));
+
+ // most WMF readers will ignore linecap and linejoin, but set them anyway. Inkscape itself can read them back in.
+
+ if (style->stroke_linecap.computed == 0) {
+ modstyle |= U_PS_ENDCAP_FLAT;
+ } else if (style->stroke_linecap.computed == 1) {
+ modstyle |= U_PS_ENDCAP_ROUND;
+ } else {
+ modstyle |= U_PS_ENDCAP_SQUARE;
+ }
+
+ if (style->stroke_linejoin.computed == 0) {
+ float miterlimit = style->stroke_miterlimit.value; // This is a ratio.
+ if (miterlimit < 1) {
+ miterlimit = 1;
+ }
+
+ // most WMF readers will ignore miterlimit, but set it anyway. Inkscape itself can read it back in
+ if ((uint32_t)miterlimit != hmiterlimit) {
+ hmiterlimit = (uint32_t)miterlimit;
+ rec = wmiterlimit_set((uint32_t) miterlimit);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::create_pen at wmiterlimit_set");
+ }
+ }
+ modstyle |= U_PS_JOIN_MITER;
+ } else if (style->stroke_linejoin.computed == 1) {
+ modstyle |= U_PS_JOIN_ROUND;
+ } else {
+ modstyle |= U_PS_JOIN_BEVEL;
+ }
+
+ if (!style->stroke_dasharray.values.empty()) {
+ if (!FixPPTDashLine) { // if this is set code elsewhere will break dots/dashes into many smaller lines.
+ penstyle = U_PS_DASH;// userstyle not supported apparently, for now map all Inkscape dot/dash to just dash
+ }
+ }
+
+ }
+
+ up = U_PEN_set(penstyle | modstyle, linewidth, penColor);
+ rec = wcreatepenindirect_set(&pen, wht, up);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::create_pen at wcreatepenindirect_set");
+ }
+
+ rec = wselectobject_set(pen, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::create_pen at wselectobject_set");
+ }
+ hpen = pen; // need this later for destroy_pen
+
+ return 0;
+}
+
+// delete the defined pen object
+void PrintWmf::destroy_pen()
+{
+ char *rec = NULL;
+ // WMF lets any object be deleted whenever, and the chips fall where they may...
+ if (hpen) {
+ rec = wdeleteobject_set(&hpen, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::destroy_pen");
+ }
+ hpen = 0;
+ }
+
+ // (re)select the null pen
+
+ rec = wselectobject_set(hpen_null, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::destroy_pen");
+ }
+}
+
+
+unsigned int PrintWmf::fill(
+ Inkscape::Extension::Print * /*mod*/,
+ Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style,
+ Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
+{
+ using Geom::X;
+ using Geom::Y;
+
+ Geom::Affine tf = m_tr_stack.top();
+
+ use_fill = true;
+ use_stroke = false;
+
+ fill_transform = tf;
+
+ if (create_brush(style, NULL)) {
+ /*
+ Handle gradients. Uses modified livarot as 2geom boolops is currently broken.
+ Can handle gradients with multiple stops.
+
+ The overlap is needed to avoid antialiasing artifacts when edges are not strictly aligned on pixel boundaries.
+ There is an inevitable loss of accuracy saving through an WMF file because of the integer coordinate system.
+ Keep the overlap quite large so that loss of accuracy does not remove an overlap.
+ */
+ destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below
+ Geom::Path cutter;
+ float rgb[3];
+ U_COLORREF wc, c1, c2;
+ FillRule frb = SPWR_to_LVFR((SPWindRule) style->fill_rule.computed);
+ double doff, doff_base, doff_range;
+ double divisions = 128.0;
+ int nstops;
+ int istop = 1;
+ float opa; // opacity at stop
+
+ SPRadialGradient *tg = (SPRadialGradient *)(gv.grad); // linear/radial are the same here
+ nstops = tg->vector.stops.size();
+ sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb);
+ opa = tg->vector.stops[0].opacity;
+ c1 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+ sp_color_get_rgb_floatv(&tg->vector.stops[nstops - 1].color, rgb);
+ opa = tg->vector.stops[nstops - 1].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+
+ doff = 0.0;
+ doff_base = 0.0;
+ doff_range = tg->vector.stops[1].offset; // next or last stop
+
+ if (gv.mode == DRAW_RADIAL_GRADIENT) {
+ Geom::Point xv = gv.p2 - gv.p1; // X' vector
+ Geom::Point yv = gv.p3 - gv.p1; // Y' vector
+ Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector
+ double rx = hypot(xv[X], xv[Y]);
+ double ry = hypot(yv[X], yv[Y]);
+ double range = fmax(rx, ry); // length along the gradient
+ double step = range / divisions; // adequate approximation for gradient
+ double overlap = step / 4.0; // overlap slices slightly
+ double start;
+ double stop;
+ Geom::PathVector pathvc, pathvr;
+
+ /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity".
+ Do this first so that outer colored ring will overlay it.
+ */
+ pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx * (1.0 - overlap / range), ry * (1.0 - overlap / range), asin(xuv[Y]));
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb);
+ wc = weight_opacity(c2);
+ (void) create_brush(style, &wc);
+ print_pathv(pathvr, fill_transform);
+
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+
+ for (start = 0.0; start < range; start += step, doff += 1. / divisions) {
+ stop = start + step + overlap;
+ if (stop > range) {
+ stop = range;
+ }
+ wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base));
+ (void) create_brush(style, &wc);
+
+ pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx * start / range, ry * start / range, rx * stop / range, ry * stop / range, asin(xuv[Y]));
+
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform); // show the intersection
+
+ if (doff >= doff_range - doff_base) {
+ istop++;
+ if (istop >= nstops) {
+ continue; // could happen on a rounding error
+ }
+ doff_base = doff_range;
+ doff_range = tg->vector.stops[istop].offset; // next or last stop
+ c1 = c2;
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+ }
+ }
+ } else if (gv.mode == DRAW_LINEAR_GRADIENT) {
+ Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector
+ Geom::Point puv = uv.cw(); // perp. to unit vector
+ double range = Geom::distance(gv.p1, gv.p2); // length along the gradient
+ double step = range / divisions; // adequate approximation for gradient
+ double overlap = step / 4.0; // overlap slices slightly
+ double start;
+ double stop;
+ Geom::PathVector pathvc, pathvr;
+
+ /* before lower end of gradient, overlap first slice position */
+ wc = weight_opacity(c1);
+ (void) create_brush(style, &wc);
+ pathvc = rect_cutter(gv.p1, uv * (overlap), uv * (-50000.0), puv * 50000.0);
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform);
+
+ /* after high end of gradient, overlap last slice position */
+ wc = weight_opacity(c2);
+ (void) create_brush(style, &wc);
+ pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0);
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform);
+
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+
+ for (start = 0.0; start < range; start += step, doff += 1. / divisions) {
+ stop = start + step + overlap;
+ if (stop > range) {
+ stop = range;
+ }
+ pathvc = rect_cutter(gv.p1, uv * start, uv * stop, puv * 50000.0);
+
+ wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base));
+ (void) create_brush(style, &wc);
+ Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform); // show the intersection
+
+ if (doff >= doff_range - doff_base) {
+ istop++;
+ if (istop >= nstops) {
+ continue; // could happen on a rounding error
+ }
+ doff_base = doff_range;
+ doff_range = tg->vector.stops[istop].offset; // next or last stop
+ c1 = c2;
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+ }
+ }
+ } else {
+ g_error("Fatal programming error in PrintWmf::fill, invalid gradient type detected");
+ }
+ use_fill = false; // gradients handled, be sure stroke does not use stroke and fill
+ } else {
+ /*
+ Inkscape was not calling create_pen for objects with no border.
+ This was because it never called stroke() (next method).
+ PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can
+ become a visible border.
+ To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill.
+ */
+ if (style->stroke.noneSet || style->stroke_width.computed == 0.0) {
+ destroy_pen(); //this sets the NULL_PEN
+ }
+
+ /* postpone fill in case stroke also required AND all stroke paths closed
+ Dashes converted to line segments will "open" a closed path.
+ */
+ bool all_closed = true;
+ for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) {
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
+ if (pit->end_default() != pit->end_closed()) {
+ all_closed = false;
+ }
+ }
+ }
+ if (
+ (style->stroke.isNone() || style->stroke.noneSet || style->stroke_width.computed == 0.0) ||
+ (!style->stroke_dasharray.values.empty() && FixPPTDashLine) ||
+ !all_closed
+ ) {
+ print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv
+ use_fill = false;
+ }
+ }
+
+ return 0;
+}
+
+
+unsigned int PrintWmf::stroke(
+ Inkscape::Extension::Print * /*mod*/,
+ Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style,
+ Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
+{
+
+ char *rec = NULL;
+ Geom::Affine tf = m_tr_stack.top();
+
+ use_stroke = true;
+ // use_fill was set in ::fill, if it is needed, if not, the null brush is used, it should be already set
+
+ if (create_pen(style, tf)) {
+ return 0;
+ }
+
+ if (!style->stroke_dasharray.values.empty() && FixPPTDashLine) {
+ // convert the path, gets its complete length, and then make a new path with parameter length instead of t
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end
+ int n_dash = style->stroke_dasharray.values.size();
+ int i = 0; //dash index
+ double tlength; // length of tmp_pathpw
+ double slength = 0.0; // start of gragment
+ double elength; // end of gragment
+ for (unsigned int i = 0; i < pathv.size(); i++) {
+ tmp_pathpw.concat(pathv[i].toPwSb());
+ }
+ tlength = length(tmp_pathpw, 0.1);
+ tmp_pathpw2 = arc_length_parametrization(tmp_pathpw);
+
+ // go around the dash array repeatedly until the entire path is consumed (but not beyond).
+ while (slength < tlength) {
+ elength = slength + style->stroke_dasharray.values[i++];
+ if (elength > tlength) {
+ elength = tlength;
+ }
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength));
+ if (slength) {
+ tmp_pathpw3.concat(fragment);
+ } else {
+ first_frag = fragment;
+ }
+ slength = elength;
+ slength += style->stroke_dasharray.values[i++]; // the gap
+ if (i >= n_dash) {
+ i = 0;
+ }
+ }
+ tmp_pathpw3.concat(first_frag); // may merge line around start point
+ Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01);
+ print_pathv(out_pathv, tf);
+ } else {
+ print_pathv(pathv, tf);
+ }
+
+ use_stroke = false;
+ use_fill = false;
+
+ if (usebk) { // OPAQUE was set, revert to TRANSPARENT
+ usebk = false;
+ rec = U_WMRSETBKMODE_set(U_TRANSPARENT);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::stroke at U_WMRSETBKMODE_set");
+ }
+ }
+
+ return 0;
+}
+
+
+// Draws simple_shapes, those with closed WMR_* primitives, like polygons, rectangles and ellipses.
+// These use whatever the current pen/brush are and need not be followed by a FILLPATH or STROKEPATH.
+// For other paths it sets a few flags and returns.
+bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform)
+{
+
+ Geom::PathVector pv = pathv_to_linear(pathv * transform, MAXDISP);
+
+ int nodes = 0;
+ int moves = 0;
+ int lines = 0;
+ int curves = 0;
+ char *rec = NULL;
+
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
+ moves++;
+ nodes++;
+
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
+ nodes++;
+
+ if (is_straight_curve(*cit)) {
+ lines++;
+ } else if (&*cit) {
+ curves++;
+ }
+ }
+ }
+
+ if (!nodes) {
+ return false;
+ }
+
+ U_POINT16 *lpPoints = new U_POINT16[moves + lines + curves * 3];
+ int i = 0;
+
+ /** For all Subpaths in the <path> */
+
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
+ using Geom::X;
+ using Geom::Y;
+
+ Geom::Point p0 = pit->initialPoint();
+
+ p0[X] = (p0[X] * PX2WORLD);
+ p0[Y] = (p0[Y] * PX2WORLD);
+
+ int32_t const x0 = (int32_t) round(p0[X]);
+ int32_t const y0 = (int32_t) round(p0[Y]);
+
+ lpPoints[i].x = x0;
+ lpPoints[i].y = y0;
+ i = i + 1;
+
+ /** For all segments in the subpath */
+
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
+ if (is_straight_curve(*cit)) {
+ //Geom::Point p0 = cit->initialPoint();
+ Geom::Point p1 = cit->finalPoint();
+
+ //p0[X] = (p0[X] * PX2WORLD);
+ p1[X] = (p1[X] * PX2WORLD);
+ //p0[Y] = (p0[Y] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
+ int32_t const x1 = (int32_t) round(p1[X]);
+ int32_t const y1 = (int32_t) round(p1[Y]);
+
+ lpPoints[i].x = x1;
+ lpPoints[i].y = y1;
+ i = i + 1;
+ } else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*cit)) {
+ std::vector<Geom::Point> points = cubic->points();
+ //Geom::Point p0 = points[0];
+ Geom::Point p1 = points[1];
+ Geom::Point p2 = points[2];
+ Geom::Point p3 = points[3];
+
+ //p0[X] = (p0[X] * PX2WORLD);
+ p1[X] = (p1[X] * PX2WORLD);
+ p2[X] = (p2[X] * PX2WORLD);
+ p3[X] = (p3[X] * PX2WORLD);
+ //p0[Y] = (p0[Y] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ p2[Y] = (p2[Y] * PX2WORLD);
+ p3[Y] = (p3[Y] * PX2WORLD);
+
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
+ int32_t const x1 = (int32_t) round(p1[X]);
+ int32_t const y1 = (int32_t) round(p1[Y]);
+ int32_t const x2 = (int32_t) round(p2[X]);
+ int32_t const y2 = (int32_t) round(p2[Y]);
+ int32_t const x3 = (int32_t) round(p3[X]);
+ int32_t const y3 = (int32_t) round(p3[Y]);
+
+ lpPoints[i].x = x1;
+ lpPoints[i].y = y1;
+ lpPoints[i + 1].x = x2;
+ lpPoints[i + 1].y = y2;
+ lpPoints[i + 2].x = x3;
+ lpPoints[i + 2].y = y3;
+ i = i + 3;
+ }
+ }
+ }
+
+ bool done = false;
+ bool closed = (lpPoints[0].x == lpPoints[i - 1].x) && (lpPoints[0].y == lpPoints[i - 1].y);
+ bool polygon = false;
+ bool rectangle = false;
+ bool ellipse = false;
+
+ if (moves == 1 && moves + lines == nodes && closed) {
+ polygon = true;
+ // if (nodes==5) { // disable due to LP Bug 407394
+ // if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x &&
+ // lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y)
+ // {
+ // rectangle = true;
+ // }
+ // }
+ } else if (moves == 1 && nodes == 5 && moves + curves == nodes && closed) {
+ // if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
+ // lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
+ // lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
+ // lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
+ // lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
+ // lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
+ // { // disable due to LP Bug 407394
+ // ellipse = true;
+ // }
+ }
+
+ if (polygon || ellipse) {
+ // pens and brushes already set by caller, do not touch them
+
+ if (polygon) {
+ if (rectangle) {
+ U_RECT16 rcl = U_RECT16_set((U_POINT16) {
+ lpPoints[0].x, lpPoints[0].y
+ }, (U_POINT16) {
+ lpPoints[2].x, lpPoints[2].y
+ });
+ rec = U_WMRRECTANGLE_set(rcl);
+ } else {
+ rec = U_WMRPOLYGON_set(nodes, lpPoints);
+ }
+ } else if (ellipse) {
+ U_RECT16 rcl = U_RECT16_set((U_POINT16) {
+ lpPoints[6].x, lpPoints[3].y
+ }, (U_POINT16) {
+ lpPoints[0].x, lpPoints[9].y
+ });
+ rec = U_WMRELLIPSE_set(rcl);
+ }
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::print_simple_shape at retangle/ellipse/polygon");
+ }
+
+ done = true;
+
+ }
+
+ delete[] lpPoints;
+
+ return done;
+}
+
+/** Some parts based on win32.cpp by Lauris Kaplinski <lauris@kaplinski.com>. Was a part of Inkscape
+ in the past (or will be in the future?) Not in current trunk. (4/19/2012)
+
+ Limitations of this code:
+ 1. Images lose their rotation, one corner stays in the same place.
+ 2. Transparency is lost on export. (A limitation of the WMF format.)
+ 3. Probably messes up if row stride != w*4
+ 4. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine
+ that calls this one and passes px, but never removes the rest of the pixbuf. The first time
+ this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more.
+ If this routine is reduced to
+ if(1)return(0);
+ and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the
+ size of two bitmaps.
+*/
+
+unsigned int PrintWmf::image(
+ Inkscape::Extension::Print * /* module */, /** not used */
+ unsigned char *rgba_px, /** array of pixel values, Gdk::Pixbuf bitmap format */
+ unsigned int w, /** width of bitmap */
+ unsigned int h, /** height of bitmap */
+ unsigned int rs, /** row stride (normally w*4) */
+ Geom::Affine const &tf_rect, /** affine transform only used for defining location and size of rect, for all other tranforms, use the one from m_tr_stack */
+ SPStyle const * /*style*/) /** provides indirect link to image object */
+{
+ double x1, y1, dw, dh;
+ char *rec = NULL;
+ Geom::Affine tf = m_tr_stack.top();
+
+ rec = U_WMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::image at EMRHEADER");
+ }
+
+ x1 = tf_rect[4];
+ y1 = tf_rect[5];
+ dw = ((double) w) * tf_rect[0];
+ dh = ((double) h) * tf_rect[3];
+ Geom::Point pLL(x1, y1);
+ Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates
+
+ /* adjust scale of w and h. This works properly when there is no rotation. The values are
+ a bit strange when there is rotation, but since WMF cannot handle rotation in any case, all
+ answers are equally wrong.
+ */
+ Geom::Point pWH(dw, dh);
+ Geom::Point pWH2 = pWH * tf.withoutTranslation();
+
+ char *px;
+ uint32_t cbPx;
+ uint32_t colortype;
+ U_RGBQUAD *ct;
+ int numCt;
+ U_BITMAPINFOHEADER Bmih;
+ U_BITMAPINFO *Bmi;
+ colortype = U_BCBM_COLOR32;
+ (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w * 4, colortype, 0, 1);
+ Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
+ Bmi = bitmapinfo_set(Bmih, ct);
+
+ U_POINT16 Dest = point16_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD));
+ U_POINT16 cDest = point16_set(round(pWH2[Geom::X] * PX2WORLD), round(pWH2[Geom::Y] * PX2WORLD));
+ U_POINT16 Src = point16_set(0, 0);
+ U_POINT16 cSrc = point16_set(w, h);
+ rec = U_WMRSTRETCHDIB_set(
+ Dest, //! Destination UL corner in logical units
+ cDest, //! Destination W & H in logical units
+ Src, //! Source UL corner in logical units
+ cSrc, //! Source W & H in logical units
+ U_DIB_RGB_COLORS, //! DIBColors Enumeration
+ U_SRCCOPY, //! RasterOPeration Enumeration
+ Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section)
+ h * rs, //! size in bytes of px
+ px //! (Optional) bitmapbuffer (U_BITMAPINFO section)
+ );
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::image at U_WMRSTRETCHDIB_set");
+ }
+ free(px);
+ free(Bmi);
+ if (numCt) {
+ free(ct);
+ }
+ return 0;
+}
+
+// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything
+unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform)
+{
+ char *rec = NULL;
+ U_POINT16 *pt16hold, *pt16ptr;
+ uint16_t *n16hold;
+ uint16_t *n16ptr;
+
+ simple_shape = print_simple_shape(pathv, transform);
+ if (!simple_shape && !pathv.empty()) {
+ // WMF does not have beziers, need to convert to ONLY linears with something like this:
+ Geom::PathVector pv = pathv_to_linear(pathv * transform, MAXDISP);
+
+ /** For all Subpaths in the <path> */
+
+ /* If the path consists entirely of closed subpaths use one polypolygon.
+ Otherwise use a mix of polygon or polyline separately on each path.
+ If the polyline turns out to be single line segments, use a series of MOVETO/LINETO instead,
+ because WMF has no POLYPOLYLINE.
+ The former allows path delimited donuts and the like, which
+ cannot be represented in WMF with polygon or polyline because there is no external way to combine paths
+ as there is in EMF or SVG.
+ For polygons specify the last point the same as the first. The WMF/EMF manuals say that the
+ reading program SHOULD close the path, which allows a conforming program not to, potentially rendering
+ a closed path as an open one. */
+ int nPolys = 0;
+ int totPoints = 0;
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
+ totPoints += 1 + pit->size_default(); // big array, will hold all points, for all polygons. Size_default ignores first point in each path.
+ if (pit->end_default() == pit->end_closed()) {
+ nPolys++;
+ } else {
+ nPolys = 0;
+ break;
+ }
+ }
+
+ if (nPolys > 1) { // a single polypolygon, a single polygon falls through to the else
+ pt16hold = pt16ptr = (U_POINT16 *) malloc(totPoints * sizeof(U_POINT16));
+ if (!pt16ptr) {
+ return(false);
+ }
+
+ n16hold = n16ptr = (uint16_t *) malloc(nPolys * sizeof(uint16_t));
+ if (!n16ptr) {
+ free(pt16hold);
+ return(false);
+ }
+
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
+ using Geom::X;
+ using Geom::Y;
+
+
+ *n16ptr++ = pit->size_default(); // points in the subpath
+
+ /** For each segment in the subpath */
+
+ Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator
+
+ p1[X] = (p1[X] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
+
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
+ Geom::Point p1 = cit->finalPoint();
+
+ p1[X] = (p1[X] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
+ }
+
+ }
+ rec = U_WMRPOLYPOLYGON_set(nPolys, n16hold, pt16hold);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYPOLYGON_set");
+ }
+ free(pt16hold);
+ free(n16hold);
+ } else { // one or more polyline or polygons (but not all polygons, that would be the preceding case)
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) {
+ using Geom::X;
+ using Geom::Y;
+
+ /* Malformatted Polylines with a sequence like M L M M L have been seen, the 2nd M does nothing
+ and that point must not go into the output. */
+ if (!(pit->size_default())) {
+ continue;
+ }
+ /* Figure out how many points there are, make an array big enough to hold them, and store
+ all the points. This is the same for open or closed path. This gives the upper bound for
+ the number of points. The actual number used is calculated on the fly.
+ */
+ int nPoints = 1 + pit->size_default();
+
+ pt16hold = pt16ptr = (U_POINT16 *) malloc(nPoints * sizeof(U_POINT16));
+ if (!pt16ptr) {
+ break;
+ }
+
+ /** For each segment in the subpath */
+
+ Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator
+
+ p1[X] = (p1[X] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
+ nPoints = 1;
+
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit, nPoints++) {
+ Geom::Point p1 = cit->finalPoint();
+
+ p1[X] = (p1[X] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
+ }
+
+ if (pit->end_default() == pit->end_closed()) {
+ rec = U_WMRPOLYGON_set(nPoints, pt16hold);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYGON_set");
+ }
+ } else if (nPoints > 2) {
+ rec = U_WMRPOLYLINE_set(nPoints, pt16hold);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::print_pathv at U_POLYLINE_set");
+ }
+ } else if (nPoints == 2) {
+ rec = U_WMRMOVETO_set(pt16hold[0]);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRMOVETO_set");
+ }
+ rec = U_WMRLINETO_set(pt16hold[1]);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRLINETO_set");
+ }
+ }
+ free(pt16hold);
+ }
+ }
+ }
+
+ // WMF has no fill or stroke commands, the draw does it with active pen/brush
+
+ // clean out brush and pen, but only after all parts of the draw complete
+ if (use_fill) {
+ destroy_brush();
+ }
+ if (use_stroke) {
+ destroy_pen();
+ }
+
+ return TRUE;
+}
+
+
+unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p,
+ SPStyle const *const style)
+{
+ if (!wt) {
+ return 0;
+ }
+
+ char *rec = NULL;
+ int ccount, newfont;
+ int fix90n = 0;
+ uint32_t hfont = 0;
+ Geom::Affine tf = m_tr_stack.top();
+ double rot = -1800.0 * std::atan2(tf[1], tf[0]) / M_PI; // 0.1 degree rotation, - sign for MM_TEXT
+ double rotb = -std::atan2(tf[1], tf[0]); // rotation for baseline offset for superscript/subscript, used below
+ double dx, dy;
+ double ky;
+
+ // the dx array is smuggled in like: text<nul>w1 w2 w3 ...wn<nul><nul>, where the widths are floats 7 characters wide, including the space
+ int ndx, rtl;
+ int16_t *adx;
+ smuggle_adxky_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(), tf.expansionY())); // side effect: free() adx
+
+ uint32_t textalignment;
+ if (rtl > 0) {
+ textalignment = U_TA_BASELINE | U_TA_LEFT;
+ } else {
+ textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING;
+ }
+ if (textalignment != htextalignment) {
+ htextalignment = textalignment;
+ rec = U_WMRSETTEXTALIGN_set(textalignment);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTALIGN_set");
+ }
+ }
+
+ char *text2 = strdup(text); // because U_Utf8ToUtf16le calls iconv which does not like a const char *
+ uint16_t *unicode_text = U_Utf8ToUtf16le(text2, 0, NULL);
+ free(text2);
+ //translates Unicode as Utf16le to NonUnicode, if possible. If any translate, all will, and all to
+ //the same font, because of code in Layout::print
+ UnicodeToNon(unicode_text, &ccount, &newfont);
+ // The preceding hopefully handled conversions to symbol, wingdings or zapf dingbats. Now slam everything
+ // else down into latin1, which is all WMF can handle. If the language isn't English expect terrible results.
+ char *latin1_text = U_Utf16leToLatin1(unicode_text, 0, NULL);
+ free(unicode_text);
+
+ //PPT gets funky with text within +-1 degree of a multiple of 90, but only for SOME fonts.Snap those to the central value
+ //Some funky ones: Arial, Times New Roman
+ //Some not funky ones: Symbol and Verdana.
+ //Without a huge table we cannot catch them all, so just the most common problem ones.
+ FontfixParams params;
+
+ if (FixPPTCharPos) {
+ switch (newfont) {
+ case CVTSYM:
+ _lookup_ppt_fontfix("Convert To Symbol", params);
+ break;
+ case CVTZDG:
+ _lookup_ppt_fontfix("Convert To Zapf Dingbats", params);
+ break;
+ case CVTWDG:
+ _lookup_ppt_fontfix("Convert To Wingdings", params);
+ break;
+ default: //also CVTNON
+ _lookup_ppt_fontfix(style->text->font_family.value, params);
+ break;
+ }
+ if (params.f2 != 0 || params.f3 != 0) {
+ int irem = ((int) round(rot)) % 900 ;
+ if (irem <= 9 && irem >= -9) {
+ fix90n = 1; //assume vertical
+ rot = (double)(((int) round(rot)) - irem);
+ rotb = rot * M_PI / 1800.0;
+ if (abs(rot) == 900.0) {
+ fix90n = 2;
+ }
+ }
+ }
+ }
+
+ /*
+ Note that text font sizes are stored into the WMF as fairly small integers and that limits their precision.
+ The WMF output files produced here have been designed so that the integer valued pt sizes
+ land right on an integer value in the WMF file, so those are exact. However, something like 18.1 pt will be
+ somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.)
+ */
+ int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(), tf.expansionY()));
+ if (!hfont) {
+
+ // Get font face name. Use changed font name if unicode mapped to one
+ // of the special fonts.
+ char *facename;
+ if (!newfont) {
+ facename = U_Utf8ToLatin1(style->text->font_family.value, 0, NULL);
+ } else {
+ facename = U_Utf8ToLatin1(FontName(newfont), 0, NULL);
+ }
+
+ // Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if
+ // it was streteched asymmetrically.) Few applications support text from WMF which is scaled
+ // differently by height/width, so leave lfWidth alone.
+
+ U_FONT *puf = U_FONT_set(
+ textheight,
+ 0,
+ round(rot),
+ round(rot),
+ _translate_weight(style->font_weight.computed),
+ (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC),
+ style->text_decoration_line.underline,
+ style->text_decoration_line.line_through,
+ U_DEFAULT_CHARSET,
+ U_OUT_DEFAULT_PRECIS,
+ U_CLIP_DEFAULT_PRECIS,
+ U_DEFAULT_QUALITY,
+ U_DEFAULT_PITCH | U_FF_DONTCARE,
+ facename);
+ free(facename);
+
+ rec = wcreatefontindirect_set(&hfont, wht, puf);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::text at wcreatefontindirect_set");
+ }
+ free(puf);
+ }
+
+ rec = wselectobject_set(hfont, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::text at wselectobject_set");
+ }
+
+ float rgb[3];
+ sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
+ // only change the text color when it needs to be changed
+ if (memcmp(htextcolor_rgb, rgb, 3 * sizeof(float))) {
+ memcpy(htextcolor_rgb, rgb, 3 * sizeof(float));
+ rec = U_WMRSETTEXTCOLOR_set(U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]));
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set");
+ }
+ }
+
+
+ // Text alignment:
+ // - (x,y) coordinates received by this filter are those of the point where the text
+ // actually starts, and already takes into account the text object's alignment;
+ // - for this reason, the WMF text alignment must always be TA_BASELINE|TA_LEFT.
+ // this is set at the beginning of the file and never changed
+
+ // Transparent text background, never changes, set at the beginning of the file
+
+ Geom::Point p2 = p * tf;
+
+ //Handle super/subscripts and vertical kerning
+ /* Previously used this, but vertical kerning was not supported
+ p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb );
+ p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb );
+ */
+ p2[Geom::X] += ky * std::sin(rotb);
+ p2[Geom::Y] += ky * std::cos(rotb);
+
+ //Conditionally handle compensation for PPT WMF import bug (affects PPT 2003-2010, at least)
+ if (FixPPTCharPos) {
+ if (fix90n == 1) { //vertical
+ dx = 0.0;
+ dy = params.f3 * style->font_size.computed * std::cos(rotb);
+ } else if (fix90n == 2) { //horizontal
+ dx = params.f2 * style->font_size.computed * std::sin(rotb);
+ dy = 0.0;
+ } else {
+ dx = params.f1 * style->font_size.computed * std::sin(rotb);
+ dy = params.f1 * style->font_size.computed * std::cos(rotb);
+ }
+ p2[Geom::X] += dx;
+ p2[Geom::Y] += dy;
+ }
+
+ p2[Geom::X] = (p2[Geom::X] * PX2WORLD);
+ p2[Geom::Y] = (p2[Geom::Y] * PX2WORLD);
+
+ int32_t const xpos = (int32_t) round(p2[Geom::X]);
+ int32_t const ypos = (int32_t) round(p2[Geom::Y]);
+
+ // The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is
+ // the number of VISIBLE characters, since some may combine from the UTF (8 originally,
+ // now 16) encoding. Conversely strlen() or wchar16len() would give the absolute number of
+ // encoding characters. Unclear if emrtext wants the former or the latter but for now assume the former.
+
+ // This is currently being smuggled in from caller as part of text, works
+ // MUCH better than the fallback hack below
+ // uint32_t *adx = dx_set(textheight, U_FW_NORMAL, slen); // dx is needed, this makes one up
+ if (rtl > 0) {
+ rec = U_WMREXTTEXTOUT_set((U_POINT16) {
+ (int16_t) xpos, (int16_t) ypos
+ },
+ ndx, U_ETO_NONE, latin1_text, adx, U_RCL16_DEF);
+ } else { // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case
+ rec = U_WMREXTTEXTOUT_set((U_POINT16) {
+ (int16_t) xpos, (int16_t) ypos
+ },
+ ndx, U_ETO_RTLREADING, latin1_text, adx, U_RCL16_DEF);
+ }
+ free(latin1_text);
+ free(adx);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::text at U_WMREXTTEXTOUTW_set");
+ }
+
+ rec = wdeleteobject_set(&hfont, wht);
+ if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintWmf::text at wdeleteobject_set");
+ }
+
+ return 0;
+}
+
+void PrintWmf::init(void)
+{
+ _load_ppt_fontfix_data();
+
+ /* WMF print */
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
+ "<name>Windows Metafile Print</name>\n"
+ "<id>org.inkscape.print.wmf</id>\n"
+ "<param name=\"destination\" type=\"string\"></param>\n"
+ "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
+ "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n"
+ "<param name=\"FixPPTCharPos\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTDashLine\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTGrad2Polys\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTPatternAsHatch\" type=\"boolean\">false</param>\n"
+ "<print/>\n"
+ "</inkscape-extension>", new PrintWmf());
+
+ return;
+}
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+
+/*
+ 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/emf-win32-print.h b/src/extension/internal/wmf-print.h
index e7bd08477..1e5d4c323 100644
--- a/src/extension/internal/emf-win32-print.h
+++ b/src/extension/internal/wmf-print.h
@@ -1,5 +1,5 @@
/** @file
- * @brief Enhanced Metafile printing - implementation
+ * @brief Windows Metafile printing - implementation
*/
/* Author:
* Ulf Erikson <ulferikson@users.sf.net>
@@ -8,59 +8,34 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__
-#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__
-
-#ifdef WIN32
+#ifndef SEEN_INKSCAPE_EXTENSION_INTERNAL_WMF_PRINT_H
+#define SEEN_INKSCAPE_EXTENSION_INTERNAL_WMF_PRINT_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-#include "extension/implementation/implementation.h"
-//#include "extension/extension.h"
-
-#include <2geom/pathvector.h>
+#include <libuemf/uwmf.h>
+#include "extension/internal/metafile-print.h"
-#include <stack>
+#include "sp-gradient.h"
+#include "splivarot.h" // pieces for union on shapes
+#include "display/canvas-bpath.h" // for SPWindRule
namespace Inkscape {
namespace Extension {
namespace Internal {
-class PrintEmfWin32 : public Inkscape::Extension::Implementation::Implementation
+class PrintWmf : public PrintMetafile
{
- double _width;
- double _height;
- HDC hdc;
- RECT rc;
-
- HBRUSH hbrush, hbrushOld;
- HPEN hpen, hpenOld;
-
- std::stack<Geom::Affine> m_tr_stack;
- Geom::PathVector fill_pathv;
- Geom::Affine fill_transform;
- bool stroke_and_fill;
- bool fill_only;
- bool simple_shape;
+ uint32_t hbrush, hpen, hpenOld, hbrush_null, hpen_null;
+ uint32_t hmiterlimit; // used to minimize redundant records that set this
unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform);
bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform);
- unsigned int image(Inkscape::Extension::Print * /* module */, /** not used */
- unsigned char *px, /** array of pixel values, Gdk::Pixbuf bitmap format */
- unsigned int w, /** width of bitmap */
- unsigned int h, /** height of bitmap */
- unsigned int rs, /** row stride (normally w*4) */
- Geom::Affine const &tf_ignore, /** WRONG affine transform, use the one from m_tr_stack */
- SPStyle const *style); /** provides indirect link to image object */
public:
- PrintEmfWin32 (void);
- virtual ~PrintEmfWin32 (void);
+ PrintWmf();
/* Print functions */
virtual unsigned int setup (Inkscape::Extension::Print * module);
@@ -69,8 +44,6 @@ public:
virtual unsigned int finish (Inkscape::Extension::Print * module);
/* Rendering methods */
- virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity);
- virtual unsigned int release(Inkscape::Extension::Print *module);
virtual unsigned int fill (Inkscape::Extension::Print *module,
Geom::PathVector const &pathv,
Geom::Affine const &ctm, SPStyle const *style,
@@ -81,32 +54,33 @@ public:
Geom::Affine const &ctm, SPStyle const *style,
Geom::OptRect const &pbox, Geom::OptRect const &dbox,
Geom::OptRect const &bbox);
+ virtual unsigned int image(Inkscape::Extension::Print *module,
+ unsigned char *px,
+ unsigned int w,
+ unsigned int h,
+ unsigned int rs,
+ Geom::Affine const &transform,
+ SPStyle const *style);
virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment);
virtual unsigned int text(Inkscape::Extension::Print *module, char const *text,
Geom::Point const &p, SPStyle const *style);
- bool textToPath (Inkscape::Extension::Print * ext);
static void init (void);
protected:
- int create_brush(SPStyle const *style);
+ static void smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *rtl, int *ndx, float scale);
+ int create_brush(SPStyle const *style, PU_COLORREF fcolor);
void destroy_brush();
-
- void create_pen(SPStyle const *style, const Geom::Affine &transform);
-
+ int create_pen(SPStyle const *style, const Geom::Affine &transform);
void destroy_pen();
-
- void flush_fill();
-
};
} /* namespace Internal */
} /* namespace Extension */
} /* namespace Inkscape */
-#endif /* WIN32 */
-#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__ */
+#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_WMF_H__ */
/*
Local Variables:
diff --git a/src/extension/internal/wpg-input.cpp b/src/extension/internal/wpg-input.cpp
index cb1677547..14ff3ec77 100644
--- a/src/extension/internal/wpg-input.cpp
+++ b/src/extension/internal/wpg-input.cpp
@@ -48,6 +48,8 @@
#include "extension/system.h"
#include "extension/input.h"
#include "document.h"
+#include "sp-root.h"
+#include "util/units.h"
#include <cstring>
// Take a guess and fallback to 0.1.x if no configure has run
@@ -109,6 +111,12 @@ SPDocument *WpgInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * u
//printf("I've got a doc: \n%s", painter.document.c_str());
SPDocument * doc = SPDocument::createNewDocFromMem(output.cstr(), strlen(output.cstr()), TRUE);
+
+ // Set viewBox if it doesn't exist
+ if (doc && !doc->getRoot()->viewBox_set) {
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit())));
+ }
+
delete input;
return doc;
}
diff --git a/src/extension/output.h b/src/extension/output.h
index 5f6785b8b..c5b1beb45 100644
--- a/src/extension/output.h
+++ b/src/extension/output.h
@@ -15,7 +15,7 @@
#include <gtk/gtk.h>
#include "extension.h"
-struct SPDocument;
+class SPDocument;
namespace Inkscape {
namespace Extension {
diff --git a/src/extension/param/bool.cpp b/src/extension/param/bool.cpp
index abef8d8f3..548dec4fa 100644
--- a/src/extension/param/bool.cpp
+++ b/src/extension/param/bool.cpp
@@ -10,6 +10,10 @@
# include "config.h"
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/adjustment.h>
#include <gtkmm/box.h>
#include <gtkmm/spinbutton.h>
@@ -137,11 +141,7 @@ Gtk::Widget *ParamBool::get_widget(SPDocument * doc, Inkscape::XML::Node * node,
Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
#endif
-#if WITH_GTKMM_2_22
Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START));
-#else
- Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
-#endif
label->show();
hbox->pack_end(*label, true, true);
diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp
index d8c78c97d..0a2598c56 100644
--- a/src/extension/param/color.cpp
+++ b/src/extension/param/color.cpp
@@ -14,6 +14,10 @@
#include <iostream>
#include <sstream>
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/adjustment.h>
#include <gtkmm/box.h>
#include <gtkmm/spinbutton.h>
diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp
index efdf03721..95ed04afc 100644
--- a/src/extension/param/description.cpp
+++ b/src/extension/param/description.cpp
@@ -13,6 +13,10 @@
# include "config.h"
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/box.h>
#include <gtkmm/label.h>
#include <glibmm/i18n.h>
@@ -62,7 +66,10 @@ ParamDescription::ParamDescription (const gchar * name,
Gtk::Widget *
ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/, sigc::signal<void> * /*changeSignal*/)
{
- if (_gui_hidden) {
+ if (_gui_hidden) {
+ return NULL;
+ }
+ if (_value == NULL) {
return NULL;
}
@@ -77,20 +84,12 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node
Gtk::Label * label;
int padding = 12 + _indent;
if (_mode == HEADER) {
-#if WITH_GTKMM_2_22
label = Gtk::manage(new Gtk::Label(Glib::ustring("<b>") +newguitext + Glib::ustring("</b>"), Gtk::ALIGN_START));
-#else
- label = Gtk::manage(new Gtk::Label(Glib::ustring("<b>") +newguitext + Glib::ustring("</b>"), Gtk::ALIGN_LEFT));
-#endif
label->set_padding(0,5);
label->set_use_markup(true);
padding = _indent;
} else {
-#if WITH_GTKMM_2_22
label = Gtk::manage(new Gtk::Label(newguitext, Gtk::ALIGN_START));
-#else
- label = Gtk::manage(new Gtk::Label(newguitext, Gtk::ALIGN_LEFT));
-#endif
}
label->set_line_wrap();
label->show();
diff --git a/src/extension/param/enum.cpp b/src/extension/param/enum.cpp
index 74ae995fb..bb50c06e1 100644
--- a/src/extension/param/enum.cpp
+++ b/src/extension/param/enum.cpp
@@ -18,6 +18,10 @@
# include "config.h"
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/box.h>
#include <gtkmm/comboboxtext.h>
#include <glibmm/i18n.h>
@@ -173,6 +177,24 @@ const gchar *ParamComboBox::set(const gchar * in, SPDocument * /*doc*/, Inkscape
return _value;
}
+/**
+ * function to test if \c guitext is selectable
+ */
+bool ParamComboBox::contains(const gchar * guitext, SPDocument const * /*doc*/, Inkscape::XML::Node const * /*node*/) const
+{
+ if (guitext == NULL) {
+ return false; /* Can't have NULL string */
+ }
+
+ for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
+ enumentry * entr = reinterpret_cast<enumentry *>(list->data);
+ if ( !entr->guitext.compare(guitext) )
+ return true;
+ }
+ // if we did not find the guitext in this ParamComboBox:
+ return false;
+}
+
void
ParamComboBox::changed (void) {
@@ -232,12 +254,7 @@ Gtk::Widget *ParamComboBox::get_widget(SPDocument * doc, Inkscape::XML::Node * n
}
Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
-
-#if WITH_GTKMM_2_22
Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START));
-#else
- Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
-#endif
label->show();
hbox->pack_start(*label, false, false, _indent);
@@ -247,11 +264,7 @@ Gtk::Widget *ParamComboBox::get_widget(SPDocument * doc, Inkscape::XML::Node * n
for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
enumentry * entr = reinterpret_cast<enumentry *>(list->data);
Glib::ustring text = entr->guitext;
-#if WITH_GTKMM_2_24
combo->append(text);
-#else
- combo->append_text(text);
-#endif
if ( _value && !entr->value.compare(_value) ) {
settext = entr->guitext;
diff --git a/src/extension/param/enum.h b/src/extension/param/enum.h
index ac7d72abd..52e018469 100644
--- a/src/extension/param/enum.h
+++ b/src/extension/param/enum.h
@@ -51,6 +51,11 @@ public:
const gchar * set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node);
+ /**
+ * @returns true if guitext is part of this enum
+ */
+ bool contains(const gchar * guitext, SPDocument const * /*doc*/, Inkscape::XML::Node const * /*node*/) const;
+
void changed (void);
}; /* class ParamComboBox */
diff --git a/src/extension/param/float.cpp b/src/extension/param/float.cpp
index 2f1c77d4e..464938f03 100644
--- a/src/extension/param/float.cpp
+++ b/src/extension/param/float.cpp
@@ -10,10 +10,15 @@
# include "config.h"
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/adjustment.h>
#include <gtkmm/box.h>
#include <gtkmm/scale.h>
#include "ui/widget/spinbutton.h"
+#include "ui/widget/spin-scale.h"
#include "xml/node.h"
#include "extension/extension.h"
@@ -176,14 +181,6 @@ Gtk::Widget * ParamFloat::get_widget(SPDocument * doc, Inkscape::XML::Node * nod
Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
-#if WITH_GTKMM_2_22
- Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START));
-#else
- Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
-#endif
- label->show();
- hbox->pack_start(*label, true, true, _indent);
-
#if WITH_GTKMM_3_0
ParamFloatAdjustment * pfa = new ParamFloatAdjustment(this, doc, node, changeSignal);
Glib::RefPtr<Gtk::Adjustment> fadjust(pfa);
@@ -192,24 +189,27 @@ Gtk::Widget * ParamFloat::get_widget(SPDocument * doc, Inkscape::XML::Node * nod
#endif
if (_mode == FULL) {
-#if WITH_GTKMM_3_0
- Gtk::HScale * scale = Gtk::manage(new Gtk::HScale(fadjust));
-#else
- Gtk::HScale * scale = Gtk::manage(new Gtk::HScale(*fadjust));
-#endif
- scale->set_draw_value(false);
- scale->set_size_request(200, -1);
+
+ UI::Widget::SpinScale *scale = new UI::Widget::SpinScale(_(_text), fadjust, _precision);
+ scale->set_size_request(400, -1);
scale->show();
hbox->pack_start(*scale, false, false);
+
}
+ else if (_mode == MINIMAL) {
+
+ Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START));
+ label->show();
+ hbox->pack_start(*label, true, true, _indent);
#if WITH_GTKMM_3_0
Inkscape::UI::Widget::SpinButton * spin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(fadjust, 0.1, _precision));
#else
Inkscape::UI::Widget::SpinButton * spin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(*fadjust, 0.1, _precision));
#endif
- spin->show();
- hbox->pack_start(*spin, false, false);
+ spin->show();
+ hbox->pack_start(*spin, false, false);
+ }
hbox->show();
diff --git a/src/extension/param/int.cpp b/src/extension/param/int.cpp
index fe29f1230..819c75693 100644
--- a/src/extension/param/int.cpp
+++ b/src/extension/param/int.cpp
@@ -10,10 +10,15 @@
# include "config.h"
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/adjustment.h>
#include <gtkmm/box.h>
#include <gtkmm/scale.h>
#include "ui/widget/spinbutton.h"
+#include "ui/widget/spin-scale.h"
#include "xml/node.h"
#include "extension/extension.h"
@@ -157,13 +162,6 @@ ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal
Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
-#if WITH_GTKMM_2_22
- Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START));
-#else
- Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
-#endif
- label->show();
- hbox->pack_start(*label, true, true, _indent);
#if WITH_GTKMM_3_0
ParamIntAdjustment * pia = new ParamIntAdjustment(this, doc, node, changeSignal);
@@ -173,24 +171,26 @@ ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal
#endif
if (_mode == FULL) {
-#if WITH_GTKMM_3_0
- Gtk::HScale * scale = Gtk::manage(new Gtk::HScale(fadjust));
-#else
- Gtk::HScale * scale = Gtk::manage(new Gtk::HScale(*fadjust));
-#endif
- scale->set_draw_value(false);
- scale->set_size_request(200, -1);
+
+ UI::Widget::SpinScale *scale = new UI::Widget::SpinScale(_(_text), fadjust, 0);
+ scale->set_size_request(400, -1);
scale->show();
hbox->pack_start(*scale, false, false);
}
+ else if (_mode == MINIMAL) {
+ Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START));
+ label->show();
+ hbox->pack_start(*label, true, true, _indent);
+
#if WITH_GTKMM_3_0
Inkscape::UI::Widget::SpinButton * spin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(fadjust, 1.0, 0));
#else
Inkscape::UI::Widget::SpinButton * spin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(*fadjust, 1.0, 0));
#endif
- spin->show();
- hbox->pack_start(*spin, false, false);
+ spin->show();
+ hbox->pack_start(*spin, false, false);
+ }
hbox->show();
diff --git a/src/extension/param/notebook.cpp b/src/extension/param/notebook.cpp
index ee7f15004..97002e33f 100644
--- a/src/extension/param/notebook.cpp
+++ b/src/extension/param/notebook.cpp
@@ -16,6 +16,9 @@
# include "config.h"
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
#include <gtkmm/adjustment.h>
#include <gtkmm/box.h>
@@ -206,14 +209,16 @@ Gtk::Widget * ParamNotebookPage::get_widget(SPDocument * doc, Inkscape::XML::Nod
for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) {
Parameter * param = reinterpret_cast<Parameter *>(list->data);
Gtk::Widget * widg = param->get_widget(doc, node, changeSignal);
- gchar const * tip = param->get_tooltip();
-// printf("Tip: '%s'\n", tip);
- vbox->pack_start(*widg, false, false, 2);
- if (tip) {
- widg->set_tooltip_text(tip);
- } else {
- widg->set_tooltip_text("");
- widg->set_has_tooltip(false);
+ if (widg) {
+ gchar const * tip = param->get_tooltip();
+ // printf("Tip: '%s'\n", tip);
+ vbox->pack_start(*widg, false, false, 2);
+ if (tip) {
+ widg->set_tooltip_text(tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
}
}
@@ -352,7 +357,11 @@ public:
// hook function
this->signal_switch_page().connect(sigc::mem_fun(this, &ParamNotebookWdg::changed_page));
};
+#if WITH_GTKMM_3_0
+ void changed_page(Gtk::Widget *page, guint pagenum);
+#else
void changed_page(GtkNotebookPage *page, guint pagenum);
+#endif
bool activated;
};
@@ -363,8 +372,11 @@ public:
* is actually visible. This to exclude 'fake' changes when the
* notebookpages are added or removed.
*/
-void ParamNotebookWdg::changed_page(GtkNotebookPage */*page*/,
- guint pagenum)
+#if WITH_GTKMM_3_0
+void ParamNotebookWdg::changed_page(Gtk::Widget * /*page*/, guint pagenum)
+#else
+void ParamNotebookWdg::changed_page(GtkNotebookPage * /*page*/, guint pagenum)
+#endif
{
if (get_visible()) {
_pref->set((int)pagenum, _doc, _node);
diff --git a/src/extension/param/parameter.cpp b/src/extension/param/parameter.cpp
index 97e4f9d8c..202b8110f 100644
--- a/src/extension/param/parameter.cpp
+++ b/src/extension/param/parameter.cpp
@@ -183,6 +183,15 @@ gchar const *Parameter::get_enum(SPDocument const *doc, Inkscape::XML::Node cons
return param->get(doc, node);
}
+bool Parameter::get_enum_contains(gchar const * value, SPDocument const *doc, Inkscape::XML::Node const *node) const
+{
+ ParamComboBox const *param = dynamic_cast<ParamComboBox const *>(this);
+ if (!param) {
+ throw Extension::param_not_enum_param();
+ }
+ return param->contains(value, doc, node);
+}
+
gchar const *Parameter::get_optiongroup(SPDocument const *doc, Inkscape::XML::Node const * node) const
{
ParamRadioButton const *param = dynamic_cast<ParamRadioButton const *>(this);
@@ -247,6 +256,15 @@ gchar const * Parameter::set_optiongroup( gchar const * in, SPDocument * doc, In
return param->set(in, doc, node);
}
+gchar const *Parameter::set_enum( gchar const * in, SPDocument * doc, Inkscape::XML::Node * node )
+{
+ ParamComboBox *param = dynamic_cast<ParamComboBox *>(this);
+ if (!param) {
+ throw Extension::param_not_enum_param();
+ }
+ return param->set(in, doc, node);
+}
+
/** Wrapper to cast to the object and use it's function. */
guint32
diff --git a/src/extension/param/parameter.h b/src/extension/param/parameter.h
index d08efc554..5e1e3897f 100644
--- a/src/extension/param/parameter.h
+++ b/src/extension/param/parameter.h
@@ -88,8 +88,10 @@ public:
gchar const *get_enum(SPDocument const *doc, Inkscape::XML::Node const *node) const;
/** Wrapper to cast to the object and use it's function. */
- gchar const *get_optiongroup(SPDocument const * doc, Inkscape::XML::Node const *node) const;
+ bool get_enum_contains(gchar const * value, SPDocument const *doc, Inkscape::XML::Node const *node) const;
+ /** Wrapper to cast to the object and use it's function. */
+ gchar const *get_optiongroup(SPDocument const * doc, Inkscape::XML::Node const *node) const;
/** Wrapper to cast to the object and use it's function. */
bool set_bool(bool in, SPDocument * doc, Inkscape::XML::Node * node);
@@ -101,6 +103,8 @@ public:
gchar const *set_optiongroup(gchar const *in, SPDocument * doc, Inkscape::XML::Node *node);
+ gchar const *set_enum(gchar const * in, SPDocument * doc, Inkscape::XML::Node *node);
+
gchar const *set_string(gchar const * in, SPDocument * doc, Inkscape::XML::Node * node);
guint32 set_color(guint32 in, SPDocument * doc, Inkscape::XML::Node * node);
diff --git a/src/extension/param/radiobutton.cpp b/src/extension/param/radiobutton.cpp
index d71d60ebd..75d5a40e3 100644
--- a/src/extension/param/radiobutton.cpp
+++ b/src/extension/param/radiobutton.cpp
@@ -18,6 +18,10 @@
# include "config.h"
#endif
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/box.h>
#include <gtkmm/comboboxtext.h>
#include <gtkmm/radiobutton.h>
@@ -172,7 +176,7 @@ const gchar *ParamRadioButton::set(const gchar * in, SPDocument * /*doc*/, Inksc
Glib::ustring * settext = NULL;
for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
optionentry * entr = reinterpret_cast<optionentry *>(list->data);
- if ( !entr->guitext->compare(in) ) {
+ if ( !entr->value->compare(in) ) {
settext = entr->value;
break; // break out of for loop
}
@@ -186,6 +190,8 @@ const gchar *ParamRadioButton::set(const gchar * in, SPDocument * /*doc*/, Inksc
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
prefs->setString(extension_pref_root + prefname, _value);
g_free(prefname);
+ } else {
+ g_warning("Couldn't set ParamRadioButton %s", in);
}
return _value;
@@ -233,8 +239,8 @@ public:
void ParamRadioButtonWdg::changed(void)
{
if (this->get_active()) {
- Glib::ustring data = this->get_label();
- _pref->set(data.c_str(), _doc, _node);
+ Glib::ustring value = _pref->value_from_label(this->get_label());
+ _pref->set(value.c_str(), _doc, _node);
}
if (_changeSignal != NULL) {
_changeSignal->emit();
@@ -260,12 +266,32 @@ protected:
virtual void on_changed() {
if ( base ) {
- base->set(get_active_text().c_str(), doc, node);
+ Glib::ustring value = base->value_from_label(get_active_text());
+ base->set(value.c_str(), doc, node);
}
}
};
/**
+ * Returns the value for the options label parameter
+ */
+Glib::ustring ParamRadioButton::value_from_label(const Glib::ustring label)
+{
+ Glib::ustring value = "";
+
+ for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
+ optionentry * entr = reinterpret_cast<optionentry *>(list->data);
+ if ( !entr->guitext->compare(label) ) {
+ value = *(entr->value);
+ break;
+ }
+ }
+
+ return value;
+
+}
+
+/**
* Creates a combobox widget for an enumeration parameter.
*/
Gtk::Widget * ParamRadioButton::get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
@@ -284,11 +310,7 @@ Gtk::Widget * ParamRadioButton::get_widget(SPDocument * doc, Inkscape::XML::Node
Gtk::VBox * vbox = Gtk::manage(new Gtk::VBox(false, 0));
#endif
-#if WITH_GTKMM_2_22
Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START, Gtk::ALIGN_START));
-#else
- Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP));
-#endif
label->show();
hbox->pack_start(*label, false, false, _indent);
@@ -309,11 +331,7 @@ Gtk::Widget * ParamRadioButton::get_widget(SPDocument * doc, Inkscape::XML::Node
switch ( _mode ) {
case MINIMAL:
{
-#if WITH_GTKMM_2_24
cbt->append(*text);
-#else
- cbt->append_text(*text);
-#endif
if (!entr->value->compare(_value)) {
cbt->set_active_text(*text);
comboSet = true;
diff --git a/src/extension/param/radiobutton.h b/src/extension/param/radiobutton.h
index 645faecaf..0e0f643c9 100644
--- a/src/extension/param/radiobutton.h
+++ b/src/extension/param/radiobutton.h
@@ -51,6 +51,8 @@ public:
virtual void string(std::string &string) const;
+ Glib::ustring value_from_label(const Glib::ustring label);
+
const gchar *get(const SPDocument * /*doc*/, const Inkscape::XML::Node * /*node*/) const { return _value; }
const gchar *set(const gchar *in, SPDocument *doc, Inkscape::XML::Node *node);
diff --git a/src/extension/param/string.cpp b/src/extension/param/string.cpp
index cf2b0f5d5..d6e438db5 100644
--- a/src/extension/param/string.cpp
+++ b/src/extension/param/string.cpp
@@ -10,11 +10,16 @@
# include "config.h"
#endif
-#include <glibmm/value.h>
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/adjustment.h>
#include <gtkmm/box.h>
#include <gtkmm/spinbutton.h>
+#include <glibmm/value.h>
+
#include "xml/node.h"
#include "extension/extension.h"
#include "string.h"
@@ -165,12 +170,7 @@ Gtk::Widget * ParamString::get_widget(SPDocument * doc, Inkscape::XML::Node * no
}
Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
-
-#if WITH_GTKMM_2_22
Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START));
-#else
- Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
-#endif
label->show();
hbox->pack_start(*label, false, false, _indent);
diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp
index 4fd5680aa..1b657f644 100644
--- a/src/extension/prefdialog.cpp
+++ b/src/extension/prefdialog.cpp
@@ -32,16 +32,20 @@ namespace Extension {
/** \brief Creates a new preference dialog for extension preferences
- \param name Name of the Extension who's dialog this is
+ \param name Name of the Extension whose dialog this is
\param help The help string for the extension (NULL if none)
\param controls The extension specific widgets in the dialog
This function initializes the dialog with the name of the extension
in the title. It adds a few buttons and sets up handlers for
- them. It also places the passed in widgets into the dialog.
+ them. It also places the passed-in widgets into the dialog.
*/
PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * controls, Effect * effect) :
- Gtk::Dialog::Dialog(_(name.c_str()), true, true),
+#if WITH_GTKMM_3_0
+ Gtk::Dialog(_(name.c_str()), true),
+#else
+ Gtk::Dialog(_(name.c_str()), true, true),
+#endif
_help(help),
_name(name),
_button_ok(NULL),
@@ -63,7 +67,12 @@ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * co
hbox->pack_start(*controls, true, true, 6);
hbox->show();
+
+#if WITH_GTKMM_3_0
+ this->get_content_area()->pack_start(*hbox, true, true, 6);
+#else
this->get_vbox()->pack_start(*hbox, true, true, 6);
+#endif
/*
Gtk::Button * help_button = add_button(Gtk::Stock::HELP, Gtk::RESPONSE_HELP);
@@ -84,28 +93,50 @@ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * co
_param_preview = Parameter::make(doc->root(), _effect);
}
+#if WITH_GTKMM_3_0
+ Gtk::Separator * sep = Gtk::manage(new Gtk::Separator());
+#else
Gtk::HSeparator * sep = Gtk::manage(new Gtk::HSeparator());
+#endif
+
sep->show();
+
+#if WITH_GTKMM_3_0
+ this->get_content_area()->pack_start(*sep, true, true, 4);
+#else
this->get_vbox()->pack_start(*sep, true, true, 4);
+#endif
hbox = Gtk::manage(new Gtk::HBox());
_button_preview = _param_preview->get_widget(NULL, NULL, &_signal_preview);
_button_preview->show();
hbox->pack_start(*_button_preview, true, true,6);
hbox->show();
+
+#if WITH_GTKMM_3_0
+ this->get_content_area()->pack_start(*hbox, true, true, 6);
+#else
this->get_vbox()->pack_start(*hbox, true, true, 6);
+#endif
Gtk::Box * hbox = dynamic_cast<Gtk::Box *>(_button_preview);
if (hbox != NULL) {
- Gtk::Widget * back = hbox->children().back().get_widget();
- Gtk::CheckButton * cb = dynamic_cast<Gtk::CheckButton *>(back);
- _checkbox_preview = cb;
+#if WITH_GTKMM_3_0
+ _checkbox_preview = dynamic_cast<Gtk::CheckButton *>(hbox->get_children().front());
+#else
+ _checkbox_preview = dynamic_cast<Gtk::CheckButton *>(hbox->children().back().get_widget());
+#endif
}
preview_toggle();
_signal_preview.connect(sigc::mem_fun(this, &PrefDialog::preview_toggle));
}
+ // Set window modality for effects that don't use live preview
+ if (_effect != NULL && _effect->no_live_preview) {
+ set_modal(false);
+ }
+
GtkWidget *dlg = GTK_WIDGET(gobj());
sp_transientize(dlg);
diff --git a/src/extension/prefdialog.h b/src/extension/prefdialog.h
index 943273623..905d35744 100644
--- a/src/extension/prefdialog.h
+++ b/src/extension/prefdialog.h
@@ -10,8 +10,16 @@
#ifndef INKSCAPE_EXTENSION_DIALOG_H__
#define INKSCAPE_EXTENSION_DIALOG_H__
-#include <glibmm/value.h>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
#include <gtkmm/dialog.h>
+#include <glibmm/value.h>
#include <glibmm/ustring.h>
diff --git a/src/extension/script/InkscapeScript.cpp b/src/extension/script/InkscapeScript.cpp
deleted file mode 100644
index 02cd28fa5..000000000
--- a/src/extension/script/InkscapeScript.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * This is a simple mechanism to bind Inkscape to Java, and thence
- * to all of the nice things that can be layered upon that.
- *
- * Authors:
- * Bob Jamison
- *
- * Copyright (C) 2007-2008 Bob Jamison
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-#include "InkscapeScript.h"
-
-
-#include <bind/javabind.h>
-
-
-namespace Inkscape
-{
-namespace Extension
-{
-namespace Script
-{
-
-
-typedef Inkscape::Bind::Value Value;
-
-
-/**
- *
- */
-InkscapeScript::InkscapeScript()
-{
-}
-
-
-
-
-/**
- *
- */
-InkscapeScript::~InkscapeScript()
-{
-}
-
-
-
-
-/**
- * Interprets the script in the 'script' buffer,
- * storing the stdout output in 'output', and any
- * error messages in 'error.' Language is one of the
- * enumerated types in ScriptLanguage above.
- */
-bool InkscapeScript::interpretScript(const Glib::ustring &script,
- Glib::ustring & /*output*/,
- Glib::ustring & /*error*/,
- ScriptLanguage language)
-{
- const char *langname=NULL;
- //if() instead of switch() lets us scope vars
- if (language == InkscapeScript::JAVASCRIPT)
- {
- langname="javascript";
- }
- else if (language == InkscapeScript::PYTHON)
- {
- langname="python";
- }
- else if (language == InkscapeScript::RUBY)
- {
- langname="ruby";
- }
- else
- {
- g_warning("interpretScript: Unknown Script Language type: %d\n",
- language);
- return false;
- }
-
- Inkscape::Bind::JavaBindery *binder =
- Inkscape::Bind::JavaBindery::getInstance();
- if (!binder->loadJVM()) //idempotent
- {
- g_warning("interpretScript: unable to start JVM\n");
- return false;
- }
- std::vector<Value> parms;
- Value retval;
- Value parm;
- parm.setString(langname);
- parms.push_back(parm);
- parm.setString(script);
- parms.push_back(parm);
-
- //binder->stdOutClear();
- //binder->stdErrClear();
- bool ret = binder->callStatic(Value::BIND_BOOLEAN,
- "org/inkscape/cmn/ScriptRunner",
- "run",
- "(Ljava/lang/String;Ljava/lang/String;)Z",
- parms,
- retval);
- //output = binder->stdOutGet();
- //error = binder->stdErrGet();
-
- if (!ret)
- {
- g_warning("interpretScript: failed\n");
- return false;
- }
-
- return true;
-}
-
-
-/**
- * Interprets the script in the named file,
- * storing the stdout output in 'output', and any
- * error messages in 'error.' Language is one of the
- * enumerated types in ScriptLanguage above.
- */
-bool InkscapeScript::interpretFile(const Glib::ustring &fname,
- Glib::ustring & /*output*/,
- Glib::ustring & /*error*/,
- ScriptLanguage language)
-{
- const char *langname=NULL;
- //if() instead of switch() lets us scope vars
- if (language == InkscapeScript::JAVASCRIPT)
- {
- langname="Javascript";
- }
- else if (language == InkscapeScript::PYTHON)
- {
- langname="Python";
- }
- else if (language == InkscapeScript::RUBY)
- {
- langname="Ruby";
- }
- else
- {
- g_warning("interpretFile: Unknown Script Language type: %d\n",
- language);
- return false;
- }
-
- Inkscape::Bind::JavaBindery *binder =
- Inkscape::Bind::JavaBindery::getInstance();
- if (!binder->loadJVM()) //idempotent
- {
- g_warning("interpretFile: unable to start JVM\n");
- return false;
- }
- std::vector<Value> parms;
- Value retval;
- Value parm;
- parm.setString(langname);
- parms.push_back(parm);
- parm.setString(fname);
- parms.push_back(parm);
-
- //binder->stdOutClear();
- //binder->stdErrClear();
- bool ret = binder->callStatic(Value::BIND_BOOLEAN,
- "org/inkscape/cmn/ScriptRunner",
- "runFile",
- "(Ljava/lang/String;Ljava/lang/String;)Z",
- parms,
- retval);
- //output = binder->stdOutGet();
- //error = binder->stdErrGet();
-
- if (!ret)
- {
- g_warning("interpretFile: failed\n");
- return false;
- }
-
- return true;
-}
-
-
-
-
-
-
-
-
-
-} // namespace Script
-} // namespace Extension
-} // namespace Inkscape
-
-//#########################################################################
-//# E N D O F F I L E
-//#########################################################################
-
-/*
- 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/script/InkscapeScript.h b/src/extension/script/InkscapeScript.h
deleted file mode 100644
index 2ebeb1b19..000000000
--- a/src/extension/script/InkscapeScript.h
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef SEEN_INKSCAPE_SCRIPT_H
-#define SEEN_INKSCAPE_SCRIPT_H
-
-/*
- * Authors:
- * Bob Jamison <rjamison@titan.com>
- *
- * Copyright (C) 2004-2008 Bob Jamison
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include "config.h"
-
-#include <glibmm.h>
-
-namespace Inkscape
-{
-namespace Extension
-{
-namespace Script
-{
-
-
-
-/**
- * Inkscape Scripting container.
- * This class is used to run scripts, either from a file or buffer.
- */
-class InkscapeScript
-{
-public:
-
- /**
- * Which type of language?
- */
- typedef enum
- {
- JAVASCRIPT,
- PYTHON,
- RUBY
- } ScriptLanguage;
-
- /**
- * Creates a generic script interpreter.
- */
- InkscapeScript();
-
- /**
- * Destructor
- */
- virtual ~InkscapeScript();
-
- /**
- * Interprets the script in the 'script' buffer,
- * storing the stdout output in 'output', and any
- * error messages in 'error.' Language is one of the
- * enumerated types in ScriptLanguage above.
- */
- bool interpretScript(const Glib::ustring &script,
- Glib::ustring &output,
- Glib::ustring &error,
- ScriptLanguage language);
-
- /**
- * Interprets the script in the named file,
- * storing the stdout output in 'output', and any
- * error messages in 'error.' Language is one of the
- * enumerated types in ScriptLanguage above.
- */
- bool interpretFile(const Glib::ustring &fname,
- Glib::ustring &output,
- Glib::ustring &error,
- ScriptLanguage language);
-
-
-
-}; //class InkscapeScript
-
-
-
-
-} // namespace Script
-} // namespace Extension
-} // namespace Inkscape
-
-
-
-#endif /* __INKSCAPE_SCRIPT_H__ */
-
-/*
- 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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/extension/script/Makefile_insert b/src/extension/script/Makefile_insert
deleted file mode 100644
index c0bd91e81..000000000
--- a/src/extension/script/Makefile_insert
+++ /dev/null
@@ -1,6 +0,0 @@
-## Makefile.am fragment sourced by src/Makefile.am.
-
-ink_common_sources += \
- extension/script/InkscapeScript.h \
- extension/script/InkscapeScript.cpp
-
diff --git a/src/extension/script/makefile.in b/src/extension/script/makefile.in
deleted file mode 100644
index f4857a9e3..000000000
--- a/src/extension/script/makefile.in
+++ /dev/null
@@ -1,17 +0,0 @@
-# Convenience stub makefile to call the real Makefile.
-
-@SET_MAKE@
-
-OBJEXT = @OBJEXT@
-
-# Explicit so that it's the default rule.
-all:
- cd ../.. && $(MAKE) extension/script/all
-
-clean %.a %.$(OBJEXT):
- cd ../.. && $(MAKE) extension/script/$@
-
-.PHONY: all clean
-
-.SUFFIXES:
-.SUFFIXES: .a .$(OBJEXT)
diff --git a/src/extension/system.cpp b/src/extension/system.cpp
index 476499385..7a50826ca 100644
--- a/src/extension/system.cpp
+++ b/src/extension/system.cpp
@@ -21,6 +21,8 @@
#endif
#include <interface.h>
+#include <unistd.h>
+#include <glibmm/miscutils.h>
#include "system.h"
#include "preferences.h"
@@ -68,24 +70,6 @@ static Extension *build_from_reprdoc(Inkscape::XML::Document *doc, Implementatio
*/
SPDocument *open(Extension *key, gchar const *filename)
{
- // Convert to absolute pathname to tolerate chdir().
- bool relpath = (filename[0] != '/');
-#ifdef WIN32
- relpath &= (filename[0] != '\\') && !(isalpha(filename[0]) && (filename[1] == ':'));
-#endif
-
- if (relpath) {
- gchar * curdir = NULL;
-#ifndef WIN32
- curdir = getcwd(NULL, 0);
-#else
- curdir = _getcwd(NULL, 0);
-#endif
-
- filename = g_build_filename(curdir, filename, NULL);
- free(curdir);
- }
-
Input *imod = NULL;
if (key == NULL) {
@@ -113,9 +97,9 @@ SPDocument *open(Extension *key, gchar const *filename)
bool show = true;
if (strlen(imod->get_id()) > 27) {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- Glib::ustring attr = prefs->getString("/dialogs/import/link");
+ bool ask = prefs->getBool("/dialogs/import/ask");
Glib::ustring id = Glib::ustring(imod->get_id(), 28);
- if (strcmp(attr.c_str(), "ask") != 0 and strcmp(id.c_str(), "org.inkscape.input.gdkpixbuf") == 0) {
+ if (!ask and id.compare( "org.inkscape.input.gdkpixbuf") == 0) {
show = false;
imod->set_gui(false);
}
@@ -127,13 +111,11 @@ SPDocument *open(Extension *key, gchar const *filename)
}
if (!imod->prefs(filename)) {
- if (relpath){
- free((void *) filename);
- }
return NULL;
}
SPDocument *doc = imod->open(filename);
+
if (!doc) {
throw Input::open_failed();
}
@@ -142,7 +124,7 @@ SPDocument *open(Extension *key, gchar const *filename)
if ( inkscape_use_gui() ) {
sp_ui_error_dialog(_("Format autodetect failed. The file is being opened as SVG."));
} else {
- g_warning(_("Format autodetect failed. The file is being opened as SVG."));
+ g_warning("%s", _("Format autodetect failed. The file is being opened as SVG."));
}
}
@@ -151,9 +133,6 @@ SPDocument *open(Extension *key, gchar const *filename)
imod->set_gui(true);
}
- if (relpath){
- free((void *) filename);
- }
return doc;
}
@@ -301,10 +280,9 @@ save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension,
// remember attributes in case this is an unofficial save and/or overwrite fails
gchar *saved_uri = g_strdup(doc->getURI());
- bool saved_modified = false;
gchar *saved_output_extension = NULL;
gchar *saved_dataloss = NULL;
- saved_modified = doc->isModifiedSinceSave();
+ bool saved_modified = doc->isModifiedSinceSave();
saved_output_extension = g_strdup(get_file_save_extension(save_method).c_str());
saved_dataloss = g_strdup(repr->attribute("inkscape:dataloss"));
if (official) {
@@ -614,10 +592,14 @@ get_file_save_extension (Inkscape::Extension::FileSaveMethod method) {
case FILE_SAVE_METHOD_INKSCAPE_SVG:
extension = SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE;
break;
+ case FILE_SAVE_METHOD_EXPORT:
+ /// \todo no default extension set for Export? defaults to SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE is ok?
+ break;
}
- if(extension.empty())
+ if(extension.empty()) {
extension = SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE;
+ }
return extension;
}
@@ -657,13 +639,19 @@ get_file_save_path (SPDocument *doc, FileSaveMethod method) {
// leave this as a choice to the user.
path = prefs->getString("/dialogs/save_as/path");
}
+ break;
+ case FILE_SAVE_METHOD_EXPORT:
+ /// \todo no default path set for Export?
+ // defaults to g_get_home_dir()
+ break;
}
- if(path.empty())
+ if(path.empty()) {
path = g_get_home_dir(); // Is this the most sensible solution? Note that we should avoid
// g_get_current_dir because this leads to problems on OS X where
// Inkscape opens the dialog inside application bundle when it is
// invoked for the first teim.
+ }
return path;
}
@@ -680,6 +668,7 @@ store_file_extension_in_prefs (Glib::ustring extension, FileSaveMethod method) {
prefs->setString("/dialogs/save_copy/default", extension);
break;
case FILE_SAVE_METHOD_INKSCAPE_SVG:
+ case FILE_SAVE_METHOD_EXPORT:
// do nothing
break;
}
@@ -697,6 +686,7 @@ store_save_path_in_prefs (Glib::ustring path, FileSaveMethod method) {
prefs->setString("/dialogs/save_copy/path", path);
break;
case FILE_SAVE_METHOD_INKSCAPE_SVG:
+ case FILE_SAVE_METHOD_EXPORT:
// do nothing
break;
}
diff --git a/src/extension/timer.cpp b/src/extension/timer.cpp
index 3941ddcfc..e4e8632d2 100644
--- a/src/extension/timer.cpp
+++ b/src/extension/timer.cpp
@@ -10,7 +10,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
+#include <glibmm/main.h>
#include "extension.h"
#include "timer.h"