File indexing completed on 2024-05-12 03:55:45
0001 /* 0002 SPDX-FileCopyrightText: 2014 Harald Fernengel <harry@kdevelop.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 /* This tool converts an svg to a Mac OS X icns file. 0008 * Note: Requires the 'iconutil' Mac OS X binary 0009 */ 0010 0011 #include <QCommandLineParser> 0012 #include <QFileInfo> 0013 #include <QProcess> 0014 #include <QTemporaryDir> 0015 0016 #include <QGuiApplication> 0017 #include <QPainter> 0018 #include <QStandardPaths> 0019 #include <QSvgRenderer> 0020 0021 #include "../../kiconthemes_version.h" 0022 0023 #include <stdio.h> 0024 0025 /* clang-format off */ 0026 #define EXIT_ON_ERROR(isOk, ...) \ 0027 do { \ 0028 if (!(isOk)) { \ 0029 fprintf(stderr, __VA_ARGS__); \ 0030 return 1; \ 0031 } \ 0032 } while (false); 0033 /* clang-format on */ 0034 0035 static bool writeImage(QSvgRenderer &svg, int size, const QString &outFile1, const QString &outFile2 = QString()) 0036 { 0037 QImage out(size, size, QImage::Format_ARGB32); 0038 out.fill(Qt::transparent); 0039 0040 QPainter painter(&out); 0041 svg.setAspectRatioMode(Qt::KeepAspectRatio); 0042 svg.render(&painter); 0043 painter.end(); 0044 0045 if (!out.save(outFile1)) { 0046 fprintf(stderr, "Unable to write %s\n", qPrintable(outFile1)); 0047 return false; 0048 } 0049 if (!outFile2.isEmpty() && !out.save(outFile2)) { 0050 fprintf(stderr, "Unable to write %s\n", qPrintable(outFile2)); 0051 return false; 0052 } 0053 0054 return true; 0055 } 0056 0057 int main(int argc, char *argv[]) 0058 { 0059 QGuiApplication app(argc, argv); 0060 0061 app.setApplicationName(QStringLiteral("ksvg2icns")); 0062 app.setApplicationVersion(QStringLiteral(KICONTHEMES_VERSION_STRING)); 0063 QCommandLineParser parser; 0064 parser.setApplicationDescription(app.translate("main", "Creates an icns file from an svg image")); 0065 parser.addPositionalArgument("iconname", app.translate("main", "The svg icon to convert")); 0066 parser.addHelpOption(); 0067 0068 parser.process(app); 0069 if (parser.positionalArguments().isEmpty()) { 0070 parser.showHelp(); 0071 return 1; 0072 } 0073 0074 bool isOk; 0075 0076 // create a temporary dir to create an iconset 0077 QTemporaryDir tmpDir(QDir::tempPath() + QStringLiteral("/ksvg2icns")); 0078 0079 isOk = tmpDir.isValid(); 0080 EXIT_ON_ERROR(isOk, "Unable to create temporary directory\n"); 0081 0082 const QString outPath = tmpDir.filePath(QStringLiteral("out.iconset")); 0083 0084 isOk = QDir(tmpDir.path()).mkpath(outPath); 0085 EXIT_ON_ERROR(isOk, "Unable to create out.iconset directory\n"); 0086 0087 const QStringList &args = app.arguments(); 0088 EXIT_ON_ERROR(args.size() == 2, "Usage: %s svg-image\n", qPrintable(args.value(0))); 0089 0090 const QString &svgFileName = args.at(1); 0091 0092 // open the actual svg file 0093 QSvgRenderer svg; 0094 isOk = svg.load(svgFileName); 0095 EXIT_ON_ERROR(isOk, "Unable to load %s\n", qPrintable(svgFileName)); 0096 0097 // The sizes are from: 0098 // https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html 0099 0100 struct OutFiles { 0101 int size; 0102 QString out1; 0103 QString out2; 0104 }; 0105 0106 // create the pngs in various resolutions 0107 const OutFiles outFiles[] = {{1024, outPath + QStringLiteral("/icon_512x512@2x.png"), QString()}, 0108 {512, outPath + QStringLiteral("/icon_512x512.png"), outPath + QStringLiteral("/icon_256x256@2x.png")}, 0109 {256, outPath + QStringLiteral("/icon_256x256.png"), outPath + QStringLiteral("/icon_128x128@2x.png")}, 0110 {128, outPath + QStringLiteral("/icon_128x128.png"), QString()}, 0111 {64, outPath + QStringLiteral("/icon_32x32@2x.png"), QString()}, 0112 {32, outPath + QStringLiteral("/icon_32x32.png"), outPath + QStringLiteral("/icon_16x16@2x.png")}, 0113 {16, outPath + QStringLiteral("/icon_16x16.png"), QString()}}; 0114 0115 for (const OutFiles &outFile : outFiles) { 0116 isOk = writeImage(svg, outFile.size, outFile.out1, outFile.out2); 0117 if (!isOk) { 0118 return 1; 0119 } 0120 } 0121 0122 // convert the iconset to icns using the "iconutil" command 0123 const QString iconutilExec = QStandardPaths::findExecutable(QStringLiteral("iconutil")); 0124 if (iconutilExec.isEmpty()) { 0125 EXIT_ON_ERROR(false, "Could not find iconutil executable in PATH.\n"); 0126 } 0127 0128 const QString outIcns = QFileInfo(svgFileName).baseName() + QStringLiteral(".icns"); 0129 0130 const QStringList utilArgs = QStringList() << "-c" 0131 << "icns" 0132 << "-o" << outIcns << outPath; 0133 0134 QProcess iconUtil; 0135 0136 iconUtil.start(iconutilExec, utilArgs, QIODevice::ReadOnly); 0137 isOk = iconUtil.waitForFinished(-1); 0138 EXIT_ON_ERROR(isOk, "Unable to launch iconutil: %s\n", qPrintable(iconUtil.errorString())); 0139 0140 EXIT_ON_ERROR(iconUtil.exitStatus() == QProcess::NormalExit, "iconutil crashed!\n"); 0141 EXIT_ON_ERROR(iconUtil.exitCode() == 0, "iconutil returned %d\n", iconUtil.exitCode()); 0142 0143 return 0; 0144 }