1- using FastReport . Utils ;
1+ using FastReport . Utils ;
22using System ;
33using System . ComponentModel ;
44using System . Drawing ;
@@ -109,6 +109,14 @@ internal string Code
109109 return pattern ;
110110 }
111111 }
112+
113+ internal bool IsBarcodeRussianPost
114+ {
115+ get
116+ {
117+ return text . Length == 15 && text . StartsWith ( "RP" , StringComparison . OrdinalIgnoreCase ) ;
118+ }
119+ }
112120 #endregion
113121
114122 #region Private Methods
@@ -192,7 +200,12 @@ internal virtual void DoLines(string data, IGraphics g, float zoom)
192200 }
193201 }
194202
195- internal string CheckSumModulo10 ( string data )
203+ /// <summary>
204+ /// Calculates the modulo 10 checksum and appends it to the data.
205+ /// </summary>
206+ /// <param name="data">A string of numeric data.</param>
207+ /// <returns>The string with the appended checksum.</returns>
208+ public static string CheckSumModulo10 ( string data )
196209 {
197210 int sum = 0 ;
198211 int fak = data . Length ;
@@ -411,7 +424,12 @@ internal override void Initialize(string text, bool showText, int angle, float z
411424 internal override SizeF CalcBounds ( )
412425 {
413426 float barWidth = GetWidth ( Code ) ;
414- float extra1 = 0 ;
427+ if ( IsBarcodeRussianPost )
428+ {
429+ barWidth += 21.15f ; // Increase the width of the object
430+ }
431+
432+ float extra1 = IsBarcodeRussianPost ? 18 : 0 ; // Left margin 6 mm
415433 float extra2 = 0 ;
416434
417435 if ( showText )
@@ -439,20 +457,29 @@ internal override SizeF CalcBounds()
439457 extra2 = this . extra2 ;
440458
441459 drawArea = new RectangleF ( 0 , 0 , barWidth + extra1 + extra2 , 0 ) ;
442- barArea = new RectangleF ( extra1 , 0 , barWidth , 0 ) ;
460+ float barTopOffset = IsBarcodeRussianPost ? 9 : 0 ; // The indentation at the top of the barcode
461+ barArea = new RectangleF ( extra1 , barTopOffset , barWidth , 0 ) ;
443462
444- return new SizeF ( drawArea . Width * 1.25f , 0 ) ;
463+ float width = drawArea . Width * 1.25f ;
464+ float height = IsBarcodeRussianPost ? 56.7f : 0 ; // The height of the object at the AutoSize
465+ return new SizeF ( width , height ) ;
445466 }
446467
447468 /// <inheritdoc/>
448469 public override void DrawBarcode ( IGraphics g , RectangleF displayRect )
449470 {
450471 float originalWidth = CalcBounds ( ) . Width / 1.25f ;
472+
473+ if ( IsBarcodeRussianPost )
474+ {
475+ originalWidth -= 3f ; // Increasing the barcode width to meet the specification
476+ }
477+
451478 float width = angle == 90 || angle == 270 ? displayRect . Height : displayRect . Width ;
452479 float height = angle == 90 || angle == 270 ? displayRect . Width : displayRect . Height ;
453480 zoom = width / originalWidth ;
454481 barArea . Height = height / zoom ;
455- if ( showText )
482+ if ( showText && ! IsBarcodeRussianPost )
456483 {
457484 barArea . Height -= FontHeight ;
458485 if ( textUp )
@@ -479,18 +506,92 @@ public override void DrawBarcode(IGraphics g, RectangleF displayRect)
479506 break ;
480507 }
481508
509+ if ( IsBarcodeRussianPost )
510+ {
511+ g . DrawRectangle ( new Pen ( Color . Black , 1f ) , drawArea . X , drawArea . Y , displayRect . Width , displayRect . Height ) ;
512+ DrawTopLabel ( g , zoom ) ;
513+ barArea . Height -= 18 ; // Reducing the height of the barcode itself
514+ }
515+
482516 g . TranslateTransform ( barArea . Left * zoom , 0 ) ;
483517 DoLines ( pattern , g , zoom ) ;
484- if ( showText )
485- DrawText ( g , text ) ;
486518
519+ if ( IsBarcodeRussianPost )
520+ {
521+ DrawBottomLabel ( g , zoom , barArea , drawArea ) ;
522+ }
523+ else if ( showText )
524+ {
525+ DrawText ( g , text ) ;
526+ }
487527 }
488528 finally
489529 {
490530 g . Restore ( state ) ;
491531 }
492532 }
493533
534+ /// <summary>
535+ /// Draws a top label for the barcode, adjusting its size and position based on the zoom level.
536+ /// </summary>
537+ private static void DrawTopLabel ( IGraphics g , float zoom )
538+ {
539+ string label = "ПОЧТА РОССИИ" ;
540+ float labelHeight = 1.3f * Units . Millimeters * zoom ;
541+
542+ // Ensure the font size is valid (greater than 0) to avoid exceptions when creating the font
543+ float labelFontSize = labelHeight > 0 ? labelHeight : 0.1f ;
544+ Font labelFont = new Font ( "Arial" , labelFontSize , FontStyle . Regular ) ;
545+
546+ g . DrawString ( label , labelFont , Brushes . Black , 16.5f * zoom , 2f * zoom ) ;
547+ labelFont . Dispose ( ) ;
548+ }
549+
550+ /// <summary>
551+ /// Draws the bottom label text below the barcode, splitting it into parts and applying specific formatting. <br/>
552+ /// Adjusts positioning and spacing based on the zoom level and barcode area dimensions.
553+ /// </summary>
554+ private void DrawBottomLabel ( IGraphics g , float zoom , RectangleF barArea , RectangleF drawArea )
555+ {
556+ string text = base . text ;
557+
558+ text = CheckSumModulo10 ( text . Substring ( 2 ) ) ;
559+
560+ float fontSize = 1.8f * Units . Millimeters * zoom ;
561+
562+ using ( Font regularFont = new Font ( "Arial" , fontSize > 0 ? fontSize : 0.1f , FontStyle . Regular ) )
563+ using ( Font boldFont = new Font ( "Arial" , fontSize > 0 ? fontSize : 0.1f , FontStyle . Bold ) )
564+ {
565+ // Split the processed text into parts for separate rendering
566+ string [ ] parts = new string [ ]
567+ {
568+ text . Substring ( 0 , 6 ) ,
569+ text . Substring ( 6 , 2 ) ,
570+ text . Substring ( 8 , 5 ) ,
571+ text . Substring ( 13 , 1 )
572+ } ;
573+
574+ // Calculate the total width of all text parts, including spacing between them
575+ float totalWidth = 0 ;
576+ foreach ( var part in parts )
577+ {
578+ SizeF partSize = g . MeasureString ( part , regularFont ) ;
579+ totalWidth += partSize . Width + 2f ; // Add fixed spacing between parts
580+ }
581+
582+ float currentX = ( barArea . Left - 17 ) * zoom ; // Offset by 17 to move text closer to the left edge
583+ float textY = ( barArea . Bottom - 1 ) * zoom ; // Offset by 1 to move text closer to the barcode
584+
585+ for ( int i = 0 ; i < parts . Length ; i ++ )
586+ {
587+ SizeF partSize = g . MeasureString ( parts [ i ] , regularFont ) ;
588+ Font partFont = ( i == 2 ) ? boldFont : regularFont ;
589+ g . DrawString ( parts [ i ] , partFont , Brushes . Black , currentX , textY ) ;
590+ currentX += partSize . Width + ( 7f * zoom ) ; // Add spacing (7 units scaled by zoom) between parts
591+ }
592+ }
593+ }
594+
494595 internal void DrawString ( IGraphics g , float x1 , float x2 , string s )
495596 {
496597 DrawString ( g , x1 , x2 , s , false ) ;
0 commit comments