Skip to content

Commit 9febc8a

Browse files
committed
Add support for GIF
1 parent 3599a86 commit 9febc8a

21 files changed

+49
-2
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ yoke = { workspace = true }
6767
float-cmp = { workspace = true }
6868
zune-png = "0.4.10"
6969
zune-jpeg = "0.4.13"
70+
gif = "0.13.1"
7071

7172
[dev-dependencies]
7273
difference = { workspace = true }

assets/images/rgb8.gif

4.91 KB
Loading

assets/images/rgba8.gif

5.34 KB
Loading
774 Bytes
Loading

assets/refs/image_rgb8_gif_mupdf.png

717 Bytes
Loading

assets/refs/image_rgb8_gif_pdfbox.png

717 Bytes
Loading

assets/refs/image_rgb8_gif_pdfium.png

696 Bytes
Loading

assets/refs/image_rgb8_gif_pdfjs.png

709 Bytes
Loading
795 Bytes
Loading

assets/refs/image_rgb8_gif_quartz.png

777 Bytes
Loading
811 Bytes
Loading

assets/refs/image_rgba8_gif_mupdf.png

754 Bytes
Loading
754 Bytes
Loading
733 Bytes
Loading

assets/refs/image_rgba8_gif_pdfjs.png

746 Bytes
Loading
982 Bytes
Loading
814 Bytes
Loading

src/object/image.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::error::KrillaResult;
33
use crate::object::color_space::DEVICE_GRAY;
44
use crate::serialize::{FilterStream, Object, SerializerContext};
55
use crate::util::{NameExt, Prehashed, SizeWrapper};
6+
use image::codecs::gif::GifDecoder;
67
use pdf_writer::{Chunk, Finish, Name, Ref};
78
use std::ops::DerefMut;
89
use std::sync::Arc;
@@ -111,6 +112,27 @@ impl Image {
111112
}))))
112113
}
113114

115+
pub fn from_gif(data: &[u8]) -> Option<Self> {
116+
let mut decoder = gif::DecodeOptions::new();
117+
decoder.set_color_output(gif::ColorOutput::RGBA);
118+
let mut decoder = decoder.read_info(data).ok()?;
119+
let first_frame = decoder.read_next_frame().ok()??;
120+
121+
let size = Size::from_wh(first_frame.width as f32, first_frame.height as f32)?;
122+
123+
let (image_data, mask_data, bits_per_component) =
124+
handle_u8_image(first_frame.buffer.to_vec(), ColorSpace::RGBA);
125+
126+
Some(Self(Arc::new(Prehashed::new(Repr {
127+
image_data,
128+
mask_data,
129+
is_dct_encoded: false,
130+
bits_per_component,
131+
image_color_space: ImageColorspace::Rgb,
132+
size: SizeWrapper(size),
133+
}))))
134+
}
135+
114136
pub fn size(&self) -> Size {
115137
self.0.size.0
116138
}
@@ -142,7 +164,7 @@ impl Object for Image {
142164

143165
let image_stream = if self.0.is_dct_encoded {
144166
FilterStream::new_from_dct_encoded(&self.0.image_data, &sc.serialize_settings)
145-
} else {
167+
} else {
146168
FilterStream::new_from_binary_data(&self.0.image_data, &sc.serialize_settings)
147169
};
148170

src/tests/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ pub fn load_jpg_image(name: &str) -> Image {
9292
Image::from_jpeg(&std::fs::read(ASSETS_PATH.join("images").join(name)).unwrap()).unwrap()
9393
}
9494

95+
pub fn load_gif_image(name: &str) -> Image {
96+
Image::from_gif(&std::fs::read(ASSETS_PATH.join("images").join(name)).unwrap()).unwrap()
97+
}
98+
9599
fn write_snapshot_to_store(name: &str, content: &[u8]) {
96100
let mut path = STORE_PATH.clone().join("snapshots");
97101
let _ = std::fs::create_dir_all(&path);

src/tests/visreg.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use crate::rgb::Rgb;
33
use crate::stream::Glyph;
44
use crate::surface::Surface;
55
use crate::tests::manual::all_glyphs_to_pdf;
6-
use crate::tests::{load_png_image, COLR_TEST_GLYPHS, NOTO_COLOR_EMOJI, NOTO_SANS, TWITTER_COLOR_EMOJI, load_jpg_image};
6+
use crate::tests::{
7+
load_gif_image, load_jpg_image, load_png_image, COLR_TEST_GLYPHS, NOTO_COLOR_EMOJI, NOTO_SANS,
8+
TWITTER_COLOR_EMOJI,
9+
};
710
use crate::util::SliceExt;
811
use crate::{rgb, Fill, LinearGradient, Paint, SpreadMethod, Stop};
912
use cosmic_text::{Attrs, Buffer, FontSystem, Metrics, Shaping};
@@ -150,6 +153,12 @@ fn jpg_image_impl(surface: &mut Surface, name: &str) {
150153
surface.draw_image(image, size);
151154
}
152155

156+
fn gif_image_impl(surface: &mut Surface, name: &str) {
157+
let image = load_gif_image(name);
158+
let size = image.size();
159+
surface.draw_image(image, size);
160+
}
161+
153162
#[visreg(all)]
154163
fn image_luma8_png(surface: &mut Surface) {
155164
png_image_impl(surface, "luma8.png");
@@ -189,3 +198,13 @@ fn image_luma8_jpg(surface: &mut Surface) {
189198
fn image_rgb8_jpg(surface: &mut Surface) {
190199
jpg_image_impl(surface, "rgb8.jpg");
191200
}
201+
202+
#[visreg(all)]
203+
fn image_rgb8_gif(surface: &mut Surface) {
204+
gif_image_impl(surface, "rgb8.gif");
205+
}
206+
207+
#[visreg(all)]
208+
fn image_rgba8_gif(surface: &mut Surface) {
209+
gif_image_impl(surface, "rgba8.gif");
210+
}

0 commit comments

Comments
 (0)