metafile-print.cpp revision 440e7182af0764dabf2219f14c5b8ed58949953e
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith/** @file
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith * @brief Metafile printing - common routines
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *//*
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith * Authors:
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith * Krzysztof KosiƄski <tweenk.pl@gmail.com>
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith * Copyright (C) 2013 Authors
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith * Released under GNU GPL, read the file 'COPYING' for more information
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith */
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#ifdef HAVE_CONFIG_H
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith# include "config.h"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#endif
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include <cstring>
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include <fstream>
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include <glib.h>
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include <glibmm/miscutils.h>
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include <2geom/rect.h>
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include <2geom/curves.h>
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include <2geom/svg-path-parser.h>
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include "extension/internal/metafile-print.h"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include "extension/print.h"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include "path-prefix.h"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include "sp-gradient.h"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include "sp-image.h"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include "sp-linear-gradient.h"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include "sp-pattern.h"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#include "sp-radial-gradient.h"
5c45bb188ab729e501e48732842cb9de6a9813beAlex Valavanis#include "style.h"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
a4142717644b885998f4de2b27be4e8648315decMarkus Engelnamespace Inkscape {
a4142717644b885998f4de2b27be4e8648315decMarkus Engelnamespace Extension {
a4142717644b885998f4de2b27be4e8648315decMarkus Engelnamespace Internal {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
a4142717644b885998f4de2b27be4e8648315decMarkus Engelbool PrintMetafile::_ppt_fontfix_read = false;
a4142717644b885998f4de2b27be4e8648315decMarkus EngelPrintMetafile::FontfixMap PrintMetafile::_ppt_fixable_fonts;
a4142717644b885998f4de2b27be4e8648315decMarkus Engel
a4142717644b885998f4de2b27be4e8648315decMarkus EngelPrintMetafile::~PrintMetafile()
a4142717644b885998f4de2b27be4e8648315decMarkus Engel{
a4142717644b885998f4de2b27be4e8648315decMarkus Engel#ifndef G_OS_WIN32
a4142717644b885998f4de2b27be4e8648315decMarkus Engel // restore default signal handling for SIGPIPE
a4142717644b885998f4de2b27be4e8648315decMarkus Engel (void) signal(SIGPIPE, SIG_DFL);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#endif
a4142717644b885998f4de2b27be4e8648315decMarkus Engel return;
a4142717644b885998f4de2b27be4e8648315decMarkus Engel}
a4142717644b885998f4de2b27be4e8648315decMarkus Engel
a4142717644b885998f4de2b27be4e8648315decMarkus Engelbool PrintMetafile::textToPath(Inkscape::Extension::Print *ext)
a4142717644b885998f4de2b27be4e8648315decMarkus Engel{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return ext->get_param_bool("textToPath");
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smithunsigned int PrintMetafile::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (!m_tr_stack.empty()) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith Geom::Affine tr_top = m_tr_stack.top();
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith m_tr_stack.push(transform * tr_top);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith } else {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith m_tr_stack.push(transform);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
6b0fbf10b982696648debeede2b57f2b32a6a958Alex Valavanis return 1;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smithunsigned int PrintMetafile::release(Inkscape::Extension::Print * /*mod*/)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith m_tr_stack.pop();
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return 1;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smithbool PrintMetafile::_load_ppt_fontfix_data() //this is not called by any other source files
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith static bool ppt_fontfix_available = false;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (_ppt_fontfix_read) return ppt_fontfix_available;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith _ppt_fontfix_read = true;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith // add default entry
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith _ppt_fixable_fonts.insert(std::make_pair(Glib::ustring(""), FontfixParams()));
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith std::string fontfix_path = Glib::build_filename(INKSCAPE_EXTENSIONDIR, "fontfix.conf");
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith std::ifstream fontfix_file(fontfix_path.c_str(), std::ios::in);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (!fontfix_file.is_open()) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith g_warning("Unable to open PowerPoint fontfix file: %s\n"
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith "PowerPoint ungrouping compensation in WMF/EMF export will not be available.",
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith fontfix_path.c_str());
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return (ppt_fontfix_available = false);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL));
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith setlocale(LC_NUMERIC, "C");
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith std::string instr;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith while (std::getline(fontfix_file, instr)) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (instr[0] == '#') {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith continue;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith // not a comment, get the 4 values from the line
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith FontfixParams params;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith char fontname[128];
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith int elements = sscanf(instr.c_str(), "%lf %lf %lf %127[^\n]",
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith &params.f1, &params.f2, &params.f3, &fontname[0]);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (elements != 4) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith g_warning("Malformed line in %s: %s\n", fontfix_path.c_str(), instr.c_str());
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith continue;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith _ppt_fixable_fonts.insert(std::make_pair(Glib::ustring(fontname), params));
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith fontfix_file.close(); // not strictly necessary
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith setlocale(LC_NUMERIC, oldlocale);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith g_free(oldlocale);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return (ppt_fontfix_available = true);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith// Finds font fix parameters for the given fontname.
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smithvoid PrintMetafile::_lookup_ppt_fontfix(Glib::ustring const &fontname, FontfixParams &params)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (!_ppt_fontfix_read) _load_ppt_fontfix_data();
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith FontfixMap::iterator f = _ppt_fixable_fonts.find(fontname);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (f != _ppt_fixable_fonts.end()) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith params = f->second;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
8dc0b6629da67892f16b8b858244ae043f3c89bbJazzyNico
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn SmithU_COLORREF PrintMetafile::_gethexcolor(uint32_t color)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith U_COLORREF out;
253a831f0fda7107ad98c474e21b71e90592d0f2Alex Valavanis out = U_RGB(
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith (color >> 16) & 0xFF,
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith (color >> 8) & 0xFF,
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith (color >> 0) & 0xFF
253a831f0fda7107ad98c474e21b71e90592d0f2Alex Valavanis );
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return out;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
253a831f0fda7107ad98c474e21b71e90592d0f2Alex Valavanis// Translate Inkscape weights to EMF weights.
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smithuint32_t PrintMetafile::_translate_weight(unsigned inkweight)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith switch (inkweight) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith // 400 is tested first, as it is the most common case
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith case SP_CSS_FONT_WEIGHT_400: return U_FW_NORMAL;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith case SP_CSS_FONT_WEIGHT_100: return U_FW_THIN;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith case SP_CSS_FONT_WEIGHT_200: return U_FW_EXTRALIGHT;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith case SP_CSS_FONT_WEIGHT_300: return U_FW_LIGHT;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith case SP_CSS_FONT_WEIGHT_500: return U_FW_MEDIUM;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith case SP_CSS_FONT_WEIGHT_600: return U_FW_SEMIBOLD;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith case SP_CSS_FONT_WEIGHT_700: return U_FW_BOLD;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith case SP_CSS_FONT_WEIGHT_800: return U_FW_EXTRABOLD;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith case SP_CSS_FONT_WEIGHT_900: return U_FW_HEAVY;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith default: return U_FW_NORMAL;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith/* opacity weighting of two colors as float. v1 is the color, op is its opacity, v2 is the background color */
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smithinline float opweight(float v1, float v2, float op)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return v1 * op + v2 * (1.0 - op);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn SmithU_COLORREF PrintMetafile::avg_stop_color(SPGradient *gr)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
253a831f0fda7107ad98c474e21b71e90592d0f2Alex Valavanis U_COLORREF cr;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith int last = gr->vector.stops.size() - 1;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (last >= 1) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith float rgbs[3];
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith float rgbe[3];
253a831f0fda7107ad98c474e21b71e90592d0f2Alex Valavanis float ops, ope;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith ops = gr->vector.stops[0 ].opacity;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith ope = gr->vector.stops[last].opacity;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs);
253a831f0fda7107ad98c474e21b71e90592d0f2Alex Valavanis sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith cr = U_RGB(
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith 255 * ((opweight(rgbs[0], gv.rgb[0], ops) + opweight(rgbe[0], gv.rgb[0], ope)) / 2.0),
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith 255 * ((opweight(rgbs[1], gv.rgb[1], ops) + opweight(rgbe[1], gv.rgb[1], ope)) / 2.0),
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith 255 * ((opweight(rgbs[2], gv.rgb[2], ops) + opweight(rgbe[2], gv.rgb[2], ope)) / 2.0)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith );
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith } else {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith cr = U_RGB(0, 0, 0); // The default fill
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return cr;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn SmithU_COLORREF PrintMetafile::weight_opacity(U_COLORREF c1)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith float opa = c1.Reserved / 255.0;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith U_COLORREF result = U_RGB(
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith 255 * opweight((float)c1.Red / 255.0, gv.rgb[0], opa),
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith 255 * opweight((float)c1.Green / 255.0, gv.rgb[1], opa),
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith 255 * opweight((float)c1.Blue / 255.0, gv.rgb[2], opa)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith );
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return result;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith/* t between 0 and 1, values outside that range use the nearest limit */
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn SmithU_COLORREF PrintMetafile::weight_colors(U_COLORREF c1, U_COLORREF c2, double t)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b))
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith U_COLORREF result;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith t = ( t > 1.0 ? 1.0 : ( t < 0.0 ? 0.0 : t));
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith result.Red = clrweight(c1.Red, c2.Red, t);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith result.Green = clrweight(c1.Green, c2.Green, t);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith result.Blue = clrweight(c1.Blue, c2.Blue, t);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith result.Reserved = clrweight(c1.Reserved, c2.Reserved, t);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith // now handle the opacity, mix the RGB with background at the weighted opacity
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (result.Reserved != 255) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith result = weight_opacity(result);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return result;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith// Extract hatchType, hatchColor from a name like
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith// EMFhatch<hatchType>_<hatchColor>
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith// Where the first one is a number and the second a color in hex.
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith// hatchType and hatchColor have been set with defaults before this is called.
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith//
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smithvoid PrintMetafile::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith int val;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith uint32_t hcolor = 0;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith uint32_t bcolor = 0;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith // name should be EMFhatch or WMFhatch but *MFhatch will be accepted
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (0 != strncmp(&name[1], "MFhatch", 7)) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return; // not anything we can parse
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith name += 8; // EMFhatch already detected
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith val = 0;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith while (*name && isdigit(*name)) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith val = 10 * val + *name - '0';
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith name++;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *hatchType = val;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (*name != '_' || val > U_HS_DITHEREDBKCLR) { // wrong syntax, cannot classify
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *hatchType = -1;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith } else {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith name++;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (2 != sscanf(name, "%X_%X", &hcolor, &bcolor)) { // not a pattern with background
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (1 != sscanf(name, "%X", &hcolor)) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *hatchType = -1; // not a pattern, cannot classify
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
bf9ec3e969ba6b11cbbc613545aedc63cc886973Matthew Petroff *hatchColor = _gethexcolor(hcolor);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith } else {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *hatchColor = _gethexcolor(hcolor);
add38d633bbf8ef881bdb908735ea27385c554b8Matthew Petroff *bkColor = _gethexcolor(bcolor);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith usebk = true;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (*hatchType > U_HS_SOLIDCLR) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *hatchType = U_HS_SOLIDCLR;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith//
bf9ec3e969ba6b11cbbc613545aedc63cc886973Matthew Petroff// Recurse down from a brush pattern, try to figure out what it is.
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith// If an image is found set a pointer to the epixbuf, else set that to NULL
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith// If a pattern is found with a name like [EW]MFhatch3_3F7FFF return hatchType=3, hatchColor=3F7FFF (as a uint32_t),
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith// otherwise hatchType is set to -1 and hatchColor is not defined.
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith//
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smithvoid PrintMetafile::brush_classify(SPObject *parent, int depth, Inkscape::Pixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor)
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith{
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (depth == 0) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *epixbuf = NULL;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *hatchType = -1;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *hatchColor = U_RGB(0, 0, 0);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *bkColor = U_RGB(255, 255, 255);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
bf9ec3e969ba6b11cbbc613545aedc63cc886973Matthew Petroff depth++;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith // first look along the pattern chain, if there is one
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (SP_IS_PATTERN(parent)) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith if (SP_IS_IMAGE(pat_i)) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *epixbuf = ((SPImage *)pat_i)->pixbuf;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith char temp[32]; // large enough
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith strncpy(temp, pat_i->getAttribute("id"), sizeof(temp)-1); // Some names may be longer than [EW]MFhatch#_######
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith temp[sizeof(temp)-1] = '\0';
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith hatch_classify(temp, hatchType, hatchColor, bkColor);
02db7fad736ff0812658ef9c5f82ac2e64ffdefcAlex Valavanis if (*hatchType != -1) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith // still looking? Look at this pattern's children, if there are any
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith SPObject *child = pat_i->firstChild();
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith while (child && !(*epixbuf) && (*hatchType == -1)) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
6b0fbf10b982696648debeede2b57f2b32a6a958Alex Valavanis child = child->getNext();
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith } else if (SP_IS_IMAGE(parent)) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith *epixbuf = ((SPImage *)parent)->pixbuf;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith return;
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith } else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either.
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith SPObject *child = parent->firstChild();
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith while (child && !(*epixbuf) && (*hatchType == -1)) {
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith child = child->getNext();
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith }
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith}
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smith//swap R/B in 4 byte pixel
2f5f997e354e7f4a02b6818bdc68fbece5cb237dJohn Smithvoid 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);
Geom::PathVector 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);
Geom::PathVector 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);
Geom::PathVector 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)
{
Geom::PathVector 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 :