fix(#2): proper JPEG output via libraw_dcraw_make_mem_image + image crate

This commit is contained in:
opencode 2026-07-05 14:46:29 +00:00
parent 2481ed644b
commit 462541e096
2 changed files with 40 additions and 4 deletions

View File

@ -7,6 +7,7 @@ edition = "2024"
libraw-sys = "0.1.1"
image = "0.24"
clap = { version = "4.0", features = ["derive"] }
libc = "0.2"
[[bin]]
name = "photo_editor"

View File

@ -1,8 +1,10 @@
use clap::Parser;
use image::{DynamicImage, ImageBuffer, Rgb};
use libraw_sys::*;
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::ptr::null_mut;
/// Resolve and sanitize a user-provided path.
/// - 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")
.to_lowercase();
let output_cstr = CString::new(output_path.to_string_lossy().as_bytes())
.map_err(|_| "Output path contains null bytes, cannot process".into())?;
let ret = unsafe { libraw_dcraw_ppm_tiff_writer(lr, output_cstr.as_ptr()) };
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())
.map_err(|_| "Output path contains null bytes, cannot process".into())?;
unsafe { libraw_dcraw_ppm_tiff_writer(lr, output_cstr.as_ptr()) }
};
if ret != LIBRAW_SUCCESS {
eprintln!("Error: Failed to write output file. Error code: {}", ret);