Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 57 additions & 18 deletions crnlib/crn_image_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,27 +174,66 @@ bool write_to_file(const char* pFilename, const image_u8& img, uint write_flags,
if (grayscale_comp_index > 3)
grayscale_comp_index = 3;

temp.resize(img.get_total_pixels());
if ((img.get_comp_flags() & pixel_format_helpers::cCompFlagGrayscale) &&
img.is_component_valid(3) &&
!(write_flags & cWriteFlagIgnoreAlpha)) {
// Preserve grayscale images with alpha.
//
// PNG supports grayscale+alpha directly, while BMP/TGA writers
// expect color channels for alpha output. Expand to RGBA for
// those formats.
const bool expand_to_rgba = (ext == "bmp") || (ext == "tga");
const uint num_channels = expand_to_rgba ? 4 : 2;

temp.resize(img.get_total_pixels() * num_channels);

for (uint y = 0; y < img.get_height(); y++) {
const color_quad_u8* pSrc = img.get_scanline(y);
const color_quad_u8* pSrc_end = pSrc + img.get_width();
uint8* pDst = &temp[y * img.get_width() * num_channels];

while (pSrc != pSrc_end) {
const color_quad_u8 c(*pSrc++);

if (expand_to_rgba) {
pDst[0] = c[1];
pDst[1] = c[1];
pDst[2] = c[1];
pDst[3] = c.a;
pDst += 4;
} else {
pDst[0] = c[1];
pDst[1] = c.a;
pDst += 2;
}
}
}

for (uint y = 0; y < img.get_height(); y++) {
const color_quad_u8* pSrc = img.get_scanline(y);
const color_quad_u8* pSrc_end = pSrc + img.get_width();
uint8* pDst = &temp[y * img.get_width()];

if (img.get_comp_flags() & pixel_format_helpers::cCompFlagGrayscale) {
while (pSrc != pSrc_end)
*pDst++ = (*pSrc++)[1];
} else if (grayscale_comp_index < 0) {
while (pSrc != pSrc_end)
*pDst++ = static_cast<uint8>((*pSrc++).get_luma());
} else {
while (pSrc != pSrc_end)
*pDst++ = (*pSrc++)[grayscale_comp_index];
pSrc_img = &temp[0];
num_src_chans = num_channels;
} else {
temp.resize(img.get_total_pixels());

for (uint y = 0; y < img.get_height(); y++) {
const color_quad_u8* pSrc = img.get_scanline(y);
const color_quad_u8* pSrc_end = pSrc + img.get_width();
uint8* pDst = &temp[y * img.get_width()];

if (img.get_comp_flags() & pixel_format_helpers::cCompFlagGrayscale) {
while (pSrc != pSrc_end)
*pDst++ = (*pSrc++)[1];
} else if (grayscale_comp_index < 0) {
while (pSrc != pSrc_end)
*pDst++ = static_cast<uint8>((*pSrc++).get_luma());
} else {
while (pSrc != pSrc_end)
*pDst++ = (*pSrc++)[grayscale_comp_index];
}
}
}

pSrc_img = &temp[0];
num_src_chans = 1;
pSrc_img = &temp[0];
num_src_chans = 1;
}
} else if ((!img.is_component_valid(3)) || (write_flags & cWriteFlagIgnoreAlpha)) {
temp.resize(img.get_total_pixels() * 3);

Expand Down
8 changes: 6 additions & 2 deletions crnlib/crn_jpgd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2330,8 +2330,12 @@ void jpeg_decoder::init_frame() {
int i;

if (m_comps_in_frame == 1) {
if ((m_comp_h_samp[0] != 1) || (m_comp_v_samp[0] != 1))
stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
if ((m_comp_h_samp[0] != 1) || (m_comp_v_samp[0] != 1)) {
// Some grayscale JPEGs contain non-1×1 sampling factors.
// There is no chroma plane to subsample, so normalize to the expected layout.
m_comp_h_samp[0] = 1;
m_comp_v_samp[0] = 1;
}

m_scan_type = JPGD_GRAYSCALE;
m_max_blocks_per_mcu = 1;
Expand Down
4 changes: 4 additions & 0 deletions crnlib/crn_mipmapped_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2653,6 +2653,10 @@ bool mipmapped_texture::read_regular_image(data_stream_serializer& serializer) {
return false;
}

// Ignore alpha channel when it exists but is fully opaque.
const bool has_alpha = image_utils::has_alpha(*pImg);
pImg->set_component_valid(3, has_alpha);

mip_level* pLevel = crnlib_new<mip_level>();
pLevel->assign(pImg);

Expand Down
565 changes: 476 additions & 89 deletions test/checksums.tsv

Large diffs are not rendered by default.

Loading
Loading