@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 {
|
||||
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__)
|
||||
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);
|
||||
|
||||
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 categories = u8"Game;Emulator;Qt;";
|
||||
#else
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <QPainter>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QTemporaryFile>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include "yuzu/util/util.h"
|
||||
|
||||
QFont GetMonospaceFont() {
|
||||
|
@ -44,79 +49,84 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) {
|
|||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
#pragma pack(push, 2)
|
||||
struct ICONDIR {
|
||||
WORD idReserved;
|
||||
WORD idType;
|
||||
WORD idCount;
|
||||
};
|
||||
template <typename T>
|
||||
void write(QFile& f, const T t) {
|
||||
f.write((const char*)&t, sizeof(t));
|
||||
}
|
||||
|
||||
struct ICONDIRENTRY {
|
||||
BYTE bWidth;
|
||||
BYTE bHeight;
|
||||
BYTE bColorCount;
|
||||
BYTE bReserved;
|
||||
WORD wPlanes;
|
||||
WORD wBitCount;
|
||||
DWORD dwBytesInRes;
|
||||
DWORD dwImageOffset;
|
||||
};
|
||||
bool savePixmapsToICO(const QList<QPixmap>& pixmaps, const QString& path) {
|
||||
static_assert(sizeof(short) == 2, "short int is not 2 bytes");
|
||||
static_assert(sizeof(int) == 4, "int is not 4 bytes");
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
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())
|
||||
QFile f(path);
|
||||
if (!f.open(QFile::OpenModeFlag::WriteOnly))
|
||||
return false;
|
||||
|
||||
iconFile.write((char*)&iconDir, sizeof(ICONDIR));
|
||||
iconFile.write((char*)&iconEntry, sizeof(ICONDIRENTRY));
|
||||
iconFile.write((char*)&bmih, sizeof(BITMAPINFOHEADER));
|
||||
// Header
|
||||
write<short>(f, 0);
|
||||
write<short>(f, 1);
|
||||
write<short>(f, pixmaps.count());
|
||||
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
auto line = (char*)sourceImage.scanLine(sourceImage.height() - 1 - y);
|
||||
iconFile.write(line, sourceImage.width() * 4);
|
||||
QList<int> images_size;
|
||||
for (int ii = 0; ii < pixmaps.count(); ++ii) {
|
||||
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;
|
||||
}
|
||||
#else
|
||||
|
||||
bool SaveAsIco(QImage image) {
|
||||
bool SaveAsIco(const QList<QPixmap>& pixmaps, const QString& path) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
|
@ -31,4 +31,4 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color);
|
|||
* @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
Reference in a new issue