KIconThemes

ksvg2icns.cpp
1/*
2 SPDX-FileCopyrightText: 2014 Harald Fernengel <harry@kdevelop.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7/* This tool converts an svg to a Mac OS X icns file.
8 * Note: Requires the 'iconutil' Mac OS X binary
9 */
10
11#include <QCommandLineParser>
12#include <QFileInfo>
13#include <QProcess>
14#include <QTemporaryDir>
15
16#include <QGuiApplication>
17#include <QPainter>
18#include <QStandardPaths>
19#include <QSvgRenderer>
20
21#include "../../kiconthemes_version.h"
22
23#include <stdio.h>
24
25/* clang-format off */
26#define EXIT_ON_ERROR(isOk, ...) \
27 do { \
28 if (!(isOk)) { \
29 fprintf(stderr, __VA_ARGS__); \
30 return 1; \
31 } \
32 } while (false);
33/* clang-format on */
34
35static bool writeImage(QSvgRenderer &svg, int size, const QString &outFile1, const QString &outFile2 = QString())
36{
37 QImage out(size, size, QImage::Format_ARGB32);
38 out.fill(Qt::transparent);
39
40 QPainter painter(&out);
42 svg.render(&painter);
43 painter.end();
44
45 if (!out.save(outFile1)) {
46 fprintf(stderr, "Unable to write %s\n", qPrintable(outFile1));
47 return false;
48 }
49 if (!outFile2.isEmpty() && !out.save(outFile2)) {
50 fprintf(stderr, "Unable to write %s\n", qPrintable(outFile2));
51 return false;
52 }
53
54 return true;
55}
56
57int main(int argc, char *argv[])
58{
59 QGuiApplication app(argc, argv);
60
61 app.setApplicationName(QStringLiteral("ksvg2icns"));
62 app.setApplicationVersion(QStringLiteral(KICONTHEMES_VERSION_STRING));
63 QCommandLineParser parser;
64 parser.setApplicationDescription(app.translate("main", "Creates an icns file from an svg image"));
65 parser.addPositionalArgument("iconname", app.translate("main", "The svg icon to convert"));
66 parser.addHelpOption();
67
68 parser.process(app);
69 if (parser.positionalArguments().isEmpty()) {
70 parser.showHelp();
71 return 1;
72 }
73
74 bool isOk;
75
76 // create a temporary dir to create an iconset
77 QTemporaryDir tmpDir(QDir::tempPath() + QStringLiteral("/ksvg2icns"));
78
79 isOk = tmpDir.isValid();
80 EXIT_ON_ERROR(isOk, "Unable to create temporary directory\n");
81
82 const QString outPath = tmpDir.filePath(QStringLiteral("out.iconset"));
83
84 isOk = QDir(tmpDir.path()).mkpath(outPath);
85 EXIT_ON_ERROR(isOk, "Unable to create out.iconset directory\n");
86
87 const QStringList &args = app.arguments();
88 EXIT_ON_ERROR(args.size() == 2, "Usage: %s svg-image\n", qPrintable(args.value(0)));
89
90 const QString &svgFileName = args.at(1);
91
92 // open the actual svg file
93 QSvgRenderer svg;
94 isOk = svg.load(svgFileName);
95 EXIT_ON_ERROR(isOk, "Unable to load %s\n", qPrintable(svgFileName));
96
97 // The sizes are from:
98 // https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html
99
100 struct OutFiles {
101 int size;
102 QString out1;
103 QString out2;
104 };
105
106 // create the pngs in various resolutions
107 const OutFiles outFiles[] = {{1024, outPath + QStringLiteral("/icon_512x512@2x.png"), QString()},
108 {512, outPath + QStringLiteral("/icon_512x512.png"), outPath + QStringLiteral("/icon_256x256@2x.png")},
109 {256, outPath + QStringLiteral("/icon_256x256.png"), outPath + QStringLiteral("/icon_128x128@2x.png")},
110 {128, outPath + QStringLiteral("/icon_128x128.png"), QString()},
111 {64, outPath + QStringLiteral("/icon_32x32@2x.png"), QString()},
112 {32, outPath + QStringLiteral("/icon_32x32.png"), outPath + QStringLiteral("/icon_16x16@2x.png")},
113 {16, outPath + QStringLiteral("/icon_16x16.png"), QString()}};
114
115 for (const OutFiles &outFile : outFiles) {
116 isOk = writeImage(svg, outFile.size, outFile.out1, outFile.out2);
117 if (!isOk) {
118 return 1;
119 }
120 }
121
122 // convert the iconset to icns using the "iconutil" command
123 const QString iconutilExec = QStandardPaths::findExecutable(QStringLiteral("iconutil"));
124 if (iconutilExec.isEmpty()) {
125 EXIT_ON_ERROR(false, "Could not find iconutil executable in PATH.\n");
126 }
127
128 const QString outIcns = QFileInfo(svgFileName).baseName() + QStringLiteral(".icns");
129
130 const QStringList utilArgs = QStringList() << "-c"
131 << "icns"
132 << "-o" << outIcns << outPath;
133
134 QProcess iconUtil;
135
136 iconUtil.start(iconutilExec, utilArgs, QIODevice::ReadOnly);
137 isOk = iconUtil.waitForFinished(-1);
138 EXIT_ON_ERROR(isOk, "Unable to launch iconutil: %s\n", qPrintable(iconUtil.errorString()));
139
140 EXIT_ON_ERROR(iconUtil.exitStatus() == QProcess::NormalExit, "iconutil crashed!\n");
141 EXIT_ON_ERROR(iconUtil.exitCode() == 0, "iconutil returned %d\n", iconUtil.exitCode());
142
143 return 0;
144}
QCommandLineOption addHelpOption()
void addPositionalArgument(const QString &name, const QString &description, const QString &syntax)
QStringList positionalArguments() const const
void process(const QCoreApplication &app)
void setApplicationDescription(const QString &description)
void showHelp(int exitCode)
bool mkpath(const QString &dirPath) const const
QString tempPath()
QString baseName() const const
QString errorString() const const
const_reference at(qsizetype i) const const
bool isEmpty() const const
qsizetype size() const const
T value(qsizetype i) const const
int exitCode() const const
QProcess::ExitStatus exitStatus() const const
void start(OpenMode mode)
bool waitForFinished(int msecs)
QString findExecutable(const QString &executableName, const QStringList &paths)
bool isEmpty() const const
void setAspectRatioMode(Qt::AspectRatioMode mode)
bool load(QXmlStreamReader *contents)
void render(QPainter *painter)
KeepAspectRatio
transparent
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:43:58 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.