Skip to content

Commit

Permalink
feat: images to webp (#92)
Browse files Browse the repository at this point in the history
Converts all bmp and png images to webp
  • Loading branch information
francisdb authored Jun 14, 2024
1 parent 3b67d84 commit b5cf28d
Show file tree
Hide file tree
Showing 4 changed files with 339 additions and 31 deletions.
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

0 comments on commit b5cf28d

Please sign in to comment.