66
77use super :: matrix:: Canvas ;
88use super :: tables:: { char_count_bits, info, mode_value} ;
9- use super :: { RmqrEcLevel , RmqrMeta , RmqrSize } ;
9+ use super :: { RmqrEcLevel , RmqrMeta , RmqrSize , SizeStrategy } ;
1010use crate :: codes:: qr:: gf;
1111use crate :: error:: { Error , Result } ;
1212use crate :: output:: Encoding ;
@@ -26,9 +26,20 @@ impl RmqrEncoder {
2626 }
2727
2828 /// Build a reproducible [`Symbol`] from `segments` at EC `level`, choosing the
29- /// smallest-area fitting size.
29+ /// smallest-area fitting size ([`SizeStrategy::Balanced`]) .
3030 pub fn build ( & self , segments : Vec < Segment > , level : RmqrEcLevel ) -> Result < Symbol > {
31- let size = choose_size ( & segments, level) ?;
31+ self . build_with ( segments, level, SizeStrategy :: Balanced )
32+ }
33+
34+ /// Build a reproducible [`Symbol`], choosing the fitting size per `strategy`
35+ /// (flat-and-wide, tall-and-narrow, or most-compact).
36+ pub fn build_with (
37+ & self ,
38+ segments : Vec < Segment > ,
39+ level : RmqrEcLevel ,
40+ strategy : SizeStrategy ,
41+ ) -> Result < Symbol > {
42+ let size = choose_size ( & segments, level, strategy) ?;
3243 let meta = RmqrMeta {
3344 size,
3445 ec_level : level,
@@ -44,6 +55,20 @@ impl RmqrEncoder {
4455 pub fn build_text ( & self , text : & str , level : RmqrEcLevel ) -> Result < Symbol > {
4556 self . build ( vec ! [ Segment :: byte( text. as_bytes( ) . to_vec( ) ) ] , level)
4657 }
58+
59+ /// Convenience: [`build_with`](Self::build_with) from UTF-8 `text`.
60+ pub fn build_text_with (
61+ & self ,
62+ text : & str ,
63+ level : RmqrEcLevel ,
64+ strategy : SizeStrategy ,
65+ ) -> Result < Symbol > {
66+ self . build_with (
67+ vec ! [ Segment :: byte( text. as_bytes( ) . to_vec( ) ) ] ,
68+ level,
69+ strategy,
70+ )
71+ }
4772}
4873
4974impl Encode for RmqrEncoder {
@@ -186,21 +211,35 @@ fn segments_bit_len(segments: &[Segment], size: RmqrSize) -> Option<usize> {
186211}
187212
188213/// The smallest-area size (at `level`) whose data capacity holds `segments`.
189- fn choose_size ( segments : & [ Segment ] , level : RmqrEcLevel ) -> Result < RmqrSize > {
190- let mut best: Option < ( RmqrSize , usize ) > = None ;
214+ fn choose_size (
215+ segments : & [ Segment ] ,
216+ level : RmqrEcLevel ,
217+ strategy : SizeStrategy ,
218+ ) -> Result < RmqrSize > {
219+ let mut best: Option < RmqrSize > = None ;
191220 for size in RmqrSize :: all ( ) {
192221 let cap = info ( size) . data_bit_capacity ( level) ;
193222 if let Some ( len) = segments_bit_len ( segments, size)
194223 && len <= cap
224+ && best. is_none_or ( |b| prefers ( size, b, strategy) )
195225 {
196- let area = size. width ( ) * size. height ( ) ;
197- if best. as_ref ( ) . is_none_or ( |& ( _, a) | area < a) {
198- best = Some ( ( size, area) ) ;
199- }
226+ best = Some ( size) ;
227+ }
228+ }
229+ best. ok_or_else ( || Error :: capacity ( "data does not fit any rMQR size at this EC level" ) )
230+ }
231+
232+ /// Whether `a` is preferred over the current best `b` under `strategy`. Every
233+ /// strategy uses smaller area as the tie-breaker so the result stays compact.
234+ fn prefers ( a : RmqrSize , b : RmqrSize , strategy : SizeStrategy ) -> bool {
235+ let area = |s : RmqrSize | s. width ( ) * s. height ( ) ;
236+ match strategy {
237+ SizeStrategy :: Balanced => area ( a) < area ( b) ,
238+ SizeStrategy :: MinHeight => ( a. height ( ) , area ( a) ) < ( b. height ( ) , area ( b) ) ,
239+ SizeStrategy :: MaxHeight => {
240+ a. height ( ) > b. height ( ) || ( a. height ( ) == b. height ( ) && area ( a) < area ( b) )
200241 }
201242 }
202- best. map ( |( s, _) | s)
203- . ok_or_else ( || Error :: capacity ( "data does not fit any rMQR size at this EC level" ) )
204243}
205244
206245/// Build the full interleaved codeword bit stream (data + EC + remainder).
0 commit comments