[office/tellico/4.2] /: Use data url for gradient images in entry template
Robby Stephenson <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 912115b4f0ccb52e71aea52e7a78184c62d2de05 by Robby Stephenson. Committed on 16/08/2026 at 21:46. Pushed by rstephenson into branch '4.2'. Use data url for gradient images in entry template Avoid creating and writing gradient images in tmp directories. M +4 -0 ChangeLog M +2 -1 src/configdialog.cpp M +0 -3 src/entrymatchdialog.cpp M +25 -73 src/entryview.cpp M +0 -3 src/entryview.h M +0 -3 src/fetchdialog.cpp M +2 -3 src/gui/previewdialog.cpp M +1 -1 src/gui/previewdialog.h M +1 -0 src/images/CMakeLists.txt C +35 -33 src/images/image_utils.cpp [from: src/gui/previewdialog.h - 053% similarity] C +15 -27 src/images/image_utils.h [from: src/gui/previewdialog.h - 073% similarity] M +0 -36 src/images/imagefactory.cpp M +0 -16 src/images/imagefactory.h C +20 -27 src/utils/styleoptions.h [from: src/gui/previewdialog.h - 074% similarity] M +4 -2 xslt/entry-templates/Fancy.xsl https://invent.kde.org/office/tellico/-/commit/912115b4f0ccb52e71aea52e7a78184c62d2de05 diff --git a/ChangeLog b/ChangeLog index 184d54fa9..6823f2c47 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2026-08-16 Robby Stephenson <[email protected]> + + * Moved gradient images to data url in entry template. + 2026-08-09 Robby Stephenson <[email protected]> * Added option to disable ISBN validation (Bug 514622). diff --git a/src/configdialog.cpp b/src/configdialog.cpp index 41deae45c..c6eba5c78 100644 --- a/src/configdialog.cpp +++ b/src/configdialog.cpp @@ -34,6 +34,7 @@ #include "tellico_kernel.h" #include "utils/tellico_utils.h" #include "utils/string_utils.h" +#include "utils/styleoptions.h" #include "config/tellico_config.h" #include "core/tellico_strings.h" #include "images/imagefactory.h" @@ -1083,7 +1084,7 @@ void ConfigDialog::slotShowTemplatePreview() { options.highlightedTextColor = m_highTextColorCombo->color(); options.highlightedBaseColor = m_highBaseColorCombo->color(); options.linkColor = m_linkColorCombo->color(); - dlg->setXSLTOptions(Kernel::self()->collectionType(), options); + dlg->setXSLTOptions(options); // always want to include a url to show link color too bool hasLink = false; diff --git a/src/entrymatchdialog.cpp b/src/entrymatchdialog.cpp index 44fdd1452..732aa95f2 100644 --- a/src/entrymatchdialog.cpp +++ b/src/entrymatchdialog.cpp @@ -101,9 +101,6 @@ EntryMatchDialog::EntryMatchDialog(QWidget* parent_, Data::EntryPtr entryToUpdat } m_entryView = new EntryView(split); - // don't bother creating funky gradient images for compact view - m_entryView->setUseGradientImages(false); - // set the xslt file AFTER setting the gradient image option m_entryView->setXSLTFile(QStringLiteral("Compact.xsl")); m_entryView->addXSLTStringParam("skip-fields", "id,mdate,cdate"); diff --git a/src/entryview.cpp b/src/entryview.cpp index 4b1e224ba..33178da27 100644 --- a/src/entryview.cpp +++ b/src/entryview.cpp @@ -31,6 +31,8 @@ #include "translators/tellicoxmlexporter.h" #include "images/imagefactory.h" #include "images/imageinfo.h" +#include "images/image.h" +#include "images/image_utils.h" #include "utils/tellico_utils.h" #include "utils/datafileregistry.h" #include "utils/cursorsaver.h" @@ -118,7 +120,6 @@ using Tellico::EntryView; EntryView::EntryView(QWidget* parent_) : QWebEngineView(parent_) , m_handler(nullptr) , m_tempFile(nullptr) - , m_useGradientImages(true) , m_checkCommonFile(true) { auto page = new EntryViewPage(this); setPage(page); @@ -174,14 +175,6 @@ void EntryView::showEntry(Tellico::Data::EntryPtr entry_) { return; } - // check if the gradient images need to be written again which might be the case if the collection is different - // and using local directories for storage - if(entry_ && (!m_entry || m_entry->collection() != entry_->collection()) && - m_useGradientImages && ImageFactory::cacheDir() == ImageFactory::LocalDir) { - // use entry_ instead of m_entry since that's the new entry to show - ImageFactory::createStyleImages(entry_->collection()->type()); - } - m_entry = entry_; Export::TellicoXMLExporter exporter(m_entry->collection(), Data::Document::self()->URL()); @@ -245,8 +238,6 @@ void EntryView::showEntry(Tellico::Data::EntryPtr entry_) { f2.close(); #endif -// myDebug() << html; - // limit is 2 MB after percent encoding, etc., so give some padding if(html.size() > 1200000) { delete m_tempFile; @@ -300,21 +291,6 @@ void EntryView::setXSLTFile(const QString& file_) { const int type = m_entry ? m_entry->collection()->type() : Data::Document::self()->collection()->type(); - // we need to know if the colors changed from last time, in case - // we need to do that ugly hack to reload the cache - bool reloadImages = m_useGradientImages; - // if m_useGradientImages is false, then we don't even need to check - // if there's no handler, there there's _no way_ to check - if(m_handler && reloadImages) { - // the only two colors that matter for the gradients are the base color - // and highlight base color - QByteArray oldBase = m_handler->param("bgcolor"); - QByteArray oldHigh = m_handler->param("color2"); - // remember the string params have apostrophes on either side, so we can start search at pos == 1 - reloadImages = oldBase.indexOf(Config::templateBaseColor(type).name().toLatin1(), 1) == -1 - || oldHigh.indexOf(Config::templateHighlightedBaseColor(type).name().toLatin1(), 1) == -1; - } - if(!m_handler || m_xsltFile != oldFile) { delete m_handler; // must read the file name to get proper context @@ -345,13 +321,17 @@ void EntryView::setXSLTFile(const QString& file_) { // imgdir gets set when an entry is shown m_handler->addStringParam("datadir", QUrl::fromLocalFile(Tellico::installationDir()).toEncoded()); - // if we don't have to reload the images, then just show the entry and we're done - if(reloadImages) { - // now, have to recreate images and refresh cache - resetColors(); - } else { - showEntry(m_entry); - } + const QImage bgImage = gradientImage(GradientBackground, type); + const QImage headerImage = gradientImage(GradientHeader, type); + + const QString bg = QStringLiteral("'data:image/png;base64,%1'") + .arg(Data::Image::byteArray(bgImage, "PNG").toBase64()); + const QString hd = QStringLiteral("'data:image/png;base64,%1'") + .arg(Data::Image::byteArray(headerImage, "PNG").toBase64()); + m_handler->addStringParam("gradient_bg", bg.toLatin1()); + m_handler->addStringParam("gradient_header", hd.toLatin1()); + + showEntry(m_entry); } void EntryView::copy() { @@ -360,7 +340,6 @@ void EntryView::copy() { void EntryView::slotRefresh() { setXSLTFile(m_xsltFile); - showEntry(m_entry); } void EntryView::changeEvent(QEvent* event_) { @@ -409,6 +388,17 @@ void EntryView::setXSLTOptions(const Tellico::StyleOptions& opt_) { m_handler->addStringParam("color2", opt_.highlightedBaseColor.name().toLatin1()); m_handler->addStringParam("linkcolor",opt_.linkColor.name().toLatin1()); m_handler->addStringParam("imgdir", QFile::encodeName(opt_.imgDir)); + + const int collType = m_entry ? m_entry->collection()->type() : Data::Collection::Base; + const QImage bgImage = gradientImage(GradientBackground, collType, opt_); + const QImage headerImage = gradientImage(GradientHeader, collType, opt_); + + const QString bg = QStringLiteral("'data:image/png;base64,%1'") + .arg(Data::Image::byteArray(bgImage, "PNG").toBase64()); + const QString hd = QStringLiteral("'data:image/png;base64,%1'") + .arg(Data::Image::byteArray(headerImage, "PNG").toBase64()); + m_handler->addStringParam("gradient_bg", bg.toLatin1()); + m_handler->addStringParam("gradient_header", hd.toLatin1()); } void EntryView::resetView() { @@ -417,45 +407,7 @@ void EntryView::resetView() { // Many of the template style parameters use default values. The only way that // KConfigSkeleton can be updated is to delete the existing config object, which will then be recreated delete Config::self(); - setXSLTFile(m_xsltFile); // this ends up calling resetColors() -} - -void EntryView::resetColors() { - // recreate gradients - ImageFactory::createStyleImages(m_entry ? m_entry->collection()->type() : Data::Collection::Base); - - QString dir = m_handler ? QFile::decodeName(m_handler->param("imgdir")) : QString(); - if(dir.isEmpty()) { - dir = ImageFactory::imageDir().url(); - } else { - // it's a string param, so it has quotes on both sides - dir = dir.mid(1); - dir.truncate(dir.length()-1); - } - - delete m_tempFile; - m_tempFile = new QTemporaryFile(); - if(!m_tempFile->open()) { - myDebug() << "failed to open temp file"; - delete m_tempFile; - m_tempFile = nullptr; - return; - } - - // this is a rather bad hack to get around the fact that the image cache is not reloaded when - // the gradient files are changed on disk. Setting the URLArgs for write() calls doesn't seem to - // work. So force a reload with a temp file, then catch the completed signal and repaint - QString s = QStringLiteral("<html><body><img src=\"%1\"><img src=\"%2\"></body></html>") - .arg(dir + QLatin1String("gradient_bg.png"), - dir + QLatin1String("gradient_header.png")); - QTextStream stream(m_tempFile); - stream << s; - stream.flush(); - - // don't flicker - setUpdatesEnabled(false); - load(QUrl::fromLocalFile(m_tempFile->fileName())); - connect(this, &EntryView::loadFinished, this, &EntryView::slotReloadEntry); + slotRefresh(); } void EntryView::contextMenuEvent(QContextMenuEvent* event_) { diff --git a/src/entryview.h b/src/entryview.h index 812ca2656..37f84fe6e 100644 --- a/src/entryview.h +++ b/src/entryview.h @@ -77,7 +77,6 @@ public: void setXSLTFile(const QString& file); void addXSLTStringParam(const QByteArray& name, const QByteArray& value); void setXSLTOptions(const StyleOptions& options); - void setUseGradientImages(bool b) { m_useGradientImages = b; } void resetView(); Q_SIGNALS: @@ -101,7 +100,6 @@ private Q_SLOTS: void slotPrint(); private: - void resetColors(); void contextMenuEvent(QContextMenuEvent* event) override; Data::EntryPtr m_entry; @@ -110,7 +108,6 @@ private: QString m_textToShow; QTemporaryFile* m_tempFile; - bool m_useGradientImages; bool m_checkCommonFile; QPrinter m_printer; }; diff --git a/src/fetchdialog.cpp b/src/fetchdialog.cpp index 29b92d077..cc02c264e 100644 --- a/src/fetchdialog.cpp +++ b/src/fetchdialog.cpp @@ -261,9 +261,6 @@ FetchDialog::FetchDialog(QWidget* parent_) "will fetch the complete entry and show it in the view below.")); m_entryView = new EntryView(split); - // don't bother creating funky gradient images for compact view - m_entryView->setUseGradientImages(false); - // set the xslt file AFTER setting the gradient image option m_entryView->setXSLTFile(QStringLiteral("Compact.xsl")); m_entryView->addXSLTStringParam("skip-fields", "id,mdate,cdate"); m_entryView->setWhatsThis(i18n("An entry may be shown here before adding it to the " diff --git a/src/gui/previewdialog.cpp b/src/gui/previewdialog.cpp index 67d99957e..29153eb6c 100644 --- a/src/gui/previewdialog.cpp +++ b/src/gui/previewdialog.cpp @@ -25,7 +25,7 @@ #include "previewdialog.h" #include "../entryview.h" #include "../entry.h" -#include "../images/imagefactory.h" // for StyleOptions +#include "../utils/styleoptions.h" #include <KLocalizedString> @@ -69,9 +69,8 @@ void PreviewDialog::setXSLTFile(const QString& file_) { m_view->setXSLTFile(file_); } -void PreviewDialog::setXSLTOptions(int collectionType_, Tellico::StyleOptions options_) { +void PreviewDialog::setXSLTOptions(Tellico::StyleOptions options_) { options_.imgDir = m_tempDir->path(); // images always get written to temp dir - ImageFactory::createStyleImages(collectionType_, options_); m_view->setXSLTOptions(options_); } diff --git a/src/gui/previewdialog.h b/src/gui/previewdialog.h index fefd970cd..eaea62d28 100644 --- a/src/gui/previewdialog.h +++ b/src/gui/previewdialog.h @@ -45,7 +45,7 @@ public: ~PreviewDialog(); void setXSLTFile(const QString& file); - void setXSLTOptions(int collectionType, StyleOptions options); + void setXSLTOptions(StyleOptions options); void showEntry(Data::EntryPtr entry); private: diff --git a/src/images/CMakeLists.txt b/src/images/CMakeLists.txt index 58556d7f4..e1dfc9ade 100644 --- a/src/images/CMakeLists.txt +++ b/src/images/CMakeLists.txt @@ -4,6 +4,7 @@ set(images_STAT_SRCS imagefactory.cpp imageinfo.cpp imagejob.cpp + image_utils.cpp ) add_library(images STATIC ${images_STAT_SRCS}) diff --git a/src/gui/previewdialog.h b/src/images/image_utils.cpp similarity index 53% copy from src/gui/previewdialog.h copy to src/images/image_utils.cpp index fefd970cd..e26906702 100644 --- a/src/gui/previewdialog.h +++ b/src/images/image_utils.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - Copyright (C) 2006-2009 Robby Stephenson <[email protected]> + Copyright (C) 2026 Robby Stephenson <[email protected]> ***************************************************************************/ /*************************************************************************** @@ -22,37 +22,39 @@ * * ***************************************************************************/ -#ifndef TELLICO_GUI_PREVIEWDIALOG_H -#define TELLICO_GUI_PREVIEWDIALOG_H - -#include <QDialog> - -#include "../datavectors.h" - -class QTemporaryDir; - -namespace Tellico { - class EntryView; - class StyleOptions; - - namespace GUI { - -class PreviewDialog : public QDialog { -Q_OBJECT - -public: - PreviewDialog(QWidget* parent); - ~PreviewDialog(); - - void setXSLTFile(const QString& file); - void setXSLTOptions(int collectionType, StyleOptions options); - void showEntry(Data::EntryPtr entry); - -private: - QTemporaryDir* m_tempDir; - EntryView* m_view; -}; - +#include "image_utils.h" +#include "../config/tellico_config.h" +#include "../utils/gradient.h" + +#include <KColorUtils> + +QImage Tellico::gradientImage(Tellico::GradientImageType gradType_, int collectionType_, const Tellico::StyleOptions& opt_) { + const QColor& baseColor = opt_.baseColor.isValid() + ? opt_.baseColor + : Config::templateBaseColor(collectionType_); + const QColor& highColor = opt_.highlightedBaseColor.isValid() + ? opt_.highlightedBaseColor + : Config::templateHighlightedBaseColor(collectionType_); + + QImage img; + switch(gradType_) { + case GradientBackground: + img = Tellico::gradient(QSize(600, 1), + KColorUtils::mix(baseColor, highColor, 0.3), + baseColor, + Tellico::PipeCrossGradient); + img = img.transformed(QTransform().rotate(90)); + break; + + case GradientHeader: + img = Tellico::unbalancedGradient(QSize(1, 10), + highColor, + KColorUtils::mix(baseColor, highColor, 0.5), + Tellico::VerticalGradient, + 100, + -100); + break; } + + return img; } -#endif diff --git a/src/gui/previewdialog.h b/src/images/image_utils.h similarity index 73% copy from src/gui/previewdialog.h copy to src/images/image_utils.h index fefd970cd..76d08ff6f 100644 --- a/src/gui/previewdialog.h +++ b/src/images/image_utils.h @@ -1,5 +1,5 @@ /*************************************************************************** - Copyright (C) 2006-2009 Robby Stephenson <[email protected]> + Copyright (C) 2026 Robby Stephenson <[email protected]> ***************************************************************************/ /*************************************************************************** @@ -22,37 +22,25 @@ * * ***************************************************************************/ -#ifndef TELLICO_GUI_PREVIEWDIALOG_H -#define TELLICO_GUI_PREVIEWDIALOG_H +#ifndef TELLICO_IMAGEUTILS_H +#define TELLICO_IMAGEUTILS_H -#include <QDialog> - -#include "../datavectors.h" - -class QTemporaryDir; +#include "../utils/styleoptions.h" namespace Tellico { - class EntryView; - class StyleOptions; - - namespace GUI { - -class PreviewDialog : public QDialog { -Q_OBJECT -public: - PreviewDialog(QWidget* parent); - ~PreviewDialog(); + enum GradientImageType { + GradientBackground, + GradientHeader + }; - void setXSLTFile(const QString& file); - void setXSLTOptions(int collectionType, StyleOptions options); - void showEntry(Data::EntryPtr entry); + /** + * Creates the gradient images used in the entry view. + */ + QImage gradientImage(GradientImageType gradientType, + int collectionType, + const StyleOptions& options = StyleOptions()); -private: - QTemporaryDir* m_tempDir; - EntryView* m_view; -}; +} // end namespace - } -} #endif diff --git a/src/images/imagefactory.cpp b/src/images/imagefactory.cpp index f25dcb646..70e1d9648 100644 --- a/src/images/imagefactory.cpp +++ b/src/images/imagefactory.cpp @@ -29,10 +29,8 @@ #include "imagejob.h" #include "../config/tellico_config.h" #include "../utils/tellico_utils.h" -#include "../utils/gradient.h" #include "../tellico_debug.h" -#include <KColorUtils> #include <KZip> #include <KIO/Global> #include <KProtocolManager> @@ -674,40 +672,6 @@ void ImageFactory::clean(bool purgeTempDirectory_) { } } -void ImageFactory::createStyleImages(int collectionType_, const Tellico::StyleOptions& opt_) { - myLog() << "Creating style images for type:" << collectionType_; - const QColor& baseColor = opt_.baseColor.isValid() - ? opt_.baseColor - : Config::templateBaseColor(collectionType_); - const QColor& highColor = opt_.highlightedBaseColor.isValid() - ? opt_.highlightedBaseColor - : Config::templateHighlightedBaseColor(collectionType_); - - const QString bgname(QStringLiteral("gradient_bg.png")); - const QColor& bgc1 = KColorUtils::mix(baseColor, highColor, 0.3); - QImage bgImage = Tellico::gradient(QSize(600, 1), bgc1, baseColor, - Tellico::PipeCrossGradient); - bgImage = bgImage.transformed(QTransform().rotate(90)); - - const QString hdrname(QStringLiteral("gradient_header.png")); - const QColor& bgc2 = KColorUtils::mix(baseColor, highColor, 0.5); - QImage hdrImage = Tellico::unbalancedGradient(QSize(1, 10), highColor, bgc2, - Tellico::VerticalGradient, 100, -100); - - if(opt_.imgDir.isEmpty()) { - ImageFactory::removeImage(bgname, true /*delete */); - factory->addImageImpl(Data::Image::byteArray(bgImage, "PNG"), QStringLiteral("PNG"), bgname); - ImageFactory::writeCachedImage(bgname, cacheDir(), true /*force*/); - - ImageFactory::removeImage(hdrname, true /*delete */); - factory->addImageImpl(Data::Image::byteArray(hdrImage, "PNG"), QStringLiteral("PNG"), hdrname); - ImageFactory::writeCachedImage(hdrname, cacheDir(), true /*force*/); - } else { - bgImage.save(opt_.imgDir + bgname, "PNG"); - hdrImage.save(opt_.imgDir + hdrname, "PNG"); - } -} - void ImageFactory::removeImage(const QString& id_, bool deleteImage_) { // myLog() << "Removing image from cache:" << id_; // be careful using this diff --git a/src/images/imagefactory.h b/src/images/imagefactory.h index 1f00d92bb..225fcf5cb 100644 --- a/src/images/imagefactory.h +++ b/src/images/imagefactory.h @@ -45,18 +45,6 @@ namespace Tellico { } class ImageDirectory; -class StyleOptions { -public: - QString fontFamily; - int fontSize; - QColor baseColor; - QColor textColor; - QColor highlightedBaseColor; - QColor highlightedTextColor; - QColor linkColor; - QString imgDir; -}; - /** * @author Robby Stephenson */ @@ -165,10 +153,6 @@ public: * if deleteTempDirectory = true, then clean the temp dir and remove all temporary image files */ static void clean(bool deleteTempDirectory); - /** - * Creates the gradient images used in the entry view. - */ - static void createStyleImages(int collectionType, const StyleOptions& options = StyleOptions()); static void removeImage(const QString& id_, bool deleteImage); static StringSet imagesNotInCache(); diff --git a/src/gui/previewdialog.h b/src/utils/styleoptions.h similarity index 74% copy from src/gui/previewdialog.h copy to src/utils/styleoptions.h index fefd970cd..d7f26429a 100644 --- a/src/gui/previewdialog.h +++ b/src/utils/styleoptions.h @@ -1,5 +1,5 @@ /*************************************************************************** - Copyright (C) 2006-2009 Robby Stephenson <[email protected]> + Copyright (C) 2026 Robby Stephenson <[email protected]> ***************************************************************************/ /*************************************************************************** @@ -22,37 +22,30 @@ * * ***************************************************************************/ -#ifndef TELLICO_GUI_PREVIEWDIALOG_H -#define TELLICO_GUI_PREVIEWDIALOG_H +#ifndef TELLICO_STYLEOPTIONS_H +#define TELLICO_STYLEOPTIONS_H -#include <QDialog> - -#include "../datavectors.h" - -class QTemporaryDir; +#include <QString> +#include <QColor> +#include <QImage> namespace Tellico { - class EntryView; - class StyleOptions; - - namespace GUI { - -class PreviewDialog : public QDialog { -Q_OBJECT +/** + * @author Robby Stephenson + */ +class StyleOptions { public: - PreviewDialog(QWidget* parent); - ~PreviewDialog(); - - void setXSLTFile(const QString& file); - void setXSLTOptions(int collectionType, StyleOptions options); - void showEntry(Data::EntryPtr entry); - -private: - QTemporaryDir* m_tempDir; - EntryView* m_view; + QString fontFamily; + int fontSize; + QColor baseColor; + QColor textColor; + QColor highlightedBaseColor; + QColor highlightedTextColor; + QColor linkColor; + QString imgDir; }; - } -} +} // end namespace + #endif diff --git a/xslt/entry-templates/Fancy.xsl b/xslt/entry-templates/Fancy.xsl index 389485774..784d1b36c 100644 --- a/xslt/entry-templates/Fancy.xsl +++ b/xslt/entry-templates/Fancy.xsl @@ -36,6 +36,8 @@ <xsl:param name="color1"/> <!-- highlighted text color --> <xsl:param name="color2"/> <!-- highlighted background color --> <xsl:param name="linkcolor"/> <!-- link color --> +<xsl:param name="gradient_bg"/> <!-- gradient background data url --> +<xsl:param name="gradient_header"/> <!-- gradient header data url --> <xsl:param name="collection-file"/> <!-- might have a link to parent collection --> @@ -80,7 +82,7 @@ font-size: <xsl:value-of select="$fontsize"/>pt; color: <xsl:value-of select="$fgcolor"/>; background-color: <xsl:value-of select="$bgcolor"/>; - background-image: url(<xsl:value-of select="concat($imgdir, 'gradient_bg.png')"/>); + background-image: url(<xsl:value-of select="$gradient_bg"/>); background-repeat: repeat; } h1 { @@ -89,7 +91,7 @@ font-size: 1.8em; color: <xsl:value-of select="$color1"/>; background-color: <xsl:value-of select="$color2"/>; - background-image: url(<xsl:value-of select="concat($imgdir, 'gradient_header.png')"/>); + background-image: url(<xsl:value-of select="$gradient_header"/>); background-repeat: repeat-x; border-bottom: 1px outset black; text-align: center;