File indexing completed on 2024-05-19 05:38:06
0001 /* 0002 SPDX-FileCopyrightText: 2018 Julian Wolff <wolff@julianwolff.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include <cmath> 0008 0009 #include <QApplication> 0010 #include <QPainter> 0011 #include <QPalette> 0012 0013 #include <KWindowSystem> 0014 0015 #include "kxftconfig.h" 0016 #include "previewimageprovider.h" 0017 #include "previewrenderengine.h" 0018 0019 /** 0020 * @brief Combines a list of images vertically into one image 0021 * 0022 * Combines a list of images vertically with the given spacing 0023 * between adjacent rows of images. 0024 * The width of the combined image is the width of the longest 0025 * image in the list, and the height is the sum of the heights 0026 * of all images in the list. 0027 * The device pixel ratio of the combined image is the same 0028 * as that of the first image in the list. 0029 * 0030 * @param images the list of images to be combined 0031 * @param bgnd the background color of the combined image 0032 * @param _spacing the spacing between adjacent rows of images 0033 * @return the combined image 0034 */ 0035 QImage combineImages(const QList<QImage> &images, const QColor &bgnd, int _spacing = 0) 0036 { 0037 if (images.empty()) { 0038 return QImage(); 0039 } 0040 0041 int width = 0; 0042 int height = 0; 0043 const double devicePixelRatio = images.at(0).devicePixelRatio(); 0044 const int spacing = std::lround(_spacing * devicePixelRatio); 0045 for (const auto &image : images) { 0046 if (width < image.width()) { 0047 width = image.width(); 0048 } 0049 height += image.height(); 0050 } 0051 height += spacing * images.count(); 0052 0053 // To correctly align the image pixels on a high dpi display, 0054 // the image dimensions need to be a multiple of devicePixelRatio 0055 QImage combinedImage(width * devicePixelRatio, height * devicePixelRatio, images.at(0).format()); 0056 combinedImage.setDevicePixelRatio(devicePixelRatio); 0057 combinedImage.fill(bgnd); 0058 0059 int offset = spacing; // Top margin 0060 QPainter p(&combinedImage); 0061 for (const auto &image : images) { 0062 p.drawImage(0, offset, image); 0063 offset += image.height() + spacing; 0064 } 0065 0066 return combinedImage; 0067 } 0068 0069 PreviewImageProvider::PreviewImageProvider(const QFont &font) 0070 : QQuickImageProvider(QQuickImageProvider::Image) 0071 , m_font(font) 0072 { 0073 } 0074 0075 QImage PreviewImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) 0076 { 0077 Q_UNUSED(requestedSize) 0078 if (!KWindowSystem::isPlatformX11()) { 0079 return QImage(); 0080 } 0081 0082 int subPixelIndex = 0; 0083 int hintingIndex = 0; 0084 0085 const auto idpart = QStringView(id).split(QLatin1Char('.'))[0]; 0086 const auto sections = idpart.split(QLatin1Char('_')); 0087 0088 if (sections.size() >= 2) { 0089 subPixelIndex = sections[0].toInt() + KXftConfig::SubPixel::None; 0090 hintingIndex = sections[1].toInt() + KXftConfig::Hint::None; 0091 } else { 0092 return QImage(); 0093 } 0094 0095 KXftConfig xft; 0096 0097 KXftConfig::AntiAliasing::State oldAntialiasing = xft.getAntiAliasing(); 0098 double oldStart = 0; 0099 double oldEnd = 0; 0100 xft.getExcludeRange(oldStart, oldEnd); 0101 KXftConfig::SubPixel::Type oldSubPixelType = KXftConfig::SubPixel::NotSet; 0102 xft.getSubPixelType(oldSubPixelType); 0103 KXftConfig::Hint::Style oldHintStyle = KXftConfig::Hint::NotSet; 0104 xft.getHintStyle(oldHintStyle); 0105 0106 xft.setAntiAliasing(KXftConfig::AntiAliasing::Enabled); 0107 xft.setExcludeRange(0, 0); 0108 0109 KXftConfig::SubPixel::Type subPixelType = (KXftConfig::SubPixel::Type)subPixelIndex; 0110 xft.setSubPixelType(subPixelType); 0111 0112 KXftConfig::Hint::Style hintStyle = (KXftConfig::Hint::Style)hintingIndex; 0113 xft.setHintStyle(hintStyle); 0114 0115 xft.apply(); 0116 0117 QColor text(QApplication::palette().color(QPalette::Text)); 0118 QColor bgnd(QApplication::palette().color(QPalette::Window)); 0119 0120 PreviewRenderEngine eng(true); 0121 QList<QImage> lines; 0122 0123 lines << eng.drawAutoSize(m_font, text, bgnd, eng.getDefaultPreviewString()); 0124 0125 QImage img = combineImages(lines, bgnd, lines[0].height() * .25); 0126 0127 xft.setAntiAliasing(oldAntialiasing); 0128 xft.setExcludeRange(oldStart, oldEnd); 0129 xft.setSubPixelType(oldSubPixelType); 0130 xft.setHintStyle(oldHintStyle); 0131 0132 xft.apply(); 0133 0134 *size = img.size(); 0135 0136 return img; 0137 }