Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: images to webp #92

Merged
merged 5 commits into from
Jun 14, 2024
Merged
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ wavefront_rs = "2.0.0-beta.1"
flate2 = "1.0.28"
image = "0.25.1"
weezl = "0.1.8"
regex = "1.10.5"

[dev-dependencies]
dirs = "5.0.1"
Expand Down
38 changes: 24 additions & 14 deletions src/vpx/expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,15 +359,8 @@ fn write_image_bmp(
width: u32,
height: u32,
) -> io::Result<()> {
let decompressed_bgra = from_lzw_blocks(lzw_compressed_data);
let decompressed_rgba: Vec<u8> = swap_red_and_blue(&decompressed_bgra);

let rgba_image = image::RgbaImage::from_raw(width, height, decompressed_rgba)
.expect("Decompressed image data does not match dimensions");
let dynamic_image = DynamicImage::ImageRgba8(rgba_image);

let uses_alpha = decompressed_bgra.chunks_exact(4).any(|bgra| bgra[3] != 255);
let image_to_save = if uses_alpha {
let image_to_save = vpx_image_to_dynamic_image(lzw_compressed_data, width, height);
if image_to_save.color().has_alpha() {
// One example is the table "Guns N Roses (Data East 1994).vpx"
// that contains vp9 images with non-255 alpha values.
// They are actually labeled as sRGBA in the Visual Pinball image manager.
Expand All @@ -380,11 +373,7 @@ fn write_image_bmp(
"Image {} has non-opaque pixels, writing as RGBA BMP that might not be supported by all applications",
file_name
);
dynamic_image
} else {
let rgb_image = dynamic_image.to_rgb8();
DynamicImage::ImageRgb8(rgb_image)
};
}
image_to_save.save(file_path).map_err(|image_error| {
io::Error::new(
io::ErrorKind::Other,
Expand All @@ -397,6 +386,27 @@ fn write_image_bmp(
})
}

pub(crate) fn vpx_image_to_dynamic_image(
lzw_compressed_data: &[u8],
width: u32,
height: u32,
) -> DynamicImage {
let decompressed_bgra = from_lzw_blocks(lzw_compressed_data);
let decompressed_rgba: Vec<u8> = swap_red_and_blue(&decompressed_bgra);

let rgba_image = image::RgbaImage::from_raw(width, height, decompressed_rgba)
.expect("Decompressed image data does not match dimensions");
let dynamic_image = DynamicImage::ImageRgba8(rgba_image);

let uses_alpha = decompressed_bgra.chunks_exact(4).any(|bgra| bgra[3] != 255);
if uses_alpha {
dynamic_image
} else {
let rgb_image = dynamic_image.to_rgb8();
DynamicImage::ImageRgb8(rgb_image)
}
}

/// Can convert between RGBA and BGRA by swapping the red and blue channels
fn swap_red_and_blue(data: &[u8]) -> Vec<u8> {
let mut swapped = Vec::with_capacity(data.len());
Expand Down
21 changes: 18 additions & 3 deletions src/vpx/image.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::fmt;

use super::biff::{self, BiffRead, BiffReader, BiffWrite, BiffWriter};

#[derive(PartialEq)]
#[derive(PartialEq, Clone)]
pub struct ImageDataJpeg {
pub path: String,
pub name: String,
Expand Down Expand Up @@ -31,7 +32,7 @@ impl fmt::Debug for ImageDataJpeg {
/**
* A bitmap blob, typically used by textures.
*/
#[derive(PartialEq)]
#[derive(PartialEq, Clone)]
pub struct ImageDataBits {
/// Lzw compressed raw BMP 32-bit sBGRA bitmap data
/// However we expect the alpha channel to always be 255
Expand All @@ -47,7 +48,7 @@ impl fmt::Debug for ImageDataBits {
}
}

#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone)]
pub struct ImageData {
pub name: String, // NAME
// /**
Expand Down Expand Up @@ -77,6 +78,20 @@ pub struct ImageData {
impl ImageData {
const ALPHA_TEST_VALUE_DEFAULT: f32 = -1.0;

pub(crate) fn change_extension(&mut self, ext: &str) {
let mut path = self.path.clone();
let re = Regex::new(r"\.[a-zA-Z0-9]+$").unwrap();
path = re.replace(&path, format!(".{ext}")).to_string();
self.path = path;

// to the same for the jpeg path
if let Some(jpeg) = &mut self.jpeg {
let mut path = jpeg.path.clone();
path = re.replace(&path, format!(".{ext}")).to_string();
jpeg.path = path;
}
}

pub fn is_link(&self) -> bool {
self.link == Some(1)
}
Expand Down
Loading