fix(#2): proper JPEG output via libraw_dcraw_make_mem_image + image crate
This commit is contained in:
parent
2481ed644b
commit
462541e096
@ -7,6 +7,7 @@ edition = "2024"
|
|||||||
libraw-sys = "0.1.1"
|
libraw-sys = "0.1.1"
|
||||||
image = "0.24"
|
image = "0.24"
|
||||||
clap = { version = "4.0", features = ["derive"] }
|
clap = { version = "4.0", features = ["derive"] }
|
||||||
|
libc = "0.2"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "photo_editor"
|
name = "photo_editor"
|
||||||
|
|||||||
39
src/main.rs
39
src/main.rs
@ -1,8 +1,10 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use image::{DynamicImage, ImageBuffer, Rgb};
|
||||||
use libraw_sys::*;
|
use libraw_sys::*;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::{c_int, c_size_t};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::ptr::null_mut;
|
||||||
|
|
||||||
/// Resolve and sanitize a user-provided path.
|
/// Resolve and sanitize a user-provided path.
|
||||||
/// - Resolves to absolute path via canonicalize (or parent canonicalization for output)
|
/// - Resolves to absolute path via canonicalize (or parent canonicalization for output)
|
||||||
@ -195,9 +197,42 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.unwrap_or("jpg")
|
.unwrap_or("jpg")
|
||||||
.to_lowercase();
|
.to_lowercase();
|
||||||
|
|
||||||
|
let ret = if ext == "jpg" || ext == "jpeg" {
|
||||||
|
// Use libraw_dcraw_make_mem_image + image crate for proper JPEG encoding
|
||||||
|
let mut imgdata: *mut std::os::raw::c_uchar = null_mut();
|
||||||
|
let mut imgsize: c_size_t = 0;
|
||||||
|
let ret = unsafe { libraw_dcraw_make_mem_image(lr, &mut imgdata, &mut imgsize) };
|
||||||
|
if ret != LIBRAW_SUCCESS {
|
||||||
|
ret
|
||||||
|
} else {
|
||||||
|
let width = unsafe { (*(*lr).internal_data).imgdata.idata.width } as u32;
|
||||||
|
let height = unsafe { (*(*lr).internal_data).imgdata.idata.height } as u32;
|
||||||
|
let bytes = unsafe { std::slice::from_raw_parts(imgdata, imgsize as usize) };
|
||||||
|
let img = DynamicImage::ImageRgb8(ImageBuffer::<Rgb<u8>, Vec<u8>>::from_raw(
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
bytes.to_vec(),
|
||||||
|
).ok_or("Failed to create image from libraw data")?);
|
||||||
|
unsafe {
|
||||||
|
let freedata = *(*lr).internal_data.imgdata.freedata;
|
||||||
|
let freesize = *(*lr).internal_data.imgdata.freesize;
|
||||||
|
if !freedata.is_null() {
|
||||||
|
libc::free(freedata as *mut std::os::raw::c_void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img.save_with_format(&output_path, image::ImageOutputFormat::Jpeg(90))
|
||||||
|
.map_err(|e| {
|
||||||
|
eprintln!("Error: Failed to write JPEG: {}", e);
|
||||||
|
"Failed to write JPEG".to_string()
|
||||||
|
})?;
|
||||||
|
LIBRAW_SUCCESS
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For TIFF/PPM, use libraw_dcraw_ppm_tiff_writer
|
||||||
let output_cstr = CString::new(output_path.to_string_lossy().as_bytes())
|
let output_cstr = CString::new(output_path.to_string_lossy().as_bytes())
|
||||||
.map_err(|_| "Output path contains null bytes, cannot process".into())?;
|
.map_err(|_| "Output path contains null bytes, cannot process".into())?;
|
||||||
let ret = unsafe { libraw_dcraw_ppm_tiff_writer(lr, output_cstr.as_ptr()) };
|
unsafe { libraw_dcraw_ppm_tiff_writer(lr, output_cstr.as_ptr()) }
|
||||||
|
};
|
||||||
|
|
||||||
if ret != LIBRAW_SUCCESS {
|
if ret != LIBRAW_SUCCESS {
|
||||||
eprintln!("Error: Failed to write output file. Error code: {}", ret);
|
eprintln!("Error: Failed to write output file. Error code: {}", ret);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user