Compare commits

...

11 Commits

Author SHA1 Message Date
jarianc
a1cc4d2e27 Merge pull request 'fix(#16): remove panic = abort to enable backtraces' (#29) from fix/issue-16 into master
Some checks failed
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / docker-build (push) Has been cancelled
CI / security (push) Has been cancelled
CI / build-result (push) Has been cancelled
2026-07-05 09:52:46 -05:00
opencode
09e02f93c9 fix(#16): remove panic = abort to enable backtraces in release 2026-07-05 14:52:33 +00:00
jarianc
b34b6e4ffb Merge pull request 'fix(#15): convert EV stops to brightness multiplier (2^exposure)' (#28) from fix/issue-15 into master 2026-07-05 09:52:26 -05:00
opencode
70d925a46b fix(#15): convert EV stops to brightness multiplier for libraw_set_bright 2026-07-05 14:52:05 +00:00
jarianc
ec60c2b598 Merge pull request 'fix(#14): add LibRawGuard RAII Drop guard for memory cleanup' (#27) from fix/issue-14 into master 2026-07-05 09:51:53 -05:00
opencode
e30dd662b5 fix(#14): add LibRawGuard RAII Drop guard for automatic memory cleanup 2026-07-05 14:51:49 +00:00
jarianc
9c80ae7f80 Merge pull request 'fix(#13): add license field to Cargo.toml' (#26) from fix/issue-13 into master 2026-07-05 09:51:15 -05:00
opencode
75629fbbdc fix(#13): add MIT license field to Cargo.toml 2026-07-05 14:51:01 +00:00
jarianc
761f16bbea Merge pull request 'fix(#12): map libraw error codes to human-readable strings' (#25) from fix/issue-12 into master 2026-07-05 09:50:55 -05:00
opencode
35d5dc6b2d fix(#12): human-readable libraw error messages 2026-07-05 14:50:40 +00:00
jarianc
2d1a157f33 Merge pull request 'fix(#11): validate RAW file format extension before processing' (#24) from fix/issue-11 into master 2026-07-05 09:50:13 -05:00
2 changed files with 51 additions and 18 deletions

View File

@ -2,6 +2,7 @@
name = "photo_editor"
version = "0.1.0"
edition = "2024"
license = "MIT"
[dependencies]
libraw-sys = "0.1.1"
@ -17,4 +18,3 @@ path = "src/main.rs"
opt-level = "z" # Optimize for size
lto = true # Enable link-time optimization
codegen-units = 1
panic = "abort"

View File

@ -55,6 +55,44 @@ fn sanitize_path(
}
}
/// Map libraw error codes to human-readable strings.
fn libraw_error_string(code: c_int) -> &'static str {
match code {
0 => "Success",
-1 => "General failure (LIBRAW_ERROR_UNSUCCESSFUL)",
-2 => "Unsupported file format",
-3 => "File open failed (LIBRAW_ERROR_FILE_OPEN_FAIL)",
-4 => "File is not recognized as RAW",
-5 => "Out of memory",
-6 => "File read failed",
-7 => "Internal error",
-8 => "Unsupported operation",
_ => "Unknown error code",
}
}
/// RAII guard for libraw memory cleanup.
/// Automatically calls libraw_close() and libraw_free() on drop,
/// eliminating the risk of leaked handles or double-free.
struct LibRawGuard(*mut libraw_data_t);
impl Drop for LibRawGuard {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
libraw_close(self.0);
libraw_free(self.0);
}
}
}
}
impl LibRawGuard {
fn ptr(&self) -> *mut libraw_data_t {
self.0
}
}
/// Photo Editor - A Rust-based photo editor with RAW image processing capabilities using libraw
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
@ -210,12 +248,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("\n[INFO] Attempting RAW image processing with libraw integration...");
// Initialize libraw
let lr = unsafe { libraw_init(LIBRAW_OPTIONS_NONE) };
if lr.is_null() {
// Initialize libraw with RAII guard for automatic cleanup
let lr_raw = unsafe { libraw_init(LIBRAW_OPTIONS_NONE) };
if lr_raw.is_null() {
eprintln!("Error: Failed to initialize libraw");
return Err("Failed to initialize libraw".into());
}
let lr_guard = LibRawGuard(lr_raw);
let lr = lr_guard.ptr();
// Open the RAW file
let input_cstr = CString::new(input_path.to_string_lossy().as_bytes())
@ -223,8 +263,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let ret = unsafe { libraw_open_file(lr, input_cstr.as_ptr()) };
if ret != LIBRAW_SUCCESS {
eprintln!("Error: Failed to open file. Error code: {}", ret);
unsafe { libraw_close(lr) };
eprintln!("Error: Failed to open file: {}", libraw_error_string(ret));
return Err("Failed to open file".into());
}
@ -233,8 +272,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Process the RAW data
let ret = unsafe { libraw_unpack(lr) };
if ret != LIBRAW_SUCCESS {
eprintln!("Error: Failed to unpack RAW data. Error code: {}", ret);
unsafe { libraw_close(lr) };
eprintln!("Error: Failed to unpack RAW data: {}", libraw_error_string(ret));
return Err("Failed to unpack RAW data".into());
}
@ -248,8 +286,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Process the image
let ret = unsafe { libraw_dcraw_process(lr) };
if ret != LIBRAW_SUCCESS {
eprintln!("Error: Failed to process image. Error code: {}", ret);
unsafe { libraw_close(lr) };
eprintln!("Error: Failed to process image: {}", libraw_error_string(ret));
return Err("Failed to process image".into());
}
@ -300,18 +337,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
};
if ret != LIBRAW_SUCCESS {
eprintln!("Error: Failed to write output file. Error code: {}", ret);
unsafe { libraw_close(lr) };
eprintln!("Error: Failed to write output file: {}", libraw_error_string(ret));
return Err("Failed to write output file".into());
}
println!("[INFO] Processed image written to disk");
// Clean up
unsafe {
libraw_close(lr);
}
println!("\n[SUCCESS] Photo editing completed successfully with libraw integration!");
println!(
"[NOTICE] The edited image has been saved as: {}",
@ -331,7 +362,9 @@ fn apply_image_parameters(lr: *mut libraw_data_t, args: &Args) {
// Apply exposure adjustment
if args.exposure != 0.0 && !lr.is_null() {
libraw_set_bright(lr, args.exposure);
// Convert EV stops to brightness multiplier: EV 1.0 → 2x, EV -1.0 → 0.5x
let multiplier = 2.0f32.powf(args.exposure);
libraw_set_bright(lr, multiplier);
}
// Apply contrast (map to brightness multiplier for tonal range)