diff --git a/src/tools/ksvg2icns/ksvg2icns.cpp b/src/tools/ksvg2icns/ksvg2icns.cpp index 96792db..f879ba7 100644 --- a/src/tools/ksvg2icns/ksvg2icns.cpp +++ b/src/tools/ksvg2icns/ksvg2icns.cpp @@ -1,165 +1,159 @@ /****************************************************************************** * Copyright 2014 Harald Fernengel * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) version 3, or any * * later version accepted by the membership of KDE e.V. (or its * * successor approved by the membership of KDE e.V.), which shall * * act as a proxy defined in Section 6 of version 3 of the license. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library. If not, see * * . * * * ******************************************************************************/ /* This tool converts an svg to a Mac OS X icns file. * Note: Requires the 'iconutil' Mac OS X binary */ #include #include #include #include -#include +#include #include #include #include "../../../kiconthemes_version.h" #include #define EXIT_ON_ERROR(isOk, ...) \ do { \ if (!(isOk)) { \ fprintf(stderr, __VA_ARGS__); \ return 1; \ } \ } while (false); static bool writeImage(QSvgRenderer &svg, int size, const QString &outFile1, const QString &outFile2 = QString()) { QImage out(size, size, QImage::Format_ARGB32); out.fill(Qt::transparent); QPainter painter(&out); svg.render(&painter); painter.end(); if (!out.save(outFile1)) { fprintf(stderr, "Unable to write %s\n", qPrintable(outFile1)); return false; } if (!outFile2.isEmpty() && !out.save(outFile2)) { fprintf(stderr, "Unable to write %s\n", qPrintable(outFile2)); return false; } return true; } int main(int argc, char *argv[]) { - // it turns out we don't actually need to be a QGuiApplication in order - // to use QPainter on a QImage. Downgrading to a QCoreApplication should - // make us usable on headless (CI) servers and remove some QPA-related - // runtime overhead. - // Alternatively we create a QGuiApplication after setting QT_QPA_PLATFORM: - // qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal")); - QCoreApplication app(argc, argv); + QGuiApplication app(argc, argv); app.setApplicationName(QStringLiteral("ksvg2icns")); app.setApplicationVersion(QStringLiteral(KICONTHEMES_VERSION_STRING)); QCommandLineParser parser; parser.setApplicationDescription(app.translate("main", "Creates an icns file from an svg image")); parser.addPositionalArgument("iconname", app.translate("main", "The svg icon to convert")); parser.addHelpOption(); parser.process(app); if (parser.positionalArguments().isEmpty()) { parser.showHelp(); return 1; } bool isOk; // create a temporary dir to create an iconset QTemporaryDir tmpDir(QDir::tempPath() + QStringLiteral("/ksvg2icns")); isOk = tmpDir.isValid(); EXIT_ON_ERROR(isOk, "Unable to create temporary directory\n"); const QString outPath = tmpDir.filePath(QStringLiteral("out.iconset")); isOk = QDir(tmpDir.path()).mkpath(outPath); EXIT_ON_ERROR(isOk, "Unable to create out.iconset directory\n"); const QStringList &args = app.arguments(); EXIT_ON_ERROR(args.size() == 2, "Usage: %s svg-image\n", qPrintable(args.value(0))); const QString &svgFileName = args.at(1); // open the actual svg file QSvgRenderer svg; isOk = svg.load(svgFileName); EXIT_ON_ERROR(isOk, "Unable to load %s\n", qPrintable(svgFileName)); // The sizes are from: // https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html struct OutFiles { int size; QString out1; QString out2; }; // create the pngs in various resolutions const OutFiles outFiles[] = { { 1024, outPath + QStringLiteral("/icon_512x512@2x.png"), QString() }, { 512, outPath + QStringLiteral("/icon_512x512.png"), outPath + QStringLiteral("/icon_256x256@2x.png") }, { 256, outPath + QStringLiteral("/icon_256x256.png"), outPath + QStringLiteral("/icon_128x128@2x.png") }, { 128, outPath + QStringLiteral("/icon_128x128.png"), QString() }, { 64, outPath + QStringLiteral("/icon_32x32@2x.png"), QString() }, { 32, outPath + QStringLiteral("/icon_32x32.png"), outPath + QStringLiteral("/icon_16x16@2x.png") }, { 16, outPath + QStringLiteral("/icon_16x16.png"), QString() } }; for (size_t i = 0; i < sizeof(outFiles) / sizeof(OutFiles); ++i) { isOk = writeImage(svg, outFiles[i].size, outFiles[i].out1, outFiles[i].out2); if (!isOk) { return 1; } } // convert the iconset to icns using the "iconutil" command const QString outIcns = QFileInfo(svgFileName).baseName() + QStringLiteral(".icns"); const QStringList utilArgs = QStringList() << "-c" << "icns" << "-o" << outIcns << outPath; QProcess iconUtil; iconUtil.start(QStringLiteral("iconutil"), utilArgs, QIODevice::ReadOnly); isOk = iconUtil.waitForFinished(-1); EXIT_ON_ERROR(isOk, "Unable to launch iconutil: %s\n", qPrintable(iconUtil.errorString())); EXIT_ON_ERROR(iconUtil.exitStatus() == QProcess::NormalExit, "iconutil crashed!\n"); EXIT_ON_ERROR(iconUtil.exitCode() == 0, "iconutil returned %d\n", iconUtil.exitCode()); return 0; } diff --git a/src/tools/ksvg2ico/CMakeLists.txt b/src/tools/ksvg2ico/CMakeLists.txt deleted file mode 100644 index 57e8ceb..0000000 --- a/src/tools/ksvg2ico/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -find_package(Png2Ico) -if (Png2Ico_FOUND) - if (Png2Ico_HAS_RCFILE_ARGUMENT) - # not used at the moment - add_definitions(-DPNG2ICO_HAS_RCFILE_ARGUMENT) - endif() - # act as if there's a png2ico utility that supports both options - if (Png2Ico_HAS_COLORS_ARGUMENT) - # using --colors appears counter-productive - # add_definitions(-DPNG2ICO_SUPPORTS_MULTIPLE_COLOR_DEPTHS) - endif() -else() - message(WARNING "Unable to find the png2ico utility - ksvg2ico will miss its runtime dependency") -endif() - -add_executable(ksvg2ico ksvg2ico.cpp qicohandler.cpp) -ecm_mark_nongui_executable(ksvg2ico) -target_link_libraries(ksvg2ico Qt5::Gui Qt5::Svg) - -install(TARGETS ksvg2ico ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/tools/ksvg2ico/ksvg2ico.cpp b/src/tools/ksvg2ico/ksvg2ico.cpp deleted file mode 100644 index 480d339..0000000 --- a/src/tools/ksvg2ico/ksvg2ico.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2007 Ralf Habacker * - * Copyright (C) 2017 René J.V. Bertin * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) version 3, or any * - * later version accepted by the membership of KDE e.V. (or its * - * successor approved by the membership of KDE e.V.), which shall * - * act as a proxy defined in Section 6 of version 3 of the license. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library. If not, see * - * . * - * * - ******************************************************************************/ - -/* - svg to ico format converter, adapted from KDEWin's sgv2ico tool. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "../../../kiconthemes_version.h" -// load our private QtIcoHandler copy, adapted from Qt 5.7.1 -#include "qicohandler.h" - -bool verbose = false; -bool debug = false; - -#include - -#define EXIT_ON_ERROR(isOk, ...) \ - do { \ - if (!(isOk)) { \ - fprintf(stderr, __VA_ARGS__); \ - return 1; \ - } \ - } while (false); - -bool svg2png(QSvgRenderer &renderer, const QString &outFile, int width, int height, QVector &imgList) -{ - QImage img(width, height, QImage::Format_ARGB32_Premultiplied); - img.fill(0); - - QPainter p(&img); - renderer.render(&p); - img.save(outFile, "PNG"); - imgList += img.convertToFormat(QImage::Format_ARGB32, Qt::ColorOnly|Qt::DiffuseAlphaDither|Qt::AvoidDither); - imgList += img.convertToFormat(QImage::Format_Indexed8, Qt::ColorOnly|Qt::DiffuseAlphaDither|Qt::AvoidDither); - return true; -} - -int main(int argc, char **argv) -{ - QGuiApplication app(argc, argv); - - QString rcFileName = ""; - - app.setApplicationName("ksvg2ico"); - app.setApplicationVersion(KICONTHEMES_VERSION_STRING); - QCommandLineParser parser; - parser.setApplicationDescription(app.translate("main", "Creates an ico file from an SVG image")); - parser.addPositionalArgument("input.sgv[z]", app.translate("main", "The SVG icon to convert")); - parser.addPositionalArgument("output.ico", app.translate("main", "The name of the resulting ico file")); - const QCommandLineOption verboseOption(QStringLiteral("verbose"), QStringLiteral("print execution details")); - const QCommandLineOption debugOption(QStringLiteral("debug"), - QStringLiteral("print debugging information and don't delete temporary files")); - const QCommandLineOption rcFileOption(QStringLiteral("rcfile"), - QStringLiteral("generate the named rc file for the icon"), - "rcfile", rcFileName); - parser.addOption(verboseOption); - parser.addOption(debugOption); - parser.addOption(rcFileOption); - parser.addHelpOption(); - parser.addVersionOption(); - - parser.process(app); - if (parser.positionalArguments().isEmpty()) { - parser.showHelp(); - return 1; - } - - bool isOk; - - if (parser.isSet(verboseOption)) { - verbose = true; - } - if (parser.isSet(debugOption)) { - debug = true; - } - - QString svgFile = parser.positionalArguments().at(0); - QString icoFile = parser.positionalArguments().at(1); - if (parser.isSet(rcFileOption)) { - rcFileName = parser.value(rcFileOption); - } - - QString pngFile = icoFile; - pngFile.replace(".ico", "-%1.png"); - - // create a temporary dir to create an iconset - QTemporaryDir tmpDir("ksvg2ico"); - tmpDir.setAutoRemove(!debug); - - isOk = tmpDir.isValid(); - EXIT_ON_ERROR(isOk, "Unable to create temporary directory\n"); - - QSvgRenderer renderer; - isOk = renderer.load(svgFile); - EXIT_ON_ERROR(isOk, "Unable to load %s\n", qPrintable(svgFile)); - - QVector imgList; - // generate PNG versions up to the largest size the ico format is guaranteed to handle: - foreach (int d, QVector({16, 32, 48, 64, 128, 256})) { - const QString pngSize = tmpDir.path() + "/" + pngFile.arg(d); - if (verbose) { - qDebug() << "converting" << svgFile << "to" << pngSize; - } - svg2png(renderer, pngSize, d, d, imgList); - } - if (debug || verbose) { - qWarning() << "Creating" << icoFile << "from:"; - foreach (const auto &img, imgList) { - qWarning() << img; - } - } - - QFile f(icoFile); - isOk = f.open(QIODevice::WriteOnly); - EXIT_ON_ERROR(isOk, "Can not open %s for writing", qPrintable(icoFile)); - - QtIcoHandler ico(&f); - isOk = ico.write(imgList); - f.close(); - EXIT_ON_ERROR(isOk, "Failure writing ico file %s\n", qPrintable(icoFile)); - - if (!rcFileName.isEmpty()) { - QFile rcFile(rcFileName); - if (!rcFile.open(QIODevice::WriteOnly)) { - EXIT_ON_ERROR(false, "Can not open %s for writing", qPrintable(rcFileName )); - } - QTextStream ts(&rcFile); - ts << QString( "IDI_ICON1 ICON DISCARDABLE \"%1\"\n" ).arg(icoFile); - rcFile.close(); - } - return !isOk; -} diff --git a/src/tools/ksvg2ico/qicohandler.cpp b/src/tools/ksvg2ico/qicohandler.cpp deleted file mode 100644 index 481eac2..0000000 --- a/src/tools/ksvg2ico/qicohandler.cpp +++ /dev/null @@ -1,966 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \class QtIcoHandler - \since 4.4 - \brief The QtIcoHandler class provides support for the ICO image format. - \internal -*/ - - - -#include "qicohandler.h" -#include -#include -#include -#include -#include - -// These next two structs represent how the icon information is stored -// in an ICO file. -typedef struct -{ - quint8 bWidth; // Width of the image - quint8 bHeight; // Height of the image (actual height, not times 2) - quint8 bColorCount; // Number of colors in image (0 if >=8bpp) [ not ture ] - quint8 bReserved; // Reserved - quint16 wPlanes; // Color Planes - quint16 wBitCount; // Bits per pixel - quint32 dwBytesInRes; // how many bytes in this resource? - quint32 dwImageOffset; // where in the file is this image -} ICONDIRENTRY, *LPICONDIRENTRY; -#define ICONDIRENTRY_SIZE 16 - -typedef struct -{ - quint16 idReserved; // Reserved - quint16 idType; // resource type (1 for icons, 2 for cursors) - quint16 idCount; // how many images? - ICONDIRENTRY idEntries[1]; // the entries for each image -} ICONDIR, *LPICONDIR; -#define ICONDIR_SIZE 6 // Exclude the idEntries field - -typedef struct { // BMP information header - quint32 biSize; // size of this struct - quint32 biWidth; // pixmap width - quint32 biHeight; // pixmap height (specifies the combined height of the XOR and AND masks) - quint16 biPlanes; // should be 1 - quint16 biBitCount; // number of bits per pixel - quint32 biCompression; // compression method - quint32 biSizeImage; // size of image - quint32 biXPelsPerMeter; // horizontal resolution - quint32 biYPelsPerMeter; // vertical resolution - quint32 biClrUsed; // number of colors used - quint32 biClrImportant; // number of important colors -} BMP_INFOHDR ,*LPBMP_INFOHDR; -#define BMP_INFOHDR_SIZE 40 - -class ICOReader -{ -public: - ICOReader(QIODevice * iodevice); -#ifdef QT_ICO_READ_SUPPORT - int count(); - QImage iconAt(int index); - static bool canRead(QIODevice *iodev); - - static QVector read(QIODevice *device); - bool readIconEntry(int index, ICONDIRENTRY * iconEntry); -#endif - static bool write(QIODevice *device, const QVector &images); - - -#ifdef QT_ICO_READ_SUPPORT -private: - bool readHeader(); - - bool readBMPHeader(quint32 imageOffset, BMP_INFOHDR * header); - void findColorInfo(QImage & image); - void readColorTable(QImage & image); - - void readBMP(QImage & image); - void read1BitBMP(QImage & image); - void read4BitBMP(QImage & image); - void read8BitBMP(QImage & image); - void read16_24_32BMP(QImage & image); - - struct IcoAttrib - { - int nbits; - int ncolors; - int h; - int w; - int depth; - } icoAttrib; - - QIODevice * iod; - qint64 startpos; - bool headerRead; - ICONDIR iconDir; -#endif -}; - -#ifdef QT_ICO_READ_SUPPORT -// Data readers and writers that takes care of alignment and endian stuff. -static bool readIconDirEntry(QIODevice *iodev, ICONDIRENTRY *iconDirEntry) -{ - if (iodev) { - uchar tmp[ICONDIRENTRY_SIZE]; - if (iodev->read((char*)tmp, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE) { - iconDirEntry->bWidth = tmp[0]; - iconDirEntry->bHeight = tmp[1]; - iconDirEntry->bColorCount = tmp[2]; - iconDirEntry->bReserved = tmp[3]; - - iconDirEntry->wPlanes = qFromLittleEndian(&tmp[4]); - iconDirEntry->wBitCount = qFromLittleEndian(&tmp[6]); - iconDirEntry->dwBytesInRes = qFromLittleEndian(&tmp[8]); - iconDirEntry->dwImageOffset = qFromLittleEndian(&tmp[12]); - return true; - } - } - return false; -} -#endif - -static bool writeIconDirEntry(QIODevice *iodev, const ICONDIRENTRY &iconEntry) -{ - if (iodev) { - uchar tmp[ICONDIRENTRY_SIZE]; - tmp[0] = iconEntry.bWidth; - tmp[1] = iconEntry.bHeight; - tmp[2] = iconEntry.bColorCount; - tmp[3] = iconEntry.bReserved; - qToLittleEndian(iconEntry.wPlanes, &tmp[4]); - qToLittleEndian(iconEntry.wBitCount, &tmp[6]); - qToLittleEndian(iconEntry.dwBytesInRes, &tmp[8]); - qToLittleEndian(iconEntry.dwImageOffset, &tmp[12]); - return iodev->write((char*)tmp, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE; - } - - return false; -} - -#ifdef QT_ICO_READ_SUPPORT -static bool readIconDir(QIODevice *iodev, ICONDIR *iconDir) -{ - if (iodev) { - uchar tmp[ICONDIR_SIZE]; - if (iodev->read((char*)tmp, ICONDIR_SIZE) == ICONDIR_SIZE) { - iconDir->idReserved = qFromLittleEndian(&tmp[0]); - iconDir->idType = qFromLittleEndian(&tmp[2]); - iconDir->idCount = qFromLittleEndian(&tmp[4]); - return true; - } - } - return false; -} -#endif - -static bool writeIconDir(QIODevice *iodev, const ICONDIR &iconDir) -{ - if (iodev) { - uchar tmp[6]; - qToLittleEndian(iconDir.idReserved, tmp); - qToLittleEndian(iconDir.idType, &tmp[2]); - qToLittleEndian(iconDir.idCount, &tmp[4]); - return iodev->write((char*)tmp, 6) == 6; - } - return false; -} - -#ifdef QT_ICO_READ_SUPPORT -static bool readBMPInfoHeader(QIODevice *iodev, BMP_INFOHDR *pHeader) -{ - if (iodev) { - uchar header[BMP_INFOHDR_SIZE]; - if (iodev->read((char*)header, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE) { - pHeader->biSize = qFromLittleEndian(&header[0]); - pHeader->biWidth = qFromLittleEndian(&header[4]); - pHeader->biHeight = qFromLittleEndian(&header[8]); - pHeader->biPlanes = qFromLittleEndian(&header[12]); - pHeader->biBitCount = qFromLittleEndian(&header[14]); - pHeader->biCompression = qFromLittleEndian(&header[16]); - pHeader->biSizeImage = qFromLittleEndian(&header[20]); - pHeader->biXPelsPerMeter = qFromLittleEndian(&header[24]); - pHeader->biYPelsPerMeter = qFromLittleEndian(&header[28]); - pHeader->biClrUsed = qFromLittleEndian(&header[32]); - pHeader->biClrImportant = qFromLittleEndian(&header[36]); - return true; - } - } - return false; -} -#endif - -static bool writeBMPInfoHeader(QIODevice *iodev, const BMP_INFOHDR &header) -{ - if (iodev) { - uchar tmp[BMP_INFOHDR_SIZE]; - qToLittleEndian(header.biSize, &tmp[0]); - qToLittleEndian(header.biWidth, &tmp[4]); - qToLittleEndian(header.biHeight, &tmp[8]); - qToLittleEndian(header.biPlanes, &tmp[12]); - qToLittleEndian(header.biBitCount, &tmp[14]); - qToLittleEndian(header.biCompression, &tmp[16]); - qToLittleEndian(header.biSizeImage, &tmp[20]); - qToLittleEndian(header.biXPelsPerMeter, &tmp[24]); - qToLittleEndian(header.biYPelsPerMeter, &tmp[28]); - qToLittleEndian(header.biClrUsed, &tmp[32]); - qToLittleEndian(header.biClrImportant, &tmp[36]); - - return iodev->write((char*)tmp, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE; - } - return false; -} - - -#ifdef QT_ICO_READ_SUPPORT -ICOReader::ICOReader(QIODevice * iodevice) - : iod(iodevice) - , startpos(0) - , headerRead(false) -{ -} -#else -ICOReader::ICOReader(QIODevice *) -{ -} -#endif - -#ifdef QT_ICO_READ_SUPPORT -int ICOReader::count() -{ - if (readHeader()) - return iconDir.idCount; - return 0; -} - -bool ICOReader::canRead(QIODevice *iodev) -{ - bool isProbablyICO = false; - if (iodev) { - qint64 oldPos = iodev->pos(); - - ICONDIR ikonDir; - if (readIconDir(iodev, &ikonDir)) { - qint64 readBytes = ICONDIR_SIZE; - if (readIconDirEntry(iodev, &ikonDir.idEntries[0])) { - readBytes += ICONDIRENTRY_SIZE; - // ICO format does not have a magic identifier, so we read 6 different values, which will hopefully be enough to identify the file. - if ( ikonDir.idReserved == 0 - && (ikonDir.idType == 1 || ikonDir.idType == 2) - && ikonDir.idEntries[0].bReserved == 0 - && (ikonDir.idEntries[0].wPlanes <= 1 || ikonDir.idType == 2) - && (ikonDir.idEntries[0].wBitCount <= 32 || ikonDir.idType == 2) // Bits per pixel - && ikonDir.idEntries[0].dwBytesInRes >= 40 // Must be over 40, since sizeof (infoheader) == 40 - ) { - isProbablyICO = true; - } - - if (iodev->isSequential()) { - // Our structs might be padded due to alignment, so we need to fetch each member before we ungetChar() ! - quint32 tmp = ikonDir.idEntries[0].dwImageOffset; - iodev->ungetChar((tmp >> 24) & 0xff); - iodev->ungetChar((tmp >> 16) & 0xff); - iodev->ungetChar((tmp >> 8) & 0xff); - iodev->ungetChar(tmp & 0xff); - - tmp = ikonDir.idEntries[0].dwBytesInRes; - iodev->ungetChar((tmp >> 24) & 0xff); - iodev->ungetChar((tmp >> 16) & 0xff); - iodev->ungetChar((tmp >> 8) & 0xff); - iodev->ungetChar(tmp & 0xff); - - tmp = ikonDir.idEntries[0].wBitCount; - iodev->ungetChar((tmp >> 8) & 0xff); - iodev->ungetChar(tmp & 0xff); - - tmp = ikonDir.idEntries[0].wPlanes; - iodev->ungetChar((tmp >> 8) & 0xff); - iodev->ungetChar(tmp & 0xff); - - iodev->ungetChar(ikonDir.idEntries[0].bReserved); - iodev->ungetChar(ikonDir.idEntries[0].bColorCount); - iodev->ungetChar(ikonDir.idEntries[0].bHeight); - iodev->ungetChar(ikonDir.idEntries[0].bWidth); - } - } - - if (iodev->isSequential()) { - // Our structs might be padded due to alignment, so we need to fetch each member before we ungetChar() ! - quint32 tmp = ikonDir.idCount; - iodev->ungetChar((tmp >> 8) & 0xff); - iodev->ungetChar(tmp & 0xff); - - tmp = ikonDir.idType; - iodev->ungetChar((tmp >> 8) & 0xff); - iodev->ungetChar(tmp & 0xff); - - tmp = ikonDir.idReserved; - iodev->ungetChar((tmp >> 8) & 0xff); - iodev->ungetChar(tmp & 0xff); - } - } - if (!iodev->isSequential()) iodev->seek(oldPos); - } - - return isProbablyICO; -} - -bool ICOReader::readHeader() -{ - if (iod && !headerRead) { - startpos = iod->pos(); - if (readIconDir(iod, &iconDir)) { - if (iconDir.idReserved == 0 && (iconDir.idType == 1 || iconDir.idType == 2)) - headerRead = true; - } - } - - return headerRead; -} - -bool ICOReader::readIconEntry(int index, ICONDIRENTRY *iconEntry) -{ - if (readHeader()) { - if (iod->seek(startpos + ICONDIR_SIZE + (index * ICONDIRENTRY_SIZE))) { - return readIconDirEntry(iod, iconEntry); - } - } - return false; -} - -bool ICOReader::readBMPHeader(quint32 imageOffset, BMP_INFOHDR * header) -{ - if (iod) { - if (iod->seek(startpos + imageOffset)) { - if (readBMPInfoHeader(iod, header)) { - return true; - } - } - } - return false; -} - -void ICOReader::findColorInfo(QImage & image) -{ - if (icoAttrib.ncolors > 0) { - // set color table - readColorTable(image); - } else if (icoAttrib.nbits == 16) { - // don't support RGB values for 15/16 bpp - image = QImage(); - } -} - -void ICOReader::readColorTable(QImage & image) -{ - if (iod) { - image.setColorCount(icoAttrib.ncolors); - uchar rgb[4]; - for (int i=0; iread((char*)rgb, 4) != 4) { - image = QImage(); - break; - } - image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0])); - } - } else { - image = QImage(); - } -} - -void ICOReader::readBMP(QImage & image) -{ - if (icoAttrib.nbits == 1) { - // 1 bit BMP image - read1BitBMP(image); - } else if (icoAttrib.nbits == 4) { - // 4 bit BMP image - read4BitBMP(image); - } else if (icoAttrib.nbits == 8) { - read8BitBMP(image); - } else if (icoAttrib.nbits == 16 || icoAttrib.nbits == 24 || icoAttrib.nbits == 32 ) { - // 16,24,32 bit BMP image - read16_24_32BMP(image); - } -} - - -/** - * NOTE: A 1 bit BMP is only flipped vertically, and not horizontally like all other color depths! - * (This is the same with the bitmask) - * - */ -void ICOReader::read1BitBMP(QImage & image) -{ - if (iod) { - int h = image.height(); - int bpl = image.bytesPerLine(); - - while (--h >= 0) { - if (iod->read((char*)image.scanLine(h),bpl) != bpl) { - image = QImage(); - break; - } - } - } else { - image = QImage(); - } -} - -void ICOReader::read4BitBMP(QImage & image) -{ - if (iod) { - - int h = icoAttrib.h; - int buflen = ((icoAttrib.w+7)/8)*4; - uchar *buf = new uchar[buflen]; - Q_CHECK_PTR(buf); - - while (--h >= 0) { - if (iod->read((char*)buf,buflen) != buflen) { - image = QImage(); - break; - } - uchar *p = image.scanLine(h); - uchar *b = buf; - for (int i=0; i> 4; - *p++ = *b++ & 0x0f; - } - if (icoAttrib.w & 1) { - // the last nibble - *p = *b >> 4; - } - } - - delete [] buf; - - } else { - image = QImage(); - } -} - -void ICOReader::read8BitBMP(QImage & image) -{ - if (iod) { - int h = icoAttrib.h; - int bpl = image.bytesPerLine(); - - while (--h >= 0) { - if (iod->read((char *)image.scanLine(h), bpl) != bpl) { - image = QImage(); - break; - } - } - } else { - image = QImage(); - } -} - -void ICOReader::read16_24_32BMP(QImage & image) -{ - if (iod) { - int h = icoAttrib.h; - QRgb *p; - QRgb *end; - uchar *buf = new uchar[image.bytesPerLine()]; - int bpl = ((icoAttrib.w*icoAttrib.nbits+31)/32)*4; - uchar *b; - - while (--h >= 0) { - p = (QRgb *)image.scanLine(h); - end = p + icoAttrib.w; - if (iod->read((char *)buf, bpl) != bpl) { - image = QImage(); - break; - } - b = buf; - while (p < end) { - if (icoAttrib.nbits == 24) - *p++ = qRgb(*(b+2), *(b+1), *b); - else if (icoAttrib.nbits == 32) - *p++ = qRgba(*(b+2), *(b+1), *b, *(b+3)); - b += icoAttrib.nbits/8; - } - } - - delete[] buf; - - } else { - image = QImage(); - } -} - -static const char icoOrigDepthKey[] = "_q_icoOrigDepth"; - -QImage ICOReader::iconAt(int index) -{ - QImage img; - - if (count() > index) { // forces header to be read - - ICONDIRENTRY iconEntry; - if (readIconEntry(index, &iconEntry)) { - - static const uchar pngMagicData[] = { 137, 80, 78, 71, 13, 10, 26, 10 }; - - iod->seek(iconEntry.dwImageOffset); - - const QByteArray pngMagic = QByteArray::fromRawData((const char*)pngMagicData, sizeof(pngMagicData)); - const bool isPngImage = (iod->read(pngMagic.size()) == pngMagic); - - if (isPngImage) { - iod->seek(iconEntry.dwImageOffset); - QImage image = QImage::fromData(iod->read(iconEntry.dwBytesInRes), "png"); - image.setText(QLatin1String(icoOrigDepthKey), QString::number(iconEntry.wBitCount)); - return image; - } - - BMP_INFOHDR header; - if (readBMPHeader(iconEntry.dwImageOffset, &header)) { - icoAttrib.nbits = header.biBitCount ? header.biBitCount : iconEntry.wBitCount; - - switch (icoAttrib.nbits) { - case 32: - case 24: - case 16: - icoAttrib.depth = 32; - break; - case 8: - case 4: - icoAttrib.depth = 8; - break; - default: - icoAttrib.depth = 1; - } - if (icoAttrib.depth == 32) // there's no colormap - icoAttrib.ncolors = 0; - else // # colors used - icoAttrib.ncolors = header.biClrUsed ? header.biClrUsed : 1 << icoAttrib.nbits; - if (icoAttrib.ncolors > 256) //color table can't be more than 256 - return img; - icoAttrib.w = iconEntry.bWidth; - if (icoAttrib.w == 0) // means 256 pixels - icoAttrib.w = header.biWidth; - icoAttrib.h = iconEntry.bHeight; - if (icoAttrib.h == 0) // means 256 pixels - icoAttrib.h = header.biHeight/2; - - QImage::Format format = QImage::Format_ARGB32; - if (icoAttrib.nbits == 24) - format = QImage::Format_RGB32; - else if (icoAttrib.ncolors == 2 && icoAttrib.depth == 1) - format = QImage::Format_Mono; - else if (icoAttrib.ncolors > 0) - format = QImage::Format_Indexed8; - - QImage image(icoAttrib.w, icoAttrib.h, format); - if (!image.isNull()) { - findColorInfo(image); - if (!image.isNull()) { - readBMP(image); - if (!image.isNull()) { - QImage mask(image.width(), image.height(), QImage::Format_Mono); - if (!mask.isNull()) { - mask.setColorCount(2); - mask.setColor(0, qRgba(255,255,255,0xff)); - mask.setColor(1, qRgba(0 ,0 ,0 ,0xff)); - read1BitBMP(mask); - if (!mask.isNull()) { - img = image; - img.setAlphaChannel(mask); - // (Luckily, it seems that setAlphaChannel() does not ruin the alpha values - // of partially transparent pixels in those icons that have that) - } - } - } - } - } - img.setText(QLatin1String(icoOrigDepthKey), QString::number(iconEntry.wBitCount)); - } - } - } - - return img; -} - - -/*! - Reads all the icons from the given \a device, and returns them as - a list of QImage objects. - - Each image has an alpha channel that represents the mask from the - corresponding icon. - - \sa write() -*/ -QVector ICOReader::read(QIODevice *device) -{ - QVector images; - - ICOReader reader(device); - const int N = reader.count(); - images.reserve(N); - for (int i = 0; i < N; i++) - images += reader.iconAt(i); - - return images; -} -#endif - -/*! - Writes all the QImages in the \a images list to the given \a - device. Returns \c true if the images are written successfully; - otherwise returns \c false. - - The first image in the list is stored as the first icon in the - device, and is therefore used as the default icon by applications. - The alpha channel of each image is converted to a mask for each - corresponding icon. - - \sa read() -*/ -bool ICOReader::write(QIODevice *device, const QVector &images) -{ - bool retValue = false; - - if (images.count()) { - - qint64 origOffset = device->pos(); - - ICONDIR id; - id.idReserved = 0; - id.idType = 1; - id.idCount = images.count(); - - ICONDIRENTRY * entries = new ICONDIRENTRY[id.idCount]; - BMP_INFOHDR * bmpHeaders = new BMP_INFOHDR[id.idCount]; - QByteArray * imageData = new QByteArray[id.idCount]; - - for (int i=0; i 256 || image.height() > 256) - { - image = image.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); - } - QImage maskImage(image.width(), image.height(), QImage::Format_Mono); - image = image.convertToFormat(QImage::Format_ARGB32); - - if (image.hasAlphaChannel()) { - maskImage = image.createAlphaMask(); - } else { - maskImage.fill(0xff); - } - maskImage = maskImage.convertToFormat(QImage::Format_Mono); - - int nbits = 32; - int bpl_bmp = ((image.width()*nbits+31)/32)*4; - - entries[i].bColorCount = 0; - entries[i].bReserved = 0; - entries[i].wBitCount = nbits; - entries[i].bHeight = image.height() < 256 ? image.height() : 0; // 0 means 256 - entries[i].bWidth = image.width() < 256 ? image.width() : 0; // 0 means 256 - entries[i].dwBytesInRes = BMP_INFOHDR_SIZE + (bpl_bmp * image.height()) - + (maskImage.bytesPerLine() * maskImage.height()); - entries[i].wPlanes = 1; - if (i == 0) - entries[i].dwImageOffset = origOffset + ICONDIR_SIZE - + (id.idCount * ICONDIRENTRY_SIZE); - else - entries[i].dwImageOffset = entries[i-1].dwImageOffset + entries[i-1].dwBytesInRes; - - bmpHeaders[i].biBitCount = entries[i].wBitCount; - bmpHeaders[i].biClrImportant = 0; - bmpHeaders[i].biClrUsed = entries[i].bColorCount; - bmpHeaders[i].biCompression = 0; - bmpHeaders[i].biHeight = entries[i].bHeight ? entries[i].bHeight * 2 : 256 * 2; // 2 is for the mask - bmpHeaders[i].biPlanes = entries[i].wPlanes; - bmpHeaders[i].biSize = BMP_INFOHDR_SIZE; - bmpHeaders[i].biSizeImage = entries[i].dwBytesInRes - BMP_INFOHDR_SIZE; - bmpHeaders[i].biWidth = entries[i].bWidth ? entries[i].bWidth : 256; - bmpHeaders[i].biXPelsPerMeter = 0; - bmpHeaders[i].biYPelsPerMeter = 0; - - QBuffer buffer(&imageData[i]); - buffer.open(QIODevice::WriteOnly); - - uchar *buf = new uchar[bpl_bmp]; - uchar *b; - memset( buf, 0, bpl_bmp ); - int y; - for (y = image.height() - 1; y >= 0; y--) { // write the image bits - // 32 bits - QRgb *p = (QRgb *)image.scanLine(y); - QRgb *end = p + image.width(); - b = buf; - int x = 0; - while (p < end) { - *b++ = qBlue(*p); - *b++ = qGreen(*p); - *b++ = qRed(*p); - *b++ = qAlpha(*p); - if (qAlpha(*p) > 0) // Even mostly transparent pixels must not be masked away - maskImage.setPixel(x, y, Qt::color1); // (i.e. createAlphaMask() takes away too much) - p++; - x++; - } - buffer.write((char*)buf, bpl_bmp); - } - delete[] buf; - - maskImage.invertPixels(); // seems as though it needs this - // NOTE! !! The mask is only flipped vertically - not horizontally !! - for (y = maskImage.height() - 1; y >= 0; y--) - buffer.write((char*)maskImage.scanLine(y), maskImage.bytesPerLine()); - - } - - if (writeIconDir(device, id)) { - int i; - bool bOK = true; - for (i = 0; i < id.idCount && bOK; i++) { - bOK = writeIconDirEntry(device, entries[i]); - } - if (bOK) { - for (i = 0; i < id.idCount && bOK; i++) { - bOK = writeBMPInfoHeader(device, bmpHeaders[i]); - bOK &= (device->write(imageData[i]) == (int) imageData[i].size()); - } - retValue = bOK; - } - } - - delete [] entries; - delete [] bmpHeaders; - delete [] imageData; - - } - return retValue; -} - -/*! - Constructs an instance of QtIcoHandler initialized to use \a device. -*/ -QtIcoHandler::QtIcoHandler(QIODevice *device) -{ - setDevice(device); -#ifdef QT_ICO_READ_SUPPORT - m_currentIconIndex = 0; - m_pICOReader = new ICOReader(device); -#endif -} - -/*! - Destructor for QtIcoHandler. -*/ -QtIcoHandler::~QtIcoHandler() -{ -#ifdef QT_ICO_READ_SUPPORT - delete m_pICOReader; -#endif -} - -QVariant QtIcoHandler::option(ImageOption option) const -{ -#ifdef QT_ICO_READ_SUPPORT - if (option == Size || option == ImageFormat) { - ICONDIRENTRY iconEntry; - if (m_pICOReader->readIconEntry(m_currentIconIndex, &iconEntry)) { - switch (option) { - case Size: - return QSize(iconEntry.bWidth ? iconEntry.bWidth : 256, - iconEntry.bHeight ? iconEntry.bHeight : 256); - - case ImageFormat: - switch (iconEntry.wBitCount) { - case 2: - return QImage::Format_Mono; - case 24: - return QImage::Format_RGB32; - case 32: - return QImage::Format_ARGB32; - default: - return QImage::Format_Indexed8; - } - break; - default: - break; - } - } - } -#else - Q_UNUSED(option); -#endif - return QVariant(); -} - -bool QtIcoHandler::supportsOption(ImageOption option) const -{ - return (option == Size || option == ImageFormat); -} - -/*! - * Verifies if some values (magic bytes) are set as expected in the header of the file. - * If the magic bytes were found, it is assumed that the QtIcoHandler can read the file. - * - */ -bool QtIcoHandler::canRead() const -{ - bool bCanRead = false; -#ifdef QT_ICO_READ_SUPPORT - QIODevice *device = QImageIOHandler::device(); - if (device) { - bCanRead = ICOReader::canRead(device); - if (bCanRead) - setFormat("ico"); - } else { - qWarning("QtIcoHandler::canRead() called with no device"); - } -#endif - return bCanRead; -} - -/*! This static function is used by the plugin code, and is provided for convenience only. - \a device must be an opened device with pointing to the start of the header data of the ICO file. -*/ -bool QtIcoHandler::canRead(QIODevice *device) -{ - Q_ASSERT(device); -#ifdef QT_ICO_READ_SUPPORT - return ICOReader::canRead(device); -#else - return false; -#endif -} - -/*! \reimp - -*/ -bool QtIcoHandler::read(QImage *image) -{ - bool bSuccess = false; -#ifdef QT_ICO_READ_SUPPORT - QImage img = m_pICOReader->iconAt(m_currentIconIndex); - - // Make sure we only write to \a image when we succeed. - if (!img.isNull()) { - bSuccess = true; - *image = img; - } -#else - Q_UNUSED(image); -#endif - return bSuccess; -} - -/*! \reimp - -*/ -bool QtIcoHandler::write(const QImage &image) -{ - QIODevice *device = QImageIOHandler::device(); - QVector imgs; - imgs.append(image); - return ICOReader::write(device, imgs); -} - -bool QtIcoHandler::write(const QVector &images) -{ - QIODevice *device = QImageIOHandler::device(); - return ICOReader::write(device, images); -} - -/*! - * Return the common identifier of the format. - * For ICO format this will return "ico". - */ -QByteArray QtIcoHandler::name() const -{ - return "ico"; -} - - -/*! \reimp - -*/ -int QtIcoHandler::imageCount() const -{ -#ifdef QT_ICO_READ_SUPPORT - return m_pICOReader->count(); -#else - return 0; -#endif -} - -/*! \reimp - -*/ -bool QtIcoHandler::jumpToImage(int imageNumber) -{ -#ifdef QT_ICO_READ_SUPPORT - if (imageNumber < imageCount()) { - m_currentIconIndex = imageNumber; - return true; - } -#else - Q_UNUSED(imageNumber); -#endif - return false; -} - -/*! \reimp - -*/ -bool QtIcoHandler::jumpToNextImage() -{ -#ifdef QT_ICO_READ_SUPPORT - return jumpToImage(m_currentIconIndex + 1); -#else - return false; -#endif -} diff --git a/src/tools/ksvg2ico/qicohandler.h b/src/tools/ksvg2ico/qicohandler.h deleted file mode 100644 index 2f35322..0000000 --- a/src/tools/ksvg2ico/qicohandler.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QTICOHANDLER_H -#define QTICOHANDLER_H - -#include -#include - -#ifdef QT_ICO_READ_SUPPORT -class ICOReader; -#endif - -class QtIcoHandler: public QImageIOHandler -{ -public: - QtIcoHandler(QIODevice *device); - virtual ~QtIcoHandler(); - - bool canRead() const Q_DECL_OVERRIDE; - bool read(QImage *image) Q_DECL_OVERRIDE; - bool write(const QImage &image) Q_DECL_OVERRIDE; - bool write(const QVector &images); - - QByteArray name() const Q_DECL_OVERRIDE; - - int imageCount() const Q_DECL_OVERRIDE; - bool jumpToImage(int imageNumber) Q_DECL_OVERRIDE; - bool jumpToNextImage() Q_DECL_OVERRIDE; - - static bool canRead(QIODevice *device); - - bool supportsOption(ImageOption option) const Q_DECL_OVERRIDE; - QVariant option(ImageOption option) const Q_DECL_OVERRIDE; - -#ifdef QT_ICO_READ_SUPPORT -private: - int m_currentIconIndex; - ICOReader *m_pICOReader; -#endif -}; - -#endif /* QTICOHANDLER_H */ -