From 462541e09687e039fb4dbd08ef80b61f77407b4c Mon Sep 17 00:00:00 2001 From: opencode Date: Sun, 5 Jul 2026 14:46:29 +0000 Subject: [PATCH] fix(#2): proper JPEG output via libraw_dcraw_make_mem_image + image crate --- Cargo.toml | 1 + src/main.rs | 43 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bd6ba1c..64bc3d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/main.rs b/src/main.rs index 9801afb..1c10200 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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> { .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::, Vec>::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);