mirror of
https://github.com/GerbilSoft/rom-properties.git
synced 2025-06-18 11:35:38 -04:00
[librptexture] ICO: Handle Win3.x 1bpp (monochrome) icons.
Tested by converting Win2.x BANG.ICO to Win3.x format. ICOPrivate::loadImage_Win1(): - Note that the mask is *before* the icon. ImageDecoder::fromLinearMono_WinIcon(): - Take separate pointers for the icon and mask data. Win3.x icons are typically stored upside-down, so this lets us handle that outside of the decoder function. This also means the image data size does not have to be 2x. Note that `img_siz == mask_siz` must be true.
This commit is contained in:
parent
da94256a37
commit
417825cd6f
@ -190,29 +190,33 @@ rp_image_ptr fromLinearGray2bpp(int width, int height,
|
||||
* Convert a linear monochrome image to rp_image.
|
||||
*
|
||||
* Windows icons are handled a bit different compared to "regular" monochrome images:
|
||||
* - Actual image height should be double the `height` value.
|
||||
* - Two images are stored: mask, then image.
|
||||
* - Two images are required: icon and mask
|
||||
* - Transparency is supported using the mask.
|
||||
* - 0 == black; 1 == white
|
||||
*
|
||||
* @param width [in] Image width
|
||||
* @param height [in] Image height
|
||||
* @param img_buf [in] Monochrome image buffer
|
||||
* @param img_siz [in] Size of image data [must be >= ((w*h)/8)*2]
|
||||
* @param img_siz [in] Size of image data [must be >= ((w*h)/8)]
|
||||
* @param mask_buf [in] Mask buffer
|
||||
* @param mask_siz [in] Size of mask buffer [must be == img_siz]
|
||||
* @param stride [in,opt] Stride, in bytes (if 0, assumes width*bytespp)
|
||||
* @return rp_image, or nullptr on error.
|
||||
*/
|
||||
ATTR_ACCESS_SIZE(read_only, 3, 4)
|
||||
rp_image_ptr fromLinearMono_WinIcon(int width, int height,
|
||||
const uint8_t *RESTRICT img_buf, size_t img_siz, int stride)
|
||||
const uint8_t *RESTRICT img_buf, size_t img_siz,
|
||||
const uint8_t *RESTRICT mask_buf, size_t mask_siz, int stride)
|
||||
{
|
||||
// Verify parameters.
|
||||
assert(img_buf != nullptr);
|
||||
assert(width > 0);
|
||||
assert(height > 0);
|
||||
assert(img_siz >= (static_cast<size_t>(width) * static_cast<size_t>(height) / 8) * 2);
|
||||
assert(img_siz >= (static_cast<size_t>(width) * static_cast<size_t>(height) / 8));
|
||||
assert(img_siz == mask_siz);
|
||||
if (!img_buf || width <= 0 || height <= 0 ||
|
||||
img_siz < (static_cast<size_t>(width) * static_cast<size_t>(height) / 8) * 2)
|
||||
img_siz < (static_cast<size_t>(width) * static_cast<size_t>(height) / 8) ||
|
||||
img_siz != mask_siz)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@ -247,12 +251,10 @@ rp_image_ptr fromLinearMono_WinIcon(int width, int height,
|
||||
|
||||
// Convert one line at a time. (monochrome -> CI8)
|
||||
uint8_t *px_dest = static_cast<uint8_t*>(img->bits());
|
||||
const uint8_t *mask_buf = img_buf;
|
||||
const uint8_t *icon_buf = img_buf + (static_cast<size_t>(height) * static_cast<size_t>(stride));
|
||||
for (unsigned int y = static_cast<unsigned int>(height); y > 0; y--) {
|
||||
for (int x = width; x > 0; x -= 8) {
|
||||
uint8_t pxMask = *mask_buf++;
|
||||
uint8_t pxIcon = *icon_buf++;
|
||||
uint8_t pxIcon = *img_buf++;
|
||||
|
||||
// For images where width is not a multiple of 8,
|
||||
// we'll discard the remaining bits in the last byte.
|
||||
@ -281,6 +283,7 @@ rp_image_ptr fromLinearMono_WinIcon(int width, int height,
|
||||
// Set the sBIT metadata.
|
||||
// NOTE: Setting the grayscale value, though we're
|
||||
// not saving grayscale PNGs at the moment.
|
||||
// TODO: Don't set alpha if the icon mask doesn't have any set bits?
|
||||
static const rp_image::sBIT_t sBIT = {1,1,1,1,1};
|
||||
img->set_sBIT(&sBIT);
|
||||
|
||||
|
@ -49,20 +49,23 @@ rp_image_ptr fromLinearGray2bpp(int width, int height,
|
||||
* Convert a linear monochrome image to rp_image.
|
||||
*
|
||||
* Windows icons are handled a bit different compared to "regular" monochrome images:
|
||||
* - Actual image height should be double the `height` value.
|
||||
* - Two images are stored: mask, then image.
|
||||
* - Two images are required: icon and mask
|
||||
* - Transparency is supported using the mask.
|
||||
* - 0 == black; 1 == white
|
||||
*
|
||||
* @param width [in] Image width
|
||||
* @param height [in] Image height
|
||||
* @param img_buf [in] Monochrome image buffer
|
||||
* @param img_siz [in] Size of image data [must be >= ((w*h)/8)*2]
|
||||
* @param img_siz [in] Size of image data [must be >= ((w*h)/8)]
|
||||
* @param mask_buf [in] Mask buffer
|
||||
* @param mask_siz [in] Size of mask buffer [must be == img_siz]
|
||||
* @param stride [in,opt] Stride, in bytes (if 0, assumes width*bytespp)
|
||||
* @return rp_image, or nullptr on error.
|
||||
*/
|
||||
ATTR_ACCESS_SIZE(read_only, 3, 4)
|
||||
ATTR_ACCESS_SIZE(read_only, 5, 6)
|
||||
rp_image_ptr fromLinearMono_WinIcon(int width, int height,
|
||||
const uint8_t *RESTRICT img_buf, size_t img_siz, int stride = 0);
|
||||
const uint8_t *RESTRICT img_buf, size_t img_siz,
|
||||
const uint8_t *RESTRICT mask_buf, size_t mask_siz, int stride = 0);
|
||||
|
||||
} }
|
||||
|
@ -504,7 +504,7 @@ int ICOPrivate::loadIconDirectory_Win3(void)
|
||||
rp_image_const_ptr ICOPrivate::loadImage_Win1(void)
|
||||
{
|
||||
// Icon data is located immediately after the header.
|
||||
// Each icon is actually two icons: a 1bpp icon, then a 1bpp mask.
|
||||
// Each icon is actually two icons: a 1bpp mask, then a 1bpp icon.
|
||||
|
||||
// NOTE: If the file has *both* DIB and DDB, then the DIB is first,
|
||||
// followed by the DDB, with its own icon header. Not handling this
|
||||
@ -546,7 +546,10 @@ rp_image_const_ptr ICOPrivate::loadImage_Win1(void)
|
||||
}
|
||||
|
||||
// Convert the icon.
|
||||
img = ImageDecoder::fromLinearMono_WinIcon(width, height, icon_data.data(), icon_size * 2, stride);
|
||||
const uint8_t *const p_mask_data = icon_data.data();
|
||||
const uint8_t *const p_icon_data = p_mask_data + icon_size;
|
||||
img = ImageDecoder::fromLinearMono_WinIcon(width, height,
|
||||
p_icon_data, icon_size, p_mask_data, icon_size, stride);
|
||||
return img;
|
||||
}
|
||||
|
||||
@ -718,9 +721,12 @@ rp_image_const_ptr ICOPrivate::loadImage_Win3(void)
|
||||
return {};
|
||||
|
||||
case 1:
|
||||
// Monochrome (TODO: Find a test icon)
|
||||
assert(!"Win3.x 1bpp icon format is not supported yet!");
|
||||
return {};
|
||||
// 1bpp (monochrome)
|
||||
// NOTE: ImageDecoder::fromLinearMono_WinIcon() handles the mask.
|
||||
img = ImageDecoder::fromLinearMono_WinIcon(width, half_height,
|
||||
icon_data, icon_size,
|
||||
mask_data, mask_size, stride);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// 16-color
|
||||
@ -760,7 +766,9 @@ rp_image_const_ptr ICOPrivate::loadImage_Win3(void)
|
||||
// Apply the icon mask.
|
||||
rp_image::sBIT_t sBIT;
|
||||
img->get_sBIT(&sBIT);
|
||||
if (bitcount < 8) {
|
||||
if (bitcount == 1) {
|
||||
// Monochrome icons are handled by ImageDecoder::fromLinearMono_WinIcon().
|
||||
} else if (bitcount < 8) {
|
||||
// Keep the icon as CI8 and add a transparency color.
|
||||
// TODO: Set sBIT.
|
||||
assert(img->format() == rp_image::Format::CI8);
|
||||
|
Loading…
Reference in New Issue
Block a user