From e5c952578e75b4071dc98042c4fa15d96ac9ce8b Mon Sep 17 00:00:00 2001 From: ishmal Date: Thu, 6 Jul 2006 17:13:04 +0000 Subject: [PATCH] save updates, and put to sleep for a while --- src/extension/internal/odf.cpp | 827 +++++++++++++++++++++++---------- src/extension/internal/odf.h | 57 ++- 2 files changed, 646 insertions(+), 238 deletions(-) diff --git a/src/extension/internal/odf.cpp b/src/extension/internal/odf.cpp index 7610caef1..48e217bd8 100644 --- a/src/extension/internal/odf.cpp +++ b/src/extension/internal/odf.cpp @@ -58,6 +58,8 @@ #include "xml/attribute-record.h" #include "sp-image.h" #include "sp-gradient.h" +#include "sp-stop.h" +#include "gradient-chemistry.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" #include "sp-path.h" @@ -1116,144 +1118,6 @@ OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node) } } - - - //###### Get style - SPStyle *style = SP_OBJECT_STYLE(item); - if (style && id.size()>0) - { - bool isGradient = false; - - StyleInfo si; - //## Style. Look in writeStyle() below to see what info - // we need to read into StyleInfo. Note that we need to - // determine whether information goes into a style element - // or a gradient element. - //## FILL - if (style->fill.type == SP_PAINT_TYPE_COLOR) - { - guint32 fillCol = - sp_color_get_rgba32_ualpha(&style->fill.value.color, 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"; - double opacityPercent = 100.0 * - (SP_SCALE24_TO_FLOAT(style->fill_opacity.value)); - snprintf(buf, 15, "%.3f%%", opacityPercent); - si.fillOpacity = buf; - } - else if (style->fill.type == SP_PAINT_TYPE_PAINTSERVER) - { - //## Gradient. Look in writeStyle() below to see what info - // we need to read into GradientInfo. - if (!SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))) - return; - isGradient = true; - GradientInfo gi; - SPGradient *gradient = SP_GRADIENT(SP_STYLE_FILL_SERVER(style)); - if (SP_IS_LINEARGRADIENT(gradient)) - { - gi.style = "linear"; - SPLinearGradient *linGrad = SP_LINEARGRADIENT(gradient); - gi.x1 = linGrad->x1.value; - gi.y1 = linGrad->y1.value; - gi.x2 = linGrad->x2.value; - gi.y2 = linGrad->y2.value; - } - 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; - } - else - { - g_warning("not a supported gradient type"); - } - - //Look for existing identical style; - bool gradientMatch = false; - std::vector::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()); - gradientLookupTable[id] = gradientName; - gradientMatch = true; - break; - } - } - //None found, make a new pair or entries - if (!gradientMatch) - { - char buf[16]; - snprintf(buf, 15, "gradient%d", (int)gradientTable.size()); - Glib::ustring gradientName = buf; - gi.name = gradientName; - gradientTable.push_back(gi); - gradientLookupTable[id] = gradientName; - } - } - - //## STROKE - if (style->stroke.type == SP_PAINT_TYPE_COLOR) - { - guint32 strokeCol = - sp_color_get_rgba32_ualpha(&style->stroke.value.color, 0); - char buf[16]; - int r = (strokeCol >> 24) & 0xff; - int g = (strokeCol >> 16) & 0xff; - int b = (strokeCol >> 8) & 0xff; - snprintf(buf, 15, "#%02x%02x%02x", r, g, b); - si.strokeColor = buf; - snprintf(buf, 15, "%.3fpt", style->stroke_width.value); - si.strokeWidth = buf; - si.stroke = "solid"; - double opacityPercent = 100.0 * - (SP_SCALE24_TO_FLOAT(style->stroke_opacity.value)); - snprintf(buf, 15, "%.3f%%", opacityPercent); - si.strokeOpacity = buf; - } - - if (!isGradient) - { - //Look for existing identical style; - bool styleMatch = false; - std::vector::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; - } - } - //None found, make a new pair or entries - if (!styleMatch) - { - char buf[16]; - snprintf(buf, 15, "style%d", (int)styleTable.size()); - Glib::ustring styleName = buf; - si.name = styleName; - styleTable.push_back(si); - styleLookupTable[id] = styleName; - } - } - } - for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next()) preprocess(zf, child); @@ -1289,6 +1153,7 @@ bool OdfOutput::writeManifest(ZipFile &zf) outs.printf("\n"); outs.printf(" \n"); outs.printf(" \n"); + outs.printf(" \n"); outs.printf(" \n"); outs.printf(" \n"); std::map::iterator iter; @@ -1412,22 +1277,10 @@ bool OdfOutput::writeMeta(ZipFile &zf) * This is called just before writeTree(), since it will write style and * gradient information above the tag in the content.xml file */ -bool OdfOutput::writeStyle(Writer &outs) +bool OdfOutput::writeStyle(ZipFile &zf) { - outs.printf("\n"); - outs.printf("\n"); - outs.printf("\n"); - outs.printf("\n"); - outs.printf(" \n"); - outs.printf("\n"); - outs.printf("\n"); - outs.printf(" \n"); - outs.printf("\n"); + BufferOutputStream bouts; + OutputStreamWriter outs(bouts); /* ========================================================== @@ -1490,27 +1343,33 @@ bool OdfOutput::writeStyle(Writer &outs) 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("\n", + outs.printf(" svg:x2=\"%05.3fcm\" svg:y2=\"%05.3fcm\"\n", gi.x2, gi.y2); + outs.printf(" svg:gradientUnits=\"objectBoundingBox\">\n"); outs.printf(" \n"); outs.printf(" \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("\n"); } else if (gi.style == "radial") @@ -1527,29 +1386,35 @@ bool OdfOutput::writeStyle(Writer &outs) draw:border="0%"/> =================================================================== */ + if (gi.stops.size() < 2) + { + g_warning("Need at least 2 tops for a radial gradient"); + continue; + } outs.printf("\n", + outs.printf(" svg:r=\"%05.3f\"\n", gi.r); + outs.printf(" svg:gradientUnits=\"objectBoundingBox\">\n"); outs.printf(" \n"); outs.printf(" \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("\n"); } else @@ -1572,6 +1437,36 @@ bool OdfOutput::writeStyle(Writer &outs) outs.printf("\n"); outs.printf("\n"); outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\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; } @@ -1652,13 +1547,306 @@ writePath(Writer &outs, NArtBpath const *bpath, +bool OdfOutput::processStyle(Writer &outs, SPItem *item, + const Glib::ustring &id) +{ + SPStyle *style = item->style; + + StyleInfo si; + + //## FILL + if (style->fill.type == SP_PAINT_TYPE_COLOR) + { + guint32 fillCol = + sp_color_get_rgba32_ualpha(&style->fill.value.color, 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"; + double opacityPercent = 100.0 * + (SP_SCALE24_TO_FLOAT(style->fill_opacity.value)); + snprintf(buf, 15, "%.3f%%", opacityPercent); + si.fillOpacity = buf; + } + + //## STROKE + if (style->stroke.type == SP_PAINT_TYPE_COLOR) + { + guint32 strokeCol = + sp_color_get_rgba32_ualpha(&style->stroke.value.color, 0); + char buf[16]; + int r = (strokeCol >> 24) & 0xff; + int g = (strokeCol >> 16) & 0xff; + int b = (strokeCol >> 8) & 0xff; + snprintf(buf, 15, "#%02x%02x%02x", r, g, b); + si.strokeColor = buf; + snprintf(buf, 15, "%.3fpt", style->stroke_width.value); + si.strokeWidth = buf; + si.stroke = "solid"; + double opacityPercent = 100.0 * + (SP_SCALE24_TO_FLOAT(style->stroke_opacity.value)); + snprintf(buf, 15, "%.3f%%", opacityPercent); + si.strokeOpacity = buf; + } + + //Look for existing identical style; + bool styleMatch = false; + std::vector::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 + if (styleMatch) + return false; + + char buf[16]; + snprintf(buf, 15, "style%d", (int)styleTable.size()); + Glib::ustring styleName = buf; + si.name = styleName; + styleTable.push_back(si); + styleLookupTable[id] = styleName; + + outs.printf("\n"); + outs.printf(" \n"); + outs.printf("\n"); + + return true; +} + + + + +bool OdfOutput::processGradient(Writer &outs, SPItem *item, + const Glib::ustring &id, NR::Matrix &tf) +{ + SPStyle *style = item->style; + + //## Gradient. Look in writeStyle() below to see what info + // we need to read into GradientInfo. + if (!SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))) + return false; + + SPGradient *gradient = SP_GRADIENT(SP_STYLE_FILL_SERVER(style)); + + GradientInfo gi; + + SPGradient *grvec = sp_gradient_get_vector(gradient, FALSE); + for (SPStop *stop = sp_first_stop(grvec) ; + stop ; stop = sp_next_stop(stop)) + { + unsigned long rgba = sp_stop_get_rgba32(stop); + unsigned long rgb = (rgba >> 8) & 0xffffff; + double opacity = ((double)(rgba & 0xff)) / 256.0; + GradientStop gs(rgb, opacity); + gi.stops.push_back(gs); + } + + if (SP_IS_LINEARGRADIENT(gradient)) + { + gi.style = "linear"; + SPLinearGradient *linGrad = SP_LINEARGRADIENT(gradient); + /* + NR::Point p1(linGrad->x1.value, linGrad->y1.value); + p1 = p1 * tf; + gi.x1 = p1[NR::X]; + gi.y1 = p1[NR::Y]; + NR::Point p2(linGrad->x2.value, linGrad->y2.value); + p2 = p2 * tf; + gi.x2 = p2[NR::X]; + gi.y2 = p2[NR::Y]; + */ + gi.x1 = linGrad->x1.value; + gi.y1 = linGrad->y1.value; + gi.x2 = linGrad->x2.value; + gi.y2 = linGrad->y2.value; + } + 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; + } + else + { + g_warning("not a supported gradient type"); + return false; + } + + //Look for existing identical style; + bool gradientMatch = false; + std::vector::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()); + 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; + gi.name = gradientName; + gradientTable.push_back(gi); + gradientLookupTable[id] = gradientName; + + int gradientCount = gradientTable.size(); + + if (gi.style == "linear") + { + /* + =================================================================== + LINEAR gradient. We need something that looks like this: + + =================================================================== + */ + if (gi.stops.size() < 2) + { + g_warning("Need at least 2 stops for a linear gradient"); + return false;; + } + outs.printf("\n", + gi.x2 * pxToCm, gi.y2 * pxToCm); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf("\n"); + } + else if (gi.style == "radial") + { + /* + =================================================================== + RADIAL gradient. We need something that looks like this: + + + =================================================================== + */ + if (gi.stops.size() < 2) + { + g_warning("Need at least 2 stops for a radial gradient"); + return false; + } + outs.printf("\n", + gi.r); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf("\n"); + } + else + { + g_warning("unsupported gradient style '%s'", gi.style.c_str()); + return false; + } + outs.printf("\n"); + outs.printf(" \n"); + outs.printf("\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(). */ -bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node) +bool OdfOutput::writeTree(Writer &couts, Writer &souts, + Inkscape::XML::Node *node) { //# Get the SPItem, if applicable SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(node); @@ -1694,14 +1882,15 @@ bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node) //# Do our stuff SPCurve *curve = NULL; - //g_message("##### %s #####", nodeName.c_str()); + if (nodeName == "svg" || nodeName == "svg:svg") { //# Iterate through the children - for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next()) + for (Inkscape::XML::Node *child = node->firstChild() ; + child ; child = child->next()) { - if (!writeTree(outs, child)) + if (!writeTree(couts, souts, child)) return false; } return true; @@ -1709,22 +1898,41 @@ bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node) else if (nodeName == "g" || nodeName == "svg:g") { if (id.size() > 0) - outs.printf("\n", id.c_str()); + couts.printf("\n", id.c_str()); else - outs.printf("\n"); + couts.printf("\n"); //# Iterate through the children - for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next()) + for (Inkscape::XML::Node *child = node->firstChild() ; + child ; child = child->next()) { - if (!writeTree(outs, child)) + if (!writeTree(couts, souts, child)) return false; } if (id.size() > 0) - outs.printf(" \n", id.c_str()); + couts.printf(" \n", id.c_str()); else - outs.printf("\n"); + couts.printf("\n"); return true; } - else if (nodeName == "image" || nodeName == "svg:image") + + //###################################### + //# 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()); + if (nodeName == "image" || nodeName == "svg:image") { if (!SP_IS_IMAGE(item)) { @@ -1760,31 +1968,31 @@ bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node) } Glib::ustring newName = iter->second; - outs.printf(" 0) - outs.printf("id=\"%s\" ", id.c_str()); - outs.printf("draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:layer=\"layout\" "); + 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 - outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ", + couts.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ", iwidth, iheight); if (itemTransformString.size() > 0) { - outs.printf("draw:transform=\"%s translate(%.3fcm, %.3fcm)\" ", + couts.printf("draw:transform=\"%s translate(%.3fcm, %.3fcm)\" ", itemTransformString.c_str(), ix, iy); } else { - outs.printf("draw:transform=\"translate(%.3fcm, %.3fcm)\" ", + couts.printf("draw:transform=\"translate(%.3fcm, %.3fcm)\" ", ix, iy); } - outs.printf(">\n"); - outs.printf(" \n"); + couts.printf(" \n"); - outs.printf(" \n"); - outs.printf(" \n"); - outs.printf("\n"); + couts.printf(" xlink:show=\"embed\" xlink:actuate=\"onLoad\">\n"); + couts.printf(" \n"); + couts.printf(" \n"); + couts.printf("\n"); return true; } else if (SP_IS_SHAPE(item)) @@ -1801,16 +2009,16 @@ bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node) { //### Default output - outs.printf("0) - outs.printf("id=\"%s\" ", id.c_str()); + couts.printf("id=\"%s\" ", id.c_str()); std::map::iterator siter; siter = styleLookupTable.find(id); if (siter != styleLookupTable.end()) { Glib::ustring styleName = siter->second; - outs.printf("draw:style-name=\"%s\" ", styleName.c_str()); + couts.printf("draw:style-name=\"%s\" ", styleName.c_str()); } std::map::iterator giter; @@ -1818,25 +2026,25 @@ bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node) if (giter != gradientLookupTable.end()) { Glib::ustring gradientName = giter->second; - outs.printf("draw:fill-gradient-name=\"%s\" ", + couts.printf("draw:fill-gradient-name=\"%s\" ", gradientName.c_str()); } - outs.printf("draw:layer=\"layout\" svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ", + couts.printf("draw:layer=\"layout\" svg:x=\"%.3fcm\" svg:y=\"%.3fcm\" ", bbox_x, bbox_y); - outs.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ", + couts.printf("svg:width=\"%.3fcm\" svg:height=\"%.3fcm\" ", bbox_width, bbox_height); - outs.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"\n", + couts.printf("svg:viewBox=\"0.0 0.0 %.3f %.3f\"\n", bbox_width * 1000.0, bbox_height * 1000.0); - outs.printf(" svg:d=\""); - int nrPoints = writePath(outs, SP_CURVE_BPATH(curve), + couts.printf(" svg:d=\""); + int nrPoints = writePath(couts, SP_CURVE_BPATH(curve), tf, bbox_x, bbox_y); - outs.printf("\""); + couts.printf("\""); - outs.printf(">\n"); - outs.printf(" \n", nrPoints); - outs.printf("\n\n"); + couts.printf(">\n"); + couts.printf(" \n", nrPoints); + couts.printf("\n\n"); sp_curve_unref(curve); @@ -1848,14 +2056,10 @@ bool OdfOutput::writeTree(Writer &outs, Inkscape::XML::Node *node) /** - * Write the content.xml file. Writes the namesspace headers, then - * calls writeStyle() and writeTree(). + * Write the header for the content.xml file */ -bool OdfOutput::writeContent(ZipFile &zf, Inkscape::XML::Node *node) +bool OdfOutput::writeStyleHeader(Writer &outs) { - BufferOutputStream bouts; - OutputStreamWriter outs(bouts); - time_t tim; time(&tim); @@ -1864,14 +2068,14 @@ bool OdfOutput::writeContent(ZipFile &zf, Inkscape::XML::Node *node) outs.printf("\n"); outs.printf("\n"); outs.printf("\n"); outs.printf("\n"); - outs.printf("\n"); outs.printf("\n"); outs.printf("\n"); - outs.printf("\n"); - outs.printf("\n"); - outs.printf("\n"); - outs.printf("\n"); outs.printf("\n"); outs.printf("\n"); + outs.printf("\n"); outs.printf("\n"); - if (!writeStyle(outs)) - { - g_warning("Failed to write styles"); - return false; - } + return true; +} + +/** + * Write the footer for the style.xml file + */ +bool OdfOutput::writeStyleFooter(Writer &outs) +{ + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf(" \n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf(" \n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf(" \n"); + outs.printf("\n"); outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + + return true; +} + + + + +/** + * Write the header for the content.xml file + */ +bool OdfOutput::writeContentHeader(Writer &outs) +{ + time_t tim; + time(&tim); + + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); + outs.printf("\n"); outs.printf("\n"); outs.printf("\n"); outs.printf("