@@ -538,7 +538,7 @@ fn generate_ssh_key_internal(
538538 } )
539539}
540540
541- #[ derive( Deserialize , Default ) ]
541+ #[ derive( Serialize , Deserialize , Default ) ]
542542#[ serde( rename_all = "camelCase" ) ]
543543struct QrRequest {
544544 otp_account : Option < String > ,
@@ -551,9 +551,10 @@ struct QrRequest {
551551 wifi_pass : Option < String > ,
552552 wifi_ssid : Option < String > ,
553553 custom_string : Option < String > ,
554+ qr_ecc : Option < String > ,
554555}
555556
556- #[ derive( Serialize , Debug ) ]
557+ #[ derive( Serialize , Deserialize , Debug ) ]
557558#[ serde( rename_all = "camelCase" ) ]
558559struct QrResponse {
559560 kind : String ,
@@ -612,13 +613,14 @@ fn generate_qr_code_internal(
612613) -> Result < QrResponse , String > {
613614 let qr_kind = parse_qr_kind ( kind) ?;
614615 let content = build_qr_payload ( qr_kind, & payload) ?;
616+ let ecc_level = parse_qr_ecc_level ( payload. qr_ecc . as_deref ( ) ) ;
615617 let fmt = format. trim ( ) . to_ascii_lowercase ( ) ;
616618
617619 let ( data_base64, mime) = match fmt. as_str ( ) {
618- "png" => encode_bitmap_qr ( & content, ImageFormat :: Png ) ?,
619- "jpg" | "jpeg" => encode_bitmap_qr ( & content, ImageFormat :: Jpeg ) ?,
620- "webp" => encode_bitmap_qr ( & content, ImageFormat :: WebP ) ?,
621- "svg" => encode_svg_qr ( & content) ?,
620+ "png" => encode_bitmap_qr ( & content, ImageFormat :: Png , ecc_level ) ?,
621+ "jpg" | "jpeg" => encode_bitmap_qr ( & content, ImageFormat :: Jpeg , ecc_level ) ?,
622+ "webp" => encode_bitmap_qr ( & content, ImageFormat :: WebP , ecc_level ) ?,
623+ "svg" => encode_svg_qr ( & content, ecc_level ) ?,
622624 _ => return Err ( "format must be png, jpg, svg, or webp" . into ( ) ) ,
623625 } ;
624626
@@ -751,22 +753,35 @@ fn escape_wifi_field(value: &str) -> String {
751753 escaped
752754}
753755
754- fn render_qr_code_matrix ( content : & str ) -> Result < QrCode , String > {
755- QrCode :: with_error_correction_level ( content. as_bytes ( ) , EcLevel :: Q )
756+ fn parse_qr_ecc_level ( raw : Option < & str > ) -> EcLevel {
757+ match raw. unwrap_or ( "Q" ) . trim ( ) . to_ascii_uppercase ( ) . as_str ( ) {
758+ "L" => EcLevel :: L ,
759+ "M" => EcLevel :: M ,
760+ "H" => EcLevel :: H ,
761+ _ => EcLevel :: Q , // Default and fallback
762+ }
763+ }
764+
765+ fn render_qr_code_matrix ( content : & str , ecc : EcLevel ) -> Result < QrCode , String > {
766+ QrCode :: with_error_correction_level ( content. as_bytes ( ) , ecc)
756767 . map_err ( |err| format ! ( "invalid QR content: {err}" ) )
757768}
758769
759- fn render_qr_image ( content : & str ) -> Result < ImageBuffer < Luma < u8 > , Vec < u8 > > , String > {
760- let code = render_qr_code_matrix ( content) ?;
770+ fn render_qr_image ( content : & str , ecc : EcLevel ) -> Result < ImageBuffer < Luma < u8 > , Vec < u8 > > , String > {
771+ let code = render_qr_code_matrix ( content, ecc ) ?;
761772 Ok ( code
762773 . render :: < Luma < u8 > > ( )
763774 . min_dimensions ( QR_CODE_SIZE , QR_CODE_SIZE )
764775 . max_dimensions ( QR_CODE_SIZE , QR_CODE_SIZE )
765776 . build ( ) )
766777}
767778
768- fn encode_bitmap_qr ( content : & str , format : ImageFormat ) -> Result < ( String , String ) , String > {
769- let image = render_qr_image ( content) ?;
779+ fn encode_bitmap_qr (
780+ content : & str ,
781+ format : ImageFormat ,
782+ ecc : EcLevel ,
783+ ) -> Result < ( String , String ) , String > {
784+ let image = render_qr_image ( content, ecc) ?;
770785 let mut buffer = Vec :: new ( ) ;
771786 let mut cursor = Cursor :: new ( & mut buffer) ;
772787 DynamicImage :: ImageLuma8 ( image)
@@ -781,8 +796,8 @@ fn encode_bitmap_qr(content: &str, format: ImageFormat) -> Result<(String, Strin
781796 Ok ( ( STANDARD . encode ( buffer) , mime. into ( ) ) )
782797}
783798
784- fn encode_svg_qr ( content : & str ) -> Result < ( String , String ) , String > {
785- let code = render_qr_code_matrix ( content) ?;
799+ fn encode_svg_qr ( content : & str , ecc : EcLevel ) -> Result < ( String , String ) , String > {
800+ let code = render_qr_code_matrix ( content, ecc ) ?;
786801 let svg_text = code
787802 . render :: < svg:: Color > ( )
788803 . min_dimensions ( QR_CODE_SIZE , QR_CODE_SIZE )
0 commit comments