Merge pull request #821 from Spartan322/add/gif-importer

Add GIF import
This commit is contained in:
George L. Albany
2025-05-23 10:14:39 +00:00
committed by GitHub
58 changed files with 6768 additions and 0 deletions

View File

@@ -201,6 +201,19 @@ TEST_CASE("[Image] Saving and loading") {
image_tga->load_tga_from_buffer(data_tga) == OK,
"The TGA image should load successfully.");
#endif // MODULE_TGA_ENABLED
#ifdef MODULE_GIF_ENABLED
// Load GIF
Ref<Image> image_gif = memnew(Image());
Ref<FileAccess> f_gif = FileAccess::open(TestUtils::get_data_path("images/icon.gif"), FileAccess::READ, &err);
REQUIRE(f_gif.is_valid());
PackedByteArray data_gif;
data_gif.resize(f_gif->get_length() + 1);
f_gif->get_buffer(data_gif.ptrw(), f_gif->get_length());
CHECK_MESSAGE(
image_gif->load_gif_from_buffer(data_gif) == OK,
"The GIF image should load successfully.");
#endif // MODULE_GIF_ENABLED
}
TEST_CASE("[Image] Basic getters") {

View File

@@ -0,0 +1,115 @@
/**************************************************************************/
/* test_image_frames.h */
/**************************************************************************/
/* This file is part of: */
/* REDOT ENGINE */
/* https://redotengine.org */
/**************************************************************************/
/* Copyright (c) 2024-present Redot Engine contributors */
/* (see REDOT_AUTHORS.md) */
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/io/image.h"
#include "core/io/image_frames.h"
#include "core/os/os.h"
#include "tests/test_utils.h"
#include "modules/modules_enabled.gen.h"
#include "thirdparty/doctest/doctest.h"
namespace TestImageFrames {
TEST_CASE("[ImageFrames] Instantiation") {
Vector<Ref<Image>> images = { memnew(Image(8, 4, false, Image::FORMAT_RGBA8)), memnew(Image(16, 8, false, Image::FORMAT_RGBA8)) };
Ref<ImageFrames> image_frames = memnew(ImageFrames({ images }));
CHECK_MESSAGE(
!image_frames->is_empty(),
"Image frames created with images should not be empty at first.");
for (int index = 0; index < image_frames->get_frame_count(); index++) {
PackedByteArray image_data = image_frames->get_frame_image(index)->get_data();
for (int i = 0; i < image_data.size(); i++) {
CHECK_MESSAGE(
image_data[i] == 0,
"An image of image frames created without data specified should have its data zeroed out.");
}
}
Ref<ImageFrames> image_frames_copy = memnew(ImageFrames());
CHECK_MESSAGE(
image_frames_copy->is_empty(),
"Image frames created without any specified images should be empty at first.");
image_frames_copy->copy_internals_from(image_frames);
CHECK_MESSAGE(
image_frames->get_frame_count() == image_frames_copy->get_frame_count(),
"Duplicated image frames should have the same frame count.");
for (int index = 0; index < image_frames->get_frame_count(); index++) {
CHECK_MESSAGE(
image_frames->get_frame_image(index)->get_data() == image_frames_copy->get_frame_image(index)->get_data(),
"Duplicated image frames should have the same image data.");
PackedByteArray image_data = image_frames->get_frame_image(index)->get_data();
Ref<Image> image_from_data = memnew(Image(images[index]->get_width(), images[index]->get_height(), images[index]->has_mipmaps(), images[index]->get_format(), image_data));
CHECK_MESSAGE(
image_frames->get_frame_image(index)->get_data() == image_from_data->get_data(),
"An image created from data of an image frame should have the same data of the original image.");
}
}
TEST_CASE("[ImageFrames] Loading") {
[[maybe_unused]] Error err = OK;
#ifdef MODULE_GIF_ENABLED
// Load GIF
Ref<ImageFrames> image_frames_gif = memnew(ImageFrames());
Ref<FileAccess> f_gif = FileAccess::open(TestUtils::get_data_path("image_frames/icon.gif"), FileAccess::READ, &err);
REQUIRE(f_gif.is_valid());
PackedByteArray data_gif;
data_gif.resize(f_gif->get_length() + 1);
f_gif->get_buffer(data_gif.ptrw(), f_gif->get_length());
CHECK_MESSAGE(
image_frames_gif->load_gif_from_buffer(data_gif) == OK,
"The GIF image frame should load successfully.");
#endif
}
TEST_CASE("[ImageFrames] Basic getters") {
Vector<Ref<Image>> images = { memnew(Image(8, 4, false, Image::FORMAT_RGBA8)), memnew(Image(16, 8, false, Image::FORMAT_L8)) };
Vector<float> delays = { 0.1, 0.2 };
Ref<ImageFrames> image_frames = memnew(ImageFrames(images, delays));
CHECK(image_frames->get_frame_count() == images.size());
CHECK(image_frames->get_loop_count() == 0);
for (int index = 0; index < image_frames->get_frame_count(); index++) {
CHECK(image_frames->get_frame_image(index) == images[index]);
CHECK(image_frames->get_frame_delay(index) == delays[index]);
}
}
} //namespace TestImageFrames

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
tests/data/images/icon.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@@ -32,6 +32,7 @@
#pragma once
#include "core/io/image_frames.h"
#include "scene/resources/sprite_frames.h"
#include "tests/test_macros.h"
@@ -244,4 +245,61 @@ TEST_CASE("[SpriteFrames] Frame addition, removal, and retrieval") {
frames.get_frame_count(test_animation_name) == 0,
"Clears frames.");
}
TEST_CASE("[SpriteFrames] ImageFrames Animation getter and setter") {
Ref<Texture2D> dummy_frame1;
dummy_frame1.instantiate();
SpriteFrames frames;
frames.add_animation(test_animation_name);
frames.add_frame(test_animation_name, dummy_frame1, 1.0, 0);
frames.add_frame(test_animation_name, dummy_frame1, 2.0, 1);
frames.add_frame(test_animation_name, dummy_frame1, 3.0, 2);
Ref<ImageFrames> image_frames = frames.make_image_frames(test_animation_name);
CHECK_MESSAGE(
image_frames->get_frame_count() == 3,
"ImageFrames frame count is set");
CHECK_MESSAGE(
image_frames->get_loop_count() == 0,
"ImageFrames loop count is set");
for (int i = 0; i < image_frames->get_frame_count(); i++) {
CHECK_MESSAGE(
image_frames->get_frame_image(i) == dummy_frame1,
"ImageFrames image is set");
CHECK_MESSAGE(
image_frames->get_frame_delay(i) == float(i + 1),
"ImageFrames delay is set");
}
Ref<SpriteFrames> new_frames;
new_frames.instantiate();
// These error handling cases should not crash.
ERR_PRINT_OFF;
new_frames->set_from_image_frames(image_frames, test_animation_name);
ERR_PRINT_ON;
CHECK_MESSAGE(
new_frames->has_animation(test_animation_name),
"SpriteFrames Animation is set");
CHECK_MESSAGE(
new_frames->get_frame_count(test_animation_name) == 3,
"SpriteFrames frame count is set");
CHECK_MESSAGE(
new_frames->get_animation_loop(test_animation_name),
"SpriteFrames loop is set");
for (int i = 0; i < image_frames->get_frame_count(); i++) {
CHECK_MESSAGE(
new_frames->get_frame_duration(test_animation_name, i) == float(i + 1),
"SpriteFrames delay is set");
}
}
} // namespace TestSpriteFrames

View File

@@ -50,6 +50,7 @@
#include "tests/core/io/test_file_access.h"
#include "tests/core/io/test_http_client.h"
#include "tests/core/io/test_image.h"
#include "tests/core/io/test_image_frames.h"
#include "tests/core/io/test_ip.h"
#include "tests/core/io/test_json.h"
#include "tests/core/io/test_json_native.h"