Skip to content

Commit

Permalink
Merge branch 'feature/heif' of github.com:woelper/oculante into featu…
Browse files Browse the repository at this point in the history
…re/heif
  • Loading branch information
woelper committed Nov 12, 2023
2 parents d6fc7d5 + 835de43 commit 0636a03
Show file tree
Hide file tree
Showing 13 changed files with 140 additions and 112 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/check_osx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
- name: cargo build
run: cargo build

- name: cargo check without default features
- name: Check without default features
run: cargo check --no-default-features

- name: Check without build features
run: cargo check --features heif
11 changes: 7 additions & 4 deletions .github/workflows/check_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ jobs:
- name: Install vcpkg
run: vcpkg integrate install

- name: Install cargo vcpkg
run: cargo install cargo-vcpkg
- name: Install libheif
run: vcpkg install libheif:x64-windows-static-md

- name: build heif
run: ./build_deps_win.bat
# - name: Install cargo vcpkg
# run: cargo install cargo-vcpkg

# - name: build heif
# run: ./build_deps_win.bat

# - name: cargo build
# run: cargo build
Expand Down
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,19 @@ dark-light = "1.0.0"
trash = "3.1"
lutgen = {version ="0.9.0", features = ["lutgen-palettes"]}
libheif-rs = { version = "0.22.0", default-features = false, optional = true}
egui-phosphor = "0.3.0"

[env]
PKG_CONFIG_PATH = "libheif"
PKG_CONFIG_PATH = "libheif/build"

[features]
heif = ["libheif-rs"]
avif_native = ["avif-decode"]
dav1d = ["libavif-image"]
default = ["turbo", "file_open", "avif_native", "update"]
file_open = ["rfd"]
turbo = ["turbojpeg"]
update = ["self_update"]
heif = ["libheif-rs"]

[target.'cfg(target_os = "macos")'.dependencies]
fruitbasket = "0.10.0"
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ pkgin install oculante
- exr (via `exr-rs`), tonemapped
- RAW (via `quickraw` - nef, cr2, dng, mos, erf, raf, arw, 3fr, ari, srf, sr2, braw, r3d, nrw, raw). Since raw is a complex field without true standards, not all camera models are supported.
- ppm
- HEIC/HEIF (via `libheif-rs`). Optional dependency, enabled on MacOS and Linux builds currently through `heif` flag.
- qoi

### Platform support:
- Linux
Expand All @@ -95,6 +97,7 @@ pkgin install oculante
- Lossless JPEG editing: Crop, rotate, mirror without recompressing data
- Light/Dark theme and follow system theme mode
- Network listen mode: Start with `oculante -l port` and oculante will switch to receive mode. You can then pipe raw image data to that port, for example using `nc localhost 8888 < image.jpg`. Image types will be auto-detected. If you pipe image sequences, these will be played at about 30 fps so you can pipe videos to it. This can be useful to visualize images from a headless system.
- EXIF support: Load metadata if present

### Misc examples:

Expand Down
10 changes: 6 additions & 4 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use std::env;
use std::fs::create_dir_all;
use std::fs::read_to_string;
use std::fs::remove_dir_all;
use std::fs::remove_file;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use std::fs::remove_file;

#[allow(dead_code)]
fn setup_heif() {
// use std::fs::create_dir_all;
// use std::fs::remove_dir_all;
// use std::process::Command;
let out_dir = env::var("OUT_DIR").unwrap();
let heif_path = format!("{out_dir}/libheif");
println!("heif is at {heif_path}");
Expand Down Expand Up @@ -55,6 +56,7 @@ fn setup_heif() {

#[cfg(target_os = "windows")]
{
use std::process::Command;
Command::new("git")
.args(["clone", "https://github.com/Microsoft/vcpkg.git"])
.status()
Expand Down
7 changes: 5 additions & 2 deletions build_deps_win.bat
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
@REM vcpkg install libde265:x64-windows
@REM vcpkg install libheif:x64-windows

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.bat
./vcpkg integrate install
./vcpkg install libheif
cd ..
@REM ./vcpkg install libheif
@REM cd ..
2 changes: 1 addition & 1 deletion build_mac.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export MACOSX_DEPLOYMENT_TARGET=10.15
cargo bundle --release
cargo bundle --release --features heif
# build universal binary
rustup target add aarch64-apple-darwin
cargo universal2
Expand Down
28 changes: 15 additions & 13 deletions src/image_editing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ use rand::{thread_rng, Rng};
use rayon::{iter::ParallelIterator, slice::ParallelSliceMut};
use serde::{Deserialize, Serialize};

use egui_phosphor::variants::regular::*;

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct EditState {
#[serde(skip)]
Expand Down Expand Up @@ -134,30 +136,30 @@ pub enum ImageOperation {
impl fmt::Display for ImageOperation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Self::Brightness(_) => write!(f, " Brightness"),
Self::Brightness(_) => write!(f, "{SUN} Brightness"),
Self::Noise { .. } => write!(f, "〰 Noise"),
Self::Desaturate(_) => write!(f, "🌁 Desaturate"),
Self::Posterize(_) => write!(f, "🖼 Posterize"),
Self::Contrast(_) => write!(f, "◑ Contrast"),
Self::Exposure(_) => write!(f, " Exposure"),
Self::Exposure(_) => write!(f, "{APERTURE} Exposure"),
Self::Equalize(_) => write!(f, "☯ Equalize"),
Self::Mult(_) => write!(f, "✖ Mult color"),
Self::Add(_) => write!(f, "➕ Add color"),
Self::Fill(_) => write!(f, "🍺 Fill color"),
Self::Blur(_) => write!(f, "💧 Blur"),
Self::Crop(_) => write!(f, " Crop"),
Self::Flip(_) => write!(f, " Flip"),
Self::Rotate(_) => write!(f, " Rotate"),
Self::Invert => write!(f, " Invert"),
Self::ChannelSwap(_) => write!(f, " Channel Copy"),
Self::Fill(_) => write!(f, "{PAINT_BUCKET} Fill color"),
Self::Blur(_) => write!(f, "{DROP} Blur"),
Self::Crop(_) => write!(f, "{CROP} Crop"),
Self::Flip(_) => write!(f, "{SWAP} Flip"),
Self::Rotate(_) => write!(f, "{ARROW_CLOCKWISE} Rotate"),
Self::Invert => write!(f, "{SELECTION_INVERSE} Invert"),
Self::ChannelSwap(_) => write!(f, "{FLOW_ARROW} Channel Copy"),
Self::HSV(_) => write!(f, "◔ HSV"),
Self::ChromaticAberration(_) => write!(f, "📷 Color Fringe"),
Self::Resize { .. } => write!(f, " Resize"),
Self::ChromaticAberration(_) => write!(f, "{CAMERA} Color Fringe"),
Self::Resize { .. } => write!(f, "{ARROWS_IN} Resize"),
Self::GradientMap { .. } => write!(f, "🗠 Gradient Map"),
Self::Expression(_) => write!(f, "📄 Expression"),
Self::Expression(_) => write!(f, "{FUNCTION} Expression"),
Self::MMult => write!(f, "✖ Multiply with alpha"),
Self::MDiv => write!(f, "➗ Divide by alpha"),
Self::LUT(_) => write!(f, "Apply Color LUT"),
Self::LUT(_) => write!(f, "{FILM_STRIP} Apply Color LUT"),
// _ => write!(f, "Not implemented Display"),
}
}
Expand Down
73 changes: 27 additions & 46 deletions src/image_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,58 +62,39 @@ pub fn open_image(img_location: &Path) -> Result<Receiver<Frame>> {
}
#[cfg(feature = "heif")]
"heif" | "heic" => {
use libheif_rs::{
Channel, ColorSpace, HeifContext, ItemId, LibHeif, Result, RgbChroma,
};
// Built on work in https://github.com/rsuu/rmg - thanks!
use libheif_rs::{ColorSpace, HeifContext, LibHeif, RgbChroma};

let lib_heif = LibHeif::new();
let ctx = HeifContext::read_from_file(&img_location.to_string_lossy())?;
let ctx = HeifContext::read_from_file(&img_location.to_string_lossy().to_string())?;
let handle = ctx.primary_image_handle()?;

// Get Exif
// let mut meta_ids: Vec<ItemId> = vec![0; 1];
// let count = handle.metadata_block_ids(&mut meta_ids, b"Exif");
// assert_eq!(count, 1);
// let exif: Vec<u8> = handle.metadata(meta_ids[0])?;

// Decode the image
let image = lib_heif.decode(&handle, ColorSpace::Rgb(RgbChroma::Rgb), None)?;
debug!("decoded HEIF/HEIC");

// Get "pixels"
let planes = image.planes();
let interleaved_plane = planes.interleaved.unwrap();


debug!("bpp {}", interleaved_plane.bits_per_pixel);
debug!("stride {}", interleaved_plane.stride);
debug!("sbpp {}", interleaved_plane.storage_bits_per_pixel);
debug!("s {}x{}", interleaved_plane.width, interleaved_plane.height);
let mut img_buffer = vec![];

for p in interleaved_plane.data.as_rgb() {
img_buffer.push(p.r);
img_buffer.push(p.g);
img_buffer.push(p.b);
img_buffer.push(255);
let img = lib_heif.decode(&handle, ColorSpace::Rgb(RgbChroma::Rgba), None)?;
let planes = img.planes();
let interleaved = planes.interleaved.context("Can't create interleaved plane")?;

let data = interleaved.data;
let width = interleaved.width;
let height = interleaved.height;
let stride = interleaved.stride;

let mut res: Vec<u8> = Vec::new();
for y in 0..height {
let mut step = y as usize * stride;

for _ in 0..width {
res.extend_from_slice(&[
data[step],
data[step + 1],
data[step + 2],
data[step + 3],
]);
step += 4;
}
}

// for interleaved_plane in buf {
// img_buffer.push(b.r);
// img_buffer.push(b.g);
// img_buffer.push(b.b);
// img_buffer.push(255);
// }
let buf = image::ImageBuffer::from_vec(interleaved_plane.width as u32, interleaved_plane.height as u32, img_buffer)
.context("Can't create HEIC ImageBuffer with given res")?;
// debug!("{:?}",buf.);
let buf = image::ImageBuffer::from_vec(width as u32, height as u32, res)
.context("Can't create HEIC/HEIF ImageBuffer with given res")?;
_ = sender.send(Frame::new_still(buf));
return Ok(receiver);

// let mut file = File::open(img_location)?;
// let mut buf = vec![];

// col.add_still(i.to_rgba8());
}
#[cfg(feature = "avif_native")]
#[cfg(not(feature = "dav1d"))]
Expand Down
10 changes: 1 addition & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,21 +252,13 @@ fn init(gfx: &mut Graphics, plugins: &mut Plugins) -> OculanteState {
.font_data
.insert("my_font".to_owned(), FontData::from_static(FONT));

// TODO: This needs to be a monospace font
// fonts.font_data.insert(
// "my_font_mono".to_owned(),
// FontData::from_static(include_bytes!("../res/fonts/FiraCode-Regular.ttf"))
// );

// Put my font first (highest priority):
fonts
.families
.get_mut(&FontFamily::Proportional)
.unwrap()
.insert(0, "my_font".to_owned());

// fonts.families.get_mut(&FontFamily::Monospace).unwrap()
// .insert(0, "my_font_mono".to_owned());
egui_phosphor::add_to_fonts(&mut fonts, egui_phosphor::Variant::Regular);

let mut style: egui::Style = (*ctx.style()).clone();
let font_scale = 0.80;
Expand Down
Loading

0 comments on commit 0636a03

Please sign in to comment.