@DanielSvoboda ICO conversion multiplataform code
This commit is contained in:
parent
e0a3ed8689
commit
f5fbf3a1f5
3 changed files with 90 additions and 70 deletions
|
@ -3128,7 +3128,21 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const QString& game_p
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string());
|
LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string());
|
||||||
}
|
}
|
||||||
#endif // __linux__
|
#elif defined(_WIN32)
|
||||||
|
// ICO is only for Windows
|
||||||
|
|
||||||
|
// Convert QImage to QPixmap
|
||||||
|
QPixmap pixmap = QPixmap::fromImage(icon_jpeg);
|
||||||
|
|
||||||
|
// Save the QPixmap as an .ico file
|
||||||
|
QList<QPixmap> pixmaps;
|
||||||
|
pixmaps.append(pixmap);
|
||||||
|
if (!savePixmapsToICO(pixmaps, QString::fromStdWString(Common::FS::ToWString(icon_path.u8string())))) {
|
||||||
|
LOG_ERROR(Frontend, "Could not write icon as ICO to file");
|
||||||
|
} else {
|
||||||
|
LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__linux__) || defined(__FreeBSD__)
|
||||||
QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No;
|
QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No;
|
||||||
|
@ -3177,10 +3191,6 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const QString& game_p
|
||||||
|
|
||||||
const std::filesystem::path shortcut_path = target_directory / (sanitized_title);
|
const std::filesystem::path shortcut_path = target_directory / (sanitized_title);
|
||||||
|
|
||||||
bool is_icon_ok = SaveIconToFile(icon_path, icon_jpeg);
|
|
||||||
if (!is_icon_ok) {
|
|
||||||
LOG_ERROR(Frontend, "Could not write icon as ICO to file");
|
|
||||||
}
|
|
||||||
const std::u8string keywords = u8"Switch;Nintendo;";
|
const std::u8string keywords = u8"Switch;Nintendo;";
|
||||||
const std::u8string categories = u8"Game;Emulator;Qt;";
|
const std::u8string categories = u8"Game;Emulator;Qt;";
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#if defined(WIN32)
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
#include "yuzu/util/util.h"
|
#include "yuzu/util/util.h"
|
||||||
|
|
||||||
QFont GetMonospaceFont() {
|
QFont GetMonospaceFont() {
|
||||||
|
@ -44,79 +49,84 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
#pragma pack(push, 2)
|
template <typename T>
|
||||||
struct ICONDIR {
|
void write(QFile& f, const T t) {
|
||||||
WORD idReserved;
|
f.write((const char*)&t, sizeof(t));
|
||||||
WORD idType;
|
}
|
||||||
WORD idCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ICONDIRENTRY {
|
bool savePixmapsToICO(const QList<QPixmap>& pixmaps, const QString& path) {
|
||||||
BYTE bWidth;
|
static_assert(sizeof(short) == 2, "short int is not 2 bytes");
|
||||||
BYTE bHeight;
|
static_assert(sizeof(int) == 4, "int is not 4 bytes");
|
||||||
BYTE bColorCount;
|
|
||||||
BYTE bReserved;
|
|
||||||
WORD wPlanes;
|
|
||||||
WORD wBitCount;
|
|
||||||
DWORD dwBytesInRes;
|
|
||||||
DWORD dwImageOffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
QFile f(path);
|
||||||
|
if (!f.open(QFile::OpenModeFlag::WriteOnly))
|
||||||
bool SaveIconToFile(const std::filesystem::path IconPath, const QImage image) {
|
|
||||||
|
|
||||||
QImage sourceImage = image.convertToFormat(QImage::Format_RGB32);
|
|
||||||
|
|
||||||
const int bytesPerPixel = 4;
|
|
||||||
const int imageSize = sourceImage.width() * sourceImage.height() * bytesPerPixel;
|
|
||||||
|
|
||||||
BITMAPINFOHEADER bmih = {};
|
|
||||||
bmih.biSize = sizeof(BITMAPINFOHEADER);
|
|
||||||
bmih.biWidth = sourceImage.width();
|
|
||||||
bmih.biHeight = sourceImage.height() * 2;
|
|
||||||
bmih.biPlanes = 1;
|
|
||||||
bmih.biBitCount = 32;
|
|
||||||
bmih.biCompression = BI_RGB;
|
|
||||||
|
|
||||||
// Create an ICO header
|
|
||||||
ICONDIR iconDir;
|
|
||||||
iconDir.idReserved = 0;
|
|
||||||
iconDir.idType = 1;
|
|
||||||
iconDir.idCount = 1;
|
|
||||||
|
|
||||||
// Create an ICONDIRENTRY
|
|
||||||
ICONDIRENTRY iconEntry;
|
|
||||||
iconEntry.bWidth = sourceImage.width();
|
|
||||||
iconEntry.bHeight = sourceImage.height() * 2;
|
|
||||||
iconEntry.bColorCount = 0;
|
|
||||||
iconEntry.bReserved = 0;
|
|
||||||
iconEntry.wPlanes = 1;
|
|
||||||
iconEntry.wBitCount = 32;
|
|
||||||
iconEntry.dwBytesInRes = sizeof(BITMAPINFOHEADER) + imageSize;
|
|
||||||
iconEntry.dwImageOffset = sizeof(ICONDIR) + sizeof(ICONDIRENTRY);
|
|
||||||
|
|
||||||
// Save the icon data to a file
|
|
||||||
std::ofstream iconFile(IconPath, std::ios::binary | std::ios::trunc);
|
|
||||||
if (iconFile.fail())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
iconFile.write((char*)&iconDir, sizeof(ICONDIR));
|
// Header
|
||||||
iconFile.write((char*)&iconEntry, sizeof(ICONDIRENTRY));
|
write<short>(f, 0);
|
||||||
iconFile.write((char*)&bmih, sizeof(BITMAPINFOHEADER));
|
write<short>(f, 1);
|
||||||
|
write<short>(f, pixmaps.count());
|
||||||
|
|
||||||
for (int y = 0; y < image.height(); y++) {
|
QList<int> images_size;
|
||||||
auto line = (char*)sourceImage.scanLine(sourceImage.height() - 1 - y);
|
for (int ii = 0; ii < pixmaps.count(); ++ii) {
|
||||||
iconFile.write(line, sourceImage.width() * 4);
|
QTemporaryFile temp;
|
||||||
|
temp.setAutoRemove(true);
|
||||||
|
if (!temp.open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto& pixmap = pixmaps[ii];
|
||||||
|
pixmap.save(&temp, "PNG");
|
||||||
|
|
||||||
|
|
||||||
|
temp.close();
|
||||||
|
|
||||||
|
images_size.push_back(QFileInfo(temp).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
iconFile.close();
|
// Images directory
|
||||||
|
constexpr unsigned int entry_size = sizeof(char) + sizeof(char) + sizeof(char) + sizeof(char) +
|
||||||
|
sizeof(short) + sizeof(short) + sizeof(unsigned int) +
|
||||||
|
sizeof(unsigned int);
|
||||||
|
static_assert(entry_size == 16, "wrong entry size");
|
||||||
|
|
||||||
|
unsigned int offset = 3 * sizeof(short) + pixmaps.count() * entry_size;
|
||||||
|
for (int ii = 0; ii < pixmaps.count(); ++ii) {
|
||||||
|
const auto& pixmap = pixmaps[ii];
|
||||||
|
if (pixmap.width() > 256 || pixmap.height() > 256)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
write<char>(f, pixmap.width() == 256 ? 0 : pixmap.width());
|
||||||
|
write<char>(f, pixmap.height() == 256 ? 0 : pixmap.height());
|
||||||
|
write<char>(f, 0); // palette size
|
||||||
|
write<char>(f, 0); // reserved
|
||||||
|
write<short>(f, 1); // color planes
|
||||||
|
write<short>(f, pixmap.depth()); // bits-per-pixel
|
||||||
|
write<unsigned int>(f, images_size[ii]); // size of image in bytes
|
||||||
|
write<unsigned int>(f, offset); // offset
|
||||||
|
offset += images_size[ii];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int ii = 0; ii < pixmaps.count(); ++ii) {
|
||||||
|
const auto& pixmap = pixmaps[ii];
|
||||||
|
if (pixmap.width() > 256 || pixmap.height() > 256)
|
||||||
|
continue;
|
||||||
|
pixmap.save(&f, "PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the file before renaming it
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
// Remove the .png extension Add the .ico extension and Rename the file
|
||||||
|
QString qPath = path;
|
||||||
|
qPath.chop(3);
|
||||||
|
qPath = qPath % QString::fromStdString("ico");
|
||||||
|
QFile::rename(path, qPath);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
bool SaveAsIco(QImage image) {
|
bool SaveAsIco(const QList<QPixmap>& pixmaps, const QString& path) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -31,4 +31,4 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color);
|
||||||
* @return QPixmap circle pixmap
|
* @return QPixmap circle pixmap
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool SaveIconToFile(const std::filesystem::path IconPath, QImage image);
|
bool savePixmapsToICO(const QList<QPixmap>& pixmaps, const QString& path);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue