From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- src/ui/dialog/svg-preview.cpp | 477 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 477 insertions(+) create mode 100644 src/ui/dialog/svg-preview.cpp (limited to 'src/ui/dialog/svg-preview.cpp') diff --git a/src/ui/dialog/svg-preview.cpp b/src/ui/dialog/svg-preview.cpp new file mode 100644 index 0000000..2d6cc4e --- /dev/null +++ b/src/ui/dialog/svg-preview.cpp @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * Implementation of the file dialog interfaces defined in filedialogimpl.h. + */ +/* Authors: + * Bob Jamison + * Joel Holdsworth + * Bruno Dilly + * Other dudes from The Inkscape Organization + * Abhishek Sharma + * + * Copyright (C) 2004-2007 Bob Jamison + * Copyright (C) 2006 Johan Engelen + * Copyright (C) 2007-2008 Joel Holdsworth + * Copyright (C) 2004-2007 The Inkscape Organization + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include +#include + +#include +#include // GStatBuf + +#include "svg-preview.h" + +#include "document.h" +#include "ui/view/svg-view-widget.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +/*######################################################################### +### SVG Preview Widget +#########################################################################*/ + +bool SVGPreview::setDocument(SPDocument *doc) +{ + if (viewer) { + viewer->setDocument(doc); + } else { + viewer = Gtk::manage(new Inkscape::UI::View::SVGViewWidget(doc)); + pack_start(*viewer, true, true); + } + + if (document) { + delete document; + } + document = doc; + + show_all(); + + return true; +} + + +bool SVGPreview::setFileName(Glib::ustring &theFileName) +{ + Glib::ustring fileName = theFileName; + + fileName = Glib::filename_to_utf8(fileName); + + /** + * I don't know why passing false to keepalive is bad. But it + * prevents the display of an svg with a non-ascii filename + */ + SPDocument *doc = SPDocument::createNewDoc(fileName.c_str(), true); + if (!doc) { + g_warning("SVGView: error loading document '%s'\n", fileName.c_str()); + return false; + } + + setDocument(doc); + + return true; +} + + + +bool SVGPreview::setFromMem(char const *xmlBuffer) +{ + if (!xmlBuffer) + return false; + + gint len = (gint)strlen(xmlBuffer); + SPDocument *doc = SPDocument::createNewDocFromMem(xmlBuffer, len, false); + if (!doc) { + g_warning("SVGView: error loading buffer '%s'\n", xmlBuffer); + return false; + } + + setDocument(doc); + + return true; +} + + + +void SVGPreview::showImage(Glib::ustring &theFileName) +{ + Glib::ustring fileName = theFileName; + + // Let's get real width and height from SVG file. These are template + // files so we assume they are well formed. + + // std::cout << "SVGPreview::showImage: " << theFileName << std::endl; + std::string width; + std::string height; + + /*##################################### + # LET'S HAVE SOME FUN WITH SVG! + # Instead of just loading an image, why + # don't we make a lovely little svg and + # display it nicely? + #####################################*/ + + // Arbitrary size of svg doc -- rather 'portrait' shaped + gint previewWidth = 400; + gint previewHeight = 600; + + // Get some image info. Smart pointer does not need to be deleted + Glib::RefPtr img(nullptr); + try + { + img = Gdk::Pixbuf::create_from_file(fileName); + } + catch (const Glib::FileError &e) + { + g_message("caught Glib::FileError in SVGPreview::showImage"); + return; + } + catch (const Gdk::PixbufError &e) + { + g_message("Gdk::PixbufError in SVGPreview::showImage"); + return; + } + catch (...) + { + g_message("Caught ... in SVGPreview::showImage"); + return; + } + + gint imgWidth = img->get_width(); + gint imgHeight = img->get_height(); + + Glib::ustring svg = ".svg"; + if (hasSuffix(fileName, svg)) { + std::ifstream input(theFileName.c_str()); + if( !input ) { + std::cerr << "SVGPreview::showImage: Failed to open file: " << theFileName << std::endl; + } else { + + Glib::ustring token; + + Glib::MatchInfo match_info; + Glib::RefPtr regex1 = Glib::Regex::create("width=\"(.*)\""); + Glib::RefPtr regex2 = Glib::Regex::create("height=\"(.*)\""); + + while( !input.eof() && (height.empty() || width.empty()) ) { + + input >> token; + // std::cout << "|" << token << "|" << std::endl; + + if (regex1->match(token, match_info)) { + width = match_info.fetch(1).raw(); + } + + if (regex2->match(token, match_info)) { + height = match_info.fetch(1).raw(); + } + + } + } + } + + // TODO: replace int to string conversion with std::to_string when fully C++11 compliant + if (height.empty() || width.empty()) { + std::ostringstream s_width; + std::ostringstream s_height; + s_width << imgWidth; + s_height << imgHeight; + width = s_width.str(); + height = s_height.str(); + } + + // Find the minimum scale to fit the image inside the preview area + double scaleFactorX = (0.9 * (double)previewWidth) / ((double)imgWidth); + double scaleFactorY = (0.9 * (double)previewHeight) / ((double)imgHeight); + double scaleFactor = scaleFactorX; + if (scaleFactorX > scaleFactorY) + scaleFactor = scaleFactorY; + + // Now get the resized values + gint scaledImgWidth = (int)(scaleFactor * (double)imgWidth); + gint scaledImgHeight = (int)(scaleFactor * (double)imgHeight); + + // center the image on the area + gint imgX = (previewWidth - scaledImgWidth) / 2; + gint imgY = (previewHeight - scaledImgHeight) / 2; + + // wrap a rectangle around the image + gint rectX = imgX - 1; + gint rectY = imgY - 1; + gint rectWidth = scaledImgWidth + 2; + gint rectHeight = scaledImgHeight + 2; + + // Our template. Modify to taste + gchar const *xformat = R"A( + + + + + %s x %s + +)A"; + + // if (!Glib::get_charset()) //If we are not utf8 + fileName = Glib::filename_to_utf8(fileName); + // Filenames in xlinks are decoded, so any % will break without this. + auto encodedName = Glib::uri_escape_string(fileName); + + // Fill in the template + /* FIXME: Do proper XML quoting for fileName. */ + gchar *xmlBuffer = + g_strdup_printf(xformat, previewWidth, previewHeight, imgX, imgY, scaledImgWidth, scaledImgHeight, + encodedName.c_str(), rectX, rectY, rectWidth, rectHeight, width.c_str(), height.c_str() ); + + // g_message("%s\n", xmlBuffer); + + // now show it! + setFromMem(xmlBuffer); + g_free(xmlBuffer); +} + + + +void SVGPreview::showNoPreview() +{ + // Are we already showing it? + if (showingNoPreview) + return; + + // Our template. Modify to taste + gchar const *xformat = R"B( + + + + + + + + + %s + +)B"; + + // Fill in the template + gchar *xmlBuffer = g_strdup_printf(xformat, _("No preview")); + + // g_message("%s\n", xmlBuffer); + + // Now show it! + setFromMem(xmlBuffer); + g_free(xmlBuffer); + showingNoPreview = true; +} + + +/** + * Inform the user that the svg file is too large to be displayed. + * This does not check for sizes of embedded images (yet) + */ +void SVGPreview::showTooLarge(long fileLength) +{ + // Our template. Modify to taste + gchar const *xformat = R"C( + + + + + + + + + %.1f MB + %s + +)C"; + + + // Fill in the template + double floatFileLength = ((double)fileLength) / 1048576.0; + // printf("%ld %f\n", fileLength, floatFileLength); + + gchar *xmlBuffer = + g_strdup_printf(xformat, floatFileLength, _("Too large for preview")); + + // g_message("%s\n", xmlBuffer); + + // now show it! + setFromMem(xmlBuffer); + g_free(xmlBuffer); +} + +bool SVGPreview::set(Glib::ustring &fileName, int dialogType) +{ + + if (!Glib::file_test(fileName, Glib::FILE_TEST_EXISTS)) { + showNoPreview(); + return false; + } + + if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) { + showNoPreview(); + return false; + } + + if (Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)) { + Glib::ustring fileNameUtf8 = Glib::filename_to_utf8(fileName); + gchar *fName = const_cast( + fileNameUtf8.c_str()); // const-cast probably not necessary? (not necessary on Windows version of stat()) + GStatBuf info; + if (g_stat(fName, &info)) // stat returns 0 upon success + { + g_warning("SVGPreview::set() : %s : %s", fName, strerror(errno)); + return false; + } + if (info.st_size > 0xA00000L) { + showingNoPreview = false; + showTooLarge(info.st_size); + return false; + } + } + + Glib::ustring svg = ".svg"; + Glib::ustring svgz = ".svgz"; + + if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) && + (hasSuffix(fileName, svg) || hasSuffix(fileName, svgz))) { + bool retval = setFileName(fileName); + showingNoPreview = false; + return retval; + } else if (isValidImageFile(fileName)) { + showImage(fileName); + showingNoPreview = false; + return true; + } else { + showNoPreview(); + return false; + } +} + + +SVGPreview::SVGPreview() + : Gtk::Box(Gtk::ORIENTATION_VERTICAL) + , document(nullptr) + , viewer(nullptr) + , showingNoPreview(false) +{ + set_size_request(200, 300); +} + +SVGPreview::~SVGPreview() +{ + if (viewer) { + viewer->setDocument(nullptr); + } + delete document; +} + +} // namespace Dialog +} // namespace UI +} // 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 : + -- cgit v1.2.3