@@ -3,7 +3,7 @@ pub mod features;
33
44use crate :: common:: engine:: { EmbedInfo , EmbedResult , ExtractResult , WatermarkEngine } ;
55use crate :: common:: temp_input_for_inference:: TempInputForInference ;
6- use crate :: common:: { ecc, password, scramble} ;
6+ use crate :: common:: { WatermarkError , ecc, password, scramble} ;
77
88use features:: { detect_keypoints, FeaturePoint , PATCH_SIZE } ;
99use image:: { DynamicImage , GenericImageView , GrayImage , Luma } ;
@@ -57,7 +57,7 @@ fn analyze(
5757 message : & str ,
5858 intensity : u8 ,
5959 output_path : & str ,
60- ) -> Result < ( EmbedInfo , bool ) , String > {
60+ ) -> Result < ( EmbedInfo , bool ) , crate :: common :: WatermarkError > {
6161 let ( w, h) = img. dimensions ( ) ;
6262 let intensity = resolve_intensity ( intensity, w, h) ;
6363 let gray = channel_to_gray ( img) ;
@@ -100,8 +100,8 @@ impl WatermarkEngine for RasterEngine {
100100 password : & str ,
101101 intensity : u8 ,
102102 output_path : & str ,
103- ) -> Result < EmbedResult , String > {
104- let img = image:: open ( input_path) . map_err ( |e| format ! ( "Failed to open image: {}" , e ) ) ?;
103+ ) -> Result < EmbedResult , WatermarkError > {
104+ let img = image:: open ( input_path) ?;
105105 let ( info, use_fp) = analyze ( & img, message, intensity, output_path) ?;
106106 let gray = channel_to_gray ( & img) ;
107107 let kps = detect_keypoints ( & gray, MAX_KEYPOINTS ) ;
@@ -125,20 +125,17 @@ impl WatermarkEngine for RasterEngine {
125125 _password : & str ,
126126 intensity : u8 ,
127127 output_path : & str ,
128- ) -> Result < EmbedInfo , String > {
129- let img = image:: open ( input_path) . map_err ( |e| format ! ( "Failed to open image: {}" , e ) ) ?;
128+ ) -> Result < EmbedInfo , WatermarkError > {
129+ let img = image:: open ( input_path) ?;
130130 let ( info, _) = analyze ( & img, message, intensity, output_path) ?;
131131 if info. message_bytes > info. max_capacity {
132- return Err ( format ! (
133- "Message too long: {} bytes, max capacity: {} bytes (mode: {})" ,
134- info. message_bytes, info. max_capacity, info. mode
135- ) ) ;
132+ return Err ( WatermarkError :: CapacityExceeded { max : info. max_capacity , actual : info. message_bytes , mode : "global-dwt" } ) ;
136133 }
137134 Ok ( info)
138135 }
139136
140- fn verify ( & self , input_path : & str , password : & str ) -> Result < ExtractResult , String > {
141- let img = image:: open ( input_path) . map_err ( |e| format ! ( "Failed to open image: {}" , e ) ) ?;
137+ fn verify ( & self , input_path : & str , password : & str ) -> Result < ExtractResult , WatermarkError > {
138+ let img = image:: open ( input_path) ?;
142139 let gray = channel_to_gray ( & img) ;
143140 let kps = detect_keypoints ( & gray, MAX_KEYPOINTS ) ;
144141 let channel = extract_channel ( & img) ;
@@ -170,7 +167,7 @@ impl RasterEngine {
170167 message : & str ,
171168 password : & str ,
172169 intensity : u8 ,
173- ) -> Result < ( ) , String > {
170+ ) -> Result < ( ) , WatermarkError > {
174171 let gray = gray_from_rgb ( rgb, width, height, DETECT_CHANNEL ) ;
175172 let kps = detect_keypoints ( & gray, MAX_KEYPOINTS ) ;
176173 let channel = channel_from_rgb ( rgb, width, height, EMBED_CHANNEL ) ;
@@ -222,7 +219,7 @@ impl RasterEngine {
222219 let mut coeffs = dwt:: forward ( & channel) ;
223220 let ( br, bc, nb) = count_blocks ( coeffs. hl . len ( ) , coeffs. hl [ 0 ] . len ( ) ) ;
224221 if nb == 0 {
225- return Err ( "Image too small for watermarking" . to_string ( ) ) ;
222+ return Err ( WatermarkError :: ImageTooSmall ) ;
226223 }
227224 let bits = ecc:: encode ( message. as_bytes ( ) , nb) ?;
228225 let seed = password:: password_to_seed ( password) ;
@@ -267,7 +264,7 @@ impl RasterEngine {
267264 width : u32 ,
268265 height : u32 ,
269266 password : & str ,
270- ) -> Result < ExtractResult , String > {
267+ ) -> Result < ExtractResult , WatermarkError > {
271268 let gray = gray_from_rgb ( rgb, width, height, DETECT_CHANNEL ) ;
272269 let kps = detect_keypoints ( & gray, MAX_KEYPOINTS ) ;
273270 let channel = channel_from_rgb ( rgb, width, height, EMBED_CHANNEL ) ;
@@ -371,13 +368,9 @@ fn calculate_local_alpha(
371368 global_alpha * multiplier
372369}
373370
374- fn fp_encode ( message : & [ u8 ] ) -> Result < Vec < bool > , String > {
371+ fn fp_encode ( message : & [ u8 ] ) -> Result < Vec < bool > , WatermarkError > {
375372 if message. len ( ) > FP_MAX_MESSAGE {
376- return Err ( format ! (
377- "Message too long for feature-point mode: max {} bytes, got {}" ,
378- FP_MAX_MESSAGE ,
379- message. len( )
380- ) ) ;
373+ return Err ( WatermarkError :: CapacityExceeded { max : FP_MAX_MESSAGE , actual : message. len ( ) , mode : "feature-point" } ) ;
381374 }
382375 let total_bytes = BLOCKS_PER_PATCH / 8 ;
383376 let mut payload = vec ! [ 0u8 ; total_bytes] ;
@@ -393,9 +386,9 @@ fn fp_encode(message: &[u8]) -> Result<Vec<bool>, String> {
393386 Ok ( bits)
394387}
395388
396- fn fp_decode ( bits : & [ bool ] ) -> Result < Vec < u8 > , String > {
389+ fn fp_decode ( bits : & [ bool ] ) -> Result < Vec < u8 > , WatermarkError > {
397390 if bits. len ( ) < 8 {
398- return Err ( "Not enough bits" . to_string ( ) ) ;
391+ return Err ( WatermarkError :: ExtractionCorrupt ) ;
399392 }
400393 let mut bytes = Vec :: with_capacity ( bits. len ( ) / 8 ) ;
401394 for chunk in bits. chunks ( 8 ) {
@@ -412,7 +405,7 @@ fn fp_decode(bits: &[bool]) -> Result<Vec<u8>, String> {
412405 }
413406 let len = bytes[ 0 ] as usize ;
414407 if len == 0 || 1 + len > bytes. len ( ) {
415- return Err ( "Invalid message length" . to_string ( ) ) ;
408+ return Err ( WatermarkError :: ExtractionCorrupt ) ;
416409 }
417410 Ok ( bytes[ 1 ..1 + len] . to_vec ( ) )
418411}
@@ -424,7 +417,7 @@ fn embed_feature_point(
424417 password : & str ,
425418 raw_intensity : u8 ,
426419 output_path : & str ,
427- ) -> Result < ( ) , String > {
420+ ) -> Result < ( ) , WatermarkError > {
428421 let ( width, height) = img. dimensions ( ) ;
429422 let alpha = fp_alpha ( raw_intensity, width, height) ;
430423
@@ -478,7 +471,7 @@ fn verify_feature_point(
478471 keypoints : & [ FeaturePoint ] ,
479472 password : & str ,
480473 channel : & [ Vec < f64 > ] ,
481- ) -> Result < ExtractResult , String > {
474+ ) -> Result < ExtractResult , WatermarkError > {
482475 let seed = password:: password_to_seed ( password) ;
483476 let ch_h = channel. len ( ) ;
484477 let ch_w = if ch_h > 0 { channel[ 0 ] . len ( ) } else { 0 } ;
@@ -580,14 +573,14 @@ fn embed_global_dwt(
580573 password : & str ,
581574 raw_intensity : u8 ,
582575 output_path : & str ,
583- ) -> Result < ( ) , String > {
576+ ) -> Result < ( ) , WatermarkError > {
584577 let ( w, h) = img. dimensions ( ) ;
585578 let alpha = dwt_alpha ( raw_intensity, w, h) ;
586579 let ch = extract_channel ( img) ;
587580 let mut coeffs = dwt:: forward ( & ch) ;
588581 let ( br, bc, nb) = count_blocks ( coeffs. hl . len ( ) , coeffs. hl [ 0 ] . len ( ) ) ;
589582 if nb == 0 {
590- return Err ( "Image too small for watermarking" . to_string ( ) ) ;
583+ return Err ( WatermarkError :: ImageTooSmall ) ;
591584 }
592585
593586 let bits = ecc:: encode ( message. as_bytes ( ) , nb) ?;
@@ -629,7 +622,7 @@ fn embed_global_dwt(
629622fn verify_global_dwt_from_channel (
630623 channel : & [ Vec < f64 > ] ,
631624 password : & str ,
632- ) -> Result < ExtractResult , String > {
625+ ) -> Result < ExtractResult , WatermarkError > {
633626 let coeffs = dwt:: forward ( channel) ;
634627 let ( _, bc, nb) = count_blocks ( coeffs. hl . len ( ) , coeffs. hl [ 0 ] . len ( ) ) ;
635628 if nb == 0 {
@@ -809,7 +802,7 @@ fn save_channel_to_image(
809802 width : u32 ,
810803 height : u32 ,
811804 path : & str ,
812- ) -> Result < ( ) , String > {
805+ ) -> Result < ( ) , WatermarkError > {
813806 let mut out = img. to_rgba8 ( ) ;
814807 let oh = height. min ( channel. len ( ) as u32 ) ;
815808 let ow = width. min ( if channel. is_empty ( ) {
@@ -825,8 +818,7 @@ fn save_channel_to_image(
825818 out. put_pixel ( x, y, px) ;
826819 }
827820 }
828- out. save ( path)
829- . map_err ( |e| format ! ( "Failed to save image: {}" , e) )
821+ Ok ( out. save ( path) ?)
830822}
831823
832824#[ cfg( test) ]
0 commit comments