Memo -- printing product label based on rdlc Report

Posted by trent2800 on Wed, 19 Jan 2022 21:17:20 +0100

Zhiming - January 13, 2022 21:40:39

0. Background description

  • The product express box and packing box need to be pasted with a box label, indicating the following information of the product

    • Product inspection information
    • Product company information
    • Product SKU set applet mall QR code link
  • Final test Demo effect


1. Barcode generation

Use zxing Net generates product batch and SKU barcodes, and simply encapsulates an auxiliary class for creating barcodes

   using ZXing;
   using ZXing.Common;

   public static class BarCodeHelper
   {
       /// <summary>
       ///Create barcode
       /// </summary>
       ///< param name = "barcodeno" > barcode < / param >
       ///< param name = "height" > height < / param >
       ///< param name = "width" > width < / param >
       ///< returns > picture byte array < / returns >
       public static byte[] CreateBarCode(string barCodeNo, int height = 120, int width = 310)
       {
           EncodingOptions encoding = new EncodingOptions()
           {
               Height = height,
               Width = width,
               Margin = 1,
               PureBarcode = false//Bar codes are displayed under bar codes. If true, they are not displayed
           };
           BarcodeWriter wr = new BarcodeWriter()
           {
               Options = encoding,
               Format = BarcodeFormat.CODE_128,

           };
           Bitmap img = wr.Write(barCodeNo);

           //Save in current project path
           // string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\" + barCodeNo + ".jpg";
           // img.Save(filepath, ImageFormat.Jpeg);

           return BitmapToBytes(img);
       }

       /// <summary>
       ///Convert bitmap to byte array
       /// </summary>
       ///< param name = "bitmap" > bitmap < / param >
       /// <returns></returns>

       private static byte[] BitmapToBytes(Bitmap bitmap)
       {
           using (MemoryStream ms = new MemoryStream())
           {
               bitmap.Save(ms, ImageFormat.Gif);
               byte[] byteImage = new byte[ms.Length];
               byteImage = ms.ToArray();
               return byteImage;
           }
       }

   }

2. Obtain the applet code of the product

  • Dynamically obtain the applet code of the page in the wechat applet mall of the current product according to the SKU of the current product

  • Obtain applet codes, which are applicable to business scenarios with a large number of codes. The applet code generated through this interface is permanently valid, and the number is unlimited

    • POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
    • Refer to for specific parameters and return values: Wechat applet interface document
  • WebRequest sends a POST request to the wechat applet interface and accepts the returned picture button

    /// <summary>
    ///Send http Post request picture
    /// </summary>
    ///< param name = "URL" > request address < / param >
    ///< param name = "messsage" > request parameters < / param >
    ///< returns > byte array of picture < / returns >
    public static byte[] PostRequestReturnImage(string url, string messsage)
    {
        byte[] byteData = Encoding.UTF8.GetBytes(messsage);
        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
        webRequest.Method = "POST";
        webRequest.ContentType = "image/jpeg";
        webRequest.ContentLength = byteData.Length;
        webRequest.AddRange(0, 10000000);
        using (Stream stream = webRequest.GetRequestStream())
        {
            stream.Write(byteData, 0, byteData.Length);
        }
        using (Stream stream = webRequest.GetResponse().GetResponseStream())
        {
            using (BinaryReader br = new BinaryReader(stream))
            {
                byte[] butter = br.ReadBytes(10000000);
                return butter;
            }
        }
    }
    

3. Report designer design label template

3.1 add ReportViewer control to WinForm Control Toolbox

  • NuGet:PM>Install-Package Microsoft.ReportingServices.ReportViewerControl.WinForms -Pre

    • Note that ReportView has many dependencies. Execute the above commands to perform installation. Do not search for installation in the NuGet management interface to reduce unnecessary trouble
  • After installation, there is a ReportView control under the Microsoft SQL Server tab of winform toolbox

3.2 install RDLC report project template for VS2019

VS2019 does not have report items by default, and the extension needs to be installed: Microsoft Reporting Designer

  • Extensions -- > Administrative extensions -- > online search: Microsoft Rdlc Report Designer

  • After that, right-click the item -- > add to display the report:

3.3 create report file

  • Create a report file myreport RDLC, precautions

    • When you open the report file, the report data window will be displayed automatically. You are not reopening VS
    • Report data window -- > dataset -- > Add dataset
      • Define data object: ReportModel class
      • Set data source name: ReportModelObject
      • Data source: select the ReportModel object
  • Layout: I use the list layout and right-click to insert the list

  • Data binding: fields of the data source ReportModelObject

  • About image: first, right-click to insert the image. Image attribute settings:

    • Tooltip: value = system Convert. FromBase64String(Fields!Image1.Value)
    • Data sources: Databases
    • Use field: the image field in the ReportModel. For example, here is the Image1 field (string type)
    • MIME type: image/jpeg

3.4 ReportView initialization

    private void InitReport()
    {
        myReportViewer.LocalReport.ReportPath = "MyReport.rdlc";//Report file name
        ReportDataSource rds = new ReportDataSource
        {
            Name = "ReportModelObject",
            Value = GetDataSource()
        };
        myReportViewer.LocalReport.DataSources.Add(rds);
        myReportViewer.RefreshReport();
    }

    /// <summary>
    ///Data source used in the test
    /// </summary>
    /// <returns></returns>
    private List<ReportModel> GetDataSource()
    {
        return new List<ReportModel>()
            {
                new ReportModel()
                {
                    //Here is to convert the byte array of the picture into a string, so as to bind it in the report
                    Image1=Convert.ToBase64String(BarCodeHelper.CreateBarCode("123456789012")),
                }
            };
    }

4. Print the report in ReportView directly without popping up the printer selection window

Click the print button on the ViewReport control to pop up a window for selecting a printer. I don't want to

Set default printer in configuration file

<configuration>
	<appSettings >
		<add key="printer" value ="Printer name"/>
	</appSettings>	
</configuration>

Encapsulate a separate print auxiliary class. This liberation method is not my original. It is a reference blog Blank mapping: C# WinForm RDLC reports are printed continuously without preview

    public class PrintHelper
    {
        /// <summary>
        ///Used to record the page currently printed
        /// </summary>
        private int m_currentPageIndex;

        /// <summary>
        ///Declare a list of Stream objects to save the output data of the report. The Render method of LocalReport object will output the report as multiple Stream objects by page.
        /// </summary>
        private IList<Stream> m_streams;

        private bool isLandSapces = false;

        /// <summary>
        ///The function used to provide the Stream object and the third parameter of the Render method of the LocalReport object.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="fileNameExtension"></param>
        /// <param name="encoding"></param>
        /// <param name="mimeType"></param>
        /// <param name="willSeek"></param>
        /// <returns></returns>
        private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
        {
            //If you need to save the data output from the report as a file, use the FileStream object.
            Stream stream = new MemoryStream();
            m_streams.Add(stream);
            return stream;
        }

        /// <summary>
        ///For report RDLC creates a local report, loads data, and outputs the report to emf file, print and release resources at the same time
        /// </summary>
        ///< param name = "RV" > parameter: ReportViewer LocalReport</param>
        public void PrintStream(LocalReport rvDoc)
        {
            //Get the report page direction in LocalReport
            isLandSapces = rvDoc.GetDefaultPageSettings().IsLandscape;
            Export(rvDoc);
            PrintSetting();
            Dispose();
        }

        private void Export(LocalReport report)
        {
            string deviceInfo =
            @"<DeviceInfo>
                 <OutputFormat>EMF</OutputFormat>
             </DeviceInfo>";
            m_streams = new List<Stream>();
            //Output the contents of the report to the Stream provided by the CreateStream function in the format specified by deviceInfo.
            report.Render("Image", deviceInfo, CreateStream, out Warning[] warnings);
            foreach (Stream stream in m_streams)
            {
                stream.Position = 0;
            }
        }

        private void PrintSetting()
        {
            if (m_streams == null || m_streams.Count == 0)
            {
                throw new Exception("error:No print data stream detected");
            }
            //Declares a PrintDocument object for printing data
            PrintDocument printDoc = new PrintDocument();
            //Gets the manifest printer name of the configuration file
            System.Configuration.AppSettingsReader appSettings = new System.Configuration.AppSettingsReader();
            printDoc.PrinterSettings.PrinterName = appSettings.GetValue("printer", Type.GetType("System.String")).ToString();
            printDoc.PrintController = new StandardPrintController();//Specifies that the printer does not display page numbers 
            //Determines whether the specified printer is available
            if (!printDoc.PrinterSettings.IsValid)
            {
                throw new Exception("error:Printer not found");
            }
            else
            {
                //Set the printer direction to follow the report direction
                printDoc.DefaultPageSettings.Landscape = isLandSapces;
                //Declare the PrintPage event of the PrintDocument object. Specific printing operations need to be handled in this event.
                printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
                m_currentPageIndex = 0;
                //Set the number of copies printed by the printer
                printDoc.PrinterSettings.Copies = 1;
                //When the Print operation is executed, the Print method will trigger the PrintPage event.
                printDoc.Print();
            }
        }

        /// <summary>
        ///Handler PrintPageEvents
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ev"></param>
        private void PrintPage(object sender, PrintPageEventArgs ev)
        {
            //The Metafile object is used to save drawings in EMF or WMF format,
            //Earlier, we output the contents of the report to the data stream in EMF graphic format.
            Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);

            //Adjust the margins of the printer area
            System.Drawing.Rectangle adjustedRect = new System.Drawing.Rectangle(
                ev.PageBounds.Left - (int)ev.PageSettings.HardMarginX,
                ev.PageBounds.Top - (int)ev.PageSettings.HardMarginY,
                ev.PageBounds.Width,
                ev.PageBounds.Height);

            //Draw a report with a white background
            //ev.Graphics.FillRectangle(Brushes.White, adjustedRect);

            //Get report content
            //The Graphics object here actually points to the printer
            ev.Graphics.DrawImage(pageImage, adjustedRect);
            //ev.Graphics.DrawImage(pageImage, ev.PageBounds);

            // Preparing for the next page, it is determined that the operation has not ended
            m_currentPageIndex++;

            //Set whether to continue printing
            ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
        }

        public void Dispose()
        {
            if (m_streams != null)
            {
                foreach (Stream stream in m_streams)
                {
                    stream.Close();
                }

                m_streams = null;
            }
        }
    }

Custom print button: btnPrint, add its click event

    private void btnPrint_Click(object sender, EventArgs e)
    {
        PrintHelper printHelper = new PrintHelper();
        printHelper.PrintStream(myReportViewer.LocalReport);//myReportViewer is the name of the current ReportViewk control
    }

5. Reference

Topics: .NET