[librptexture] ICO: Rework the private loadImage_*() functions (except Win1) to take a bitmap image index.

This will allow us to show a list of all the bitmaps in a given icon.

NOTE: loadInternalImage() ensures that d->img_icon is set to the "best"
icon; that is, icon index "-1". The loadImage_*() functions won't use
d->img_icon themselves, so if the "best" icon is manually selected
using positive indexes, it won't be cached.
This commit is contained in:
David Korth 2025-06-12 21:31:09 -04:00
parent 704a5eead5
commit 0c512deed6

View File

@ -198,19 +198,22 @@ private:
/** /**
* Load the image. (Windows 3.x icon format) * Load the image. (Windows 3.x icon format)
* @param idx Icon's bitmap index (-1 for "best")
* @return Image, or nullptr on error. * @return Image, or nullptr on error.
*/ */
rp_image_const_ptr loadImage_Win3(void); rp_image_const_ptr loadImage_Win3(int idx = -1);
/** /**
* Load the image. (Windows Vista PNG format) * Load the image. (Windows Vista PNG format)
* @param idx Icon's bitmap index (-1 for "best")
* @return Image, or nullptr on error. * @return Image, or nullptr on error.
*/ */
rp_image_const_ptr loadImage_WinVista_PNG(void); rp_image_const_ptr loadImage_WinVista_PNG(int idx = -1);
public: public:
/** /**
* Load the image. * Load the image.
* This loads the "best" bitmap from the icon.
* @return Image, or nullptr on error. * @return Image, or nullptr on error.
*/ */
rp_image_const_ptr loadImage(void); rp_image_const_ptr loadImage(void);
@ -555,9 +558,10 @@ rp_image_const_ptr ICOPrivate::loadImage_Win1(void)
/** /**
* Load the image. (Windows 3.x icon format) * Load the image. (Windows 3.x icon format)
* @param idx Icon's bitmap index (-1 for "best")
* @return Image, or nullptr on error. * @return Image, or nullptr on error.
*/ */
rp_image_const_ptr ICOPrivate::loadImage_Win3(void) rp_image_const_ptr ICOPrivate::loadImage_Win3(int idx)
{ {
// Icon image header was already loaded by loadIconDirectory_Win3(). // Icon image header was already loaded by loadIconDirectory_Win3().
// TODO: Verify dwBytesInRes. // TODO: Verify dwBytesInRes.
@ -653,9 +657,19 @@ rp_image_const_ptr ICOPrivate::loadImage_Win3(void)
const uint16_t rt = imageResType(); const uint16_t rt = imageResType();
if (rt != 0) { if (rt != 0) {
// Open the resource. // Load the icon from a resource.
const auto &res = *(dir.res); const auto &res = *(dir.res);
f_icon = res.resReader->open(rt, le16_to_cpu(res.pBestIcon->nID), res.lang); const GRPICONDIRENTRY *pBestIcon;
if (idx < 0) {
pBestIcon = res.pBestIcon;
} else if (idx < static_cast<int>(res.iconDirectory.size())) {
pBestIcon = &res.iconDirectory[idx];
} else {
// Invalid index.
return {};
}
f_icon = res.resReader->open(rt, le16_to_cpu(pBestIcon->nID), res.lang);
if (!f_icon) { if (!f_icon) {
// Unable to open the resource. // Unable to open the resource.
return {}; return {};
@ -663,7 +677,17 @@ rp_image_const_ptr ICOPrivate::loadImage_Win3(void)
addr = header_size; addr = header_size;
} else { } else {
// Get the icon's starting address within the .ico file. // Get the icon's starting address within the .ico file.
const ICONDIRENTRY *const pBestIcon = dir.ico->pBestIcon; const auto &ico = *(dir.ico);
const ICONDIRENTRY *pBestIcon;
if (idx < 0) {
pBestIcon = ico.pBestIcon;
} else if (idx < static_cast<int>(ico.iconDirectory.size())) {
pBestIcon = &ico.iconDirectory[idx];
} else {
// Invalid index.
return {};
}
f_icon = this->file; f_icon = this->file;
addr = le32_to_cpu(pBestIcon->dwImageOffset) + header_size; addr = le32_to_cpu(pBestIcon->dwImageOffset) + header_size;
} }
@ -880,9 +904,10 @@ rp_image_const_ptr ICOPrivate::loadImage_Win3(void)
/** /**
* Load the image. (Windows Vista PNG format) * Load the image. (Windows Vista PNG format)
* @param idx Icon's bitmap index (-1 for "best")
* @return Image, or nullptr on error. * @return Image, or nullptr on error.
*/ */
rp_image_const_ptr ICOPrivate::loadImage_WinVista_PNG(void) rp_image_const_ptr ICOPrivate::loadImage_WinVista_PNG(int idx)
{ {
// Use RpPng to load a PNG image. // Use RpPng to load a PNG image.
IRpFilePtr f_png; IRpFilePtr f_png;
@ -891,12 +916,33 @@ rp_image_const_ptr ICOPrivate::loadImage_WinVista_PNG(void)
if (rt != 0) { if (rt != 0) {
// Load the PNG from a resource. // Load the PNG from a resource.
const auto &res = *(dir.res); const auto &res = *(dir.res);
f_png = res.resReader->open(rt, le16_to_cpu(res.pBestIcon->nID), res.lang); const GRPICONDIRENTRY *pBestIcon;
if (idx < 0) {
pBestIcon = res.pBestIcon;
} else if (idx < static_cast<int>(res.iconDirectory.size())) {
pBestIcon = &res.iconDirectory[idx];
} else {
// Invalid index.
return {};
}
f_png = res.resReader->open(rt, le16_to_cpu(pBestIcon->nID), res.lang);
} else { } else {
// Get the PNG's starting address within the .ico file.
const auto &ico = *(dir.ico);
const ICONDIRENTRY *pBestIcon;
if (idx < 0) {
pBestIcon = ico.pBestIcon;
} else if (idx < static_cast<int>(ico.iconDirectory.size())) {
pBestIcon = &ico.iconDirectory[idx];
} else {
// Invalid index.
return {};
}
// NOTE: PartitionFile only supports IDiscReader, so we'll need to // NOTE: PartitionFile only supports IDiscReader, so we'll need to
// create a dummy DiscReader object. // create a dummy DiscReader object.
IDiscReaderPtr discReader = std::make_shared<DiscReader>(file, 0, file->size()); IDiscReaderPtr discReader = std::make_shared<DiscReader>(file, 0, file->size());
const ICONDIRENTRY *const pBestIcon = dir.ico->pBestIcon;
f_png = std::make_shared<PartitionFile>(discReader, pBestIcon->dwImageOffset, pBestIcon->dwBytesInRes); f_png = std::make_shared<PartitionFile>(discReader, pBestIcon->dwImageOffset, pBestIcon->dwBytesInRes);
} }
@ -906,6 +952,7 @@ rp_image_const_ptr ICOPrivate::loadImage_WinVista_PNG(void)
/** /**
* Load the image. * Load the image.
* This loads the "best" bitmap from the icon.
* @return Image, or nullptr on error. * @return Image, or nullptr on error.
*/ */
rp_image_const_ptr ICOPrivate::loadImage(void) rp_image_const_ptr ICOPrivate::loadImage(void)