Skip to content

Commit

Permalink
Fix lossless formats in PortableCompressedTexture2D (add statics and …
Browse files Browse the repository at this point in the history
…file format detection)
  • Loading branch information
nklbdev committed Jun 4, 2023
1 parent e5cab4c commit efdfaf8
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 12 deletions.
73 changes: 63 additions & 10 deletions core/io/image.cpp
Expand Up @@ -3929,22 +3929,75 @@ void Image::renormalize_rgbe9995(uint32_t *p_rgb) {
// Never used
}

Image::FileFormat Image::detect_file_format(const uint8_t *p_data, int p_len) {
size_t len = p_len < 0 ? 0 : unsigned(p_len);

static const uint8_t png_file_header[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; // \211PNG\r\n\032\n
static const size_t png_file_header_size = sizeof(png_file_header);
if (len > png_file_header_size && memcmp(p_data, png_file_header, png_file_header_size) == 0)
return FILE_FORMAT_PNG;

static const size_t riff_four_cc_size = 4;
static const uint8_t riff_file_header[] = { 0x52, 0x49, 0x46, 0x46 }; // RIFF
static const uint8_t webp_content_header[] = { 0x57, 0x45, 0x42, 0x50 }; // WEBP
if (len > riff_four_cc_size * 3 && // RIFF SIZE WEBP
memcmp(p_data, riff_file_header, riff_four_cc_size) == 0 && // RIFF header.
memcmp(p_data + riff_four_cc_size * 2, webp_content_header, riff_four_cc_size) == 0) { // WEBP chunk header.
return FILE_FORMAT_RIFF_WEBP;
}

static const uint8_t jpeg_soi_marker[] = { 0xFF, 0xD8 };
static const uint8_t jpeg_application0_marker[] = { 0xFF, 0xE0 };
static const uint8_t jpeg_jfif_data_identifier[] = { 0x4A, 0x46, 0x49, 0x46, 0x00 }; // JFIF\0
static const uint8_t jpeg_application1_marker[] = { 0xFF, 0xE1 };
static const uint8_t jpeg_exif_data_identifier[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; // Exif\0\0

static const size_t jpeg_marker_size = 2;
static const size_t jpeg_data_length_size = sizeof(uint16_t);
static const size_t jpeg_data_identifier_offset = jpeg_marker_size * 2 + jpeg_data_length_size;
static const size_t jpeg_jfif_data_identifier_size = sizeof(jpeg_jfif_data_identifier);
static const size_t jpeg_exif_data_identifier_size = sizeof(jpeg_exif_data_identifier);

if (len > 12 && memcmp(p_data, jpeg_soi_marker, jpeg_marker_size) == 0) {
if (memcmp(p_data + jpeg_marker_size, jpeg_application0_marker, jpeg_marker_size) == 0 &&
memcmp(p_data + jpeg_data_identifier_offset,
jpeg_jfif_data_identifier, jpeg_jfif_data_identifier_size) == 0) {
return FILE_FORMAT_JPEG_JFIF;
} else if (memcmp(p_data + jpeg_marker_size, jpeg_application1_marker, jpeg_marker_size) == 0 &&
memcmp(p_data + jpeg_data_identifier_offset,
jpeg_exif_data_identifier, jpeg_exif_data_identifier_size) == 0) {
return FILE_FORMAT_JPEG_EXIF;
}
}

return FILE_FORMAT_UNKNOWN;
}

Image::Image(const uint8_t *p_mem_png_jpg, int p_len) {
width = 0;
height = 0;
mipmaps = false;
format = FORMAT_L8;

if (_png_mem_loader_func) {
copy_internals_from(_png_mem_loader_func(p_mem_png_jpg, p_len));
}

if (is_empty() && _jpg_mem_loader_func) {
copy_internals_from(_jpg_mem_loader_func(p_mem_png_jpg, p_len));
}

if (is_empty() && _webp_mem_loader_func) {
copy_internals_from(_webp_mem_loader_func(p_mem_png_jpg, p_len));
switch (detect_file_format(p_mem_png_jpg, p_len)) {
case FILE_FORMAT_PNG:
if (_png_mem_loader_func) {
copy_internals_from(_png_mem_loader_func(p_mem_png_jpg, p_len));
}
break;
case FILE_FORMAT_JPEG_JFIF:
case FILE_FORMAT_JPEG_EXIF:
if (_jpg_mem_loader_func) {
copy_internals_from(_jpg_mem_loader_func(p_mem_png_jpg, p_len));
}
break;
case FILE_FORMAT_RIFF_WEBP:
if (_webp_mem_loader_func) {
copy_internals_from(_webp_mem_loader_func(p_mem_png_jpg, p_len));
}
break;
default: // FILE_FORMAT_UNKNOWN
break;
}
}

Expand Down
10 changes: 10 additions & 0 deletions core/io/image.h
Expand Up @@ -143,6 +143,14 @@ class Image : public Resource {
ASTC_FORMAT_8x8,
};

enum FileFormat {
FILE_FORMAT_UNKNOWN,
FILE_FORMAT_PNG,
FILE_FORMAT_JPEG_JFIF,
FILE_FORMAT_JPEG_EXIF,
FILE_FORMAT_RIFF_WEBP,
};

static ImageMemLoadFunc _png_mem_loader_func;
static ImageMemLoadFunc _jpg_mem_loader_func;
static ImageMemLoadFunc _webp_mem_loader_func;
Expand Down Expand Up @@ -217,6 +225,8 @@ class Image : public Resource {
static void renormalize_half(uint16_t *p_rgb);
static void renormalize_rgbe9995(uint32_t *p_rgb);

static FileFormat detect_file_format(const uint8_t *p_mem_png_jpg, int p_len);

public:
int get_width() const; ///< Get image width
int get_height() const; ///< Get image height
Expand Down
4 changes: 2 additions & 2 deletions scene/resources/texture.cpp
Expand Up @@ -373,8 +373,8 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
data_size -= 4;

// Skip possible Godot png tag "PNG " before pure PNG data.
const uint8_t godot_png_prefix[] = { 0x50, 0x4E, 0x47, 0x20 };
const size_t godot_png_prefix_size = sizeof(godot_png_prefix);
static const uint8_t godot_png_prefix[] = { 0x50, 0x4E, 0x47, 0x20 };
static const size_t godot_png_prefix_size = sizeof(godot_png_prefix);
if (memcmp(data, godot_png_prefix, godot_png_prefix_size) == 0) {
data += godot_png_prefix_size;
data_size -= godot_png_prefix_size;
Expand Down

0 comments on commit efdfaf8

Please sign in to comment.