using FastReport.Barcode; using FastReport.Table; using FastReport.Utils; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; using System.Text; namespace FastReport.Export.Zpl { /// /// Represents the Zpl export filter. /// public partial class ZplExport : ExportBase { #region Public properties /// /// Enum of ZPL format versions. /// public enum ZplVersions { /// /// Standart ZPL /// ZPL1, /// /// ZPL II /// ZPL2 } /// /// Enum of densty types of Zebra printers. /// public enum ZplDensity { /// /// 6 dpmm(152 dpi) /// d6_dpmm_152_dpi, /// /// 8 dpmm(203 dpi) /// d8_dpmm_203_dpi, /// /// 12 dpmm(300 dpi) /// d12_dpmm_300_dpi, /// /// 24 dpmm(600 dpi) /// d24_dpmm_600_dpi } /// /// Sets the density of printer. /// public ZplDensity Density { get { return density; } set { density = value; } } /// /// Gets or sets the version of ZPL. /// public ZplVersions Version { get { return version; } set { version = value; } } /// /// Sets the init string for sending before printing the document. /// public string PrinterInit { get { return printerInit; } set { printerInit = value; } } /// /// Sets the code page of document. Default is UTF-8 (^CI28). /// public string CodePage { get { return codePage; } set { codePage = value; } } /// /// Sets the string for sending after printing the document. /// public string PrinterFinish { get { return printerFinish; } set { printerFinish = value; } } /// /// Sets the string for sending before printing each page. /// public string PageInit { get { return pageInit; } set { pageInit = value; } } /// /// Sets the scale font size. /// public float FontScale { get { return fontScale / defaultFontScale; } set { fontScale = value * defaultFontScale; } } /// /// Sets the scale barcode size. /// public float BarcodeScale { get { return barcodeScale; } set { barcodeScale = value; } } /// /// Sets the Printer Font, default value is "A". /// public string PrinterFont { get { return font; } set { font = value; } } /// /// Enable or disable export as bitmap. /// public bool PrintAsBitmap { get { return printAsBitmap; } set { printAsBitmap = value; } } #endregion Public properties #region Private constants private const float millimeters = 3.78f; private const float defaultFontScale = 1.4f; private const float defaultBarcodeScale = 2f; #endregion Private constants #region Private Fields #if READONLY_STRUCTS private readonly struct ZplScale #else private struct ZplScale #endif { public readonly float PageScale; public readonly int TwoDCodeScale; public ZplScale(float pageScale, int qrCodeScale) { PageScale = pageScale; TwoDCodeScale = qrCodeScale; } } // scales of X and Y position and sized depend by ZplDensity // second value is multiplier for barcode zoom private ZplScale[] zplScaleArray = { //6 dpmm(152 dpi) new ZplScale(1.5833f, 7), //8 dpmm(203 dpi) new ZplScale(2.11458f, 8), //12 dpmm(300 dpi) new ZplScale(3.16667f, 10), //24 dpmm(600 dpi) new ZplScale(6.34375f, 10) }; // Enable for Print as Bitmap; private bool printAsBitmap = true; private ZplDensity density = ZplDensity.d8_dpmm_203_dpi; private ZplVersions version = ZplVersions.ZPL1; // Printer Init String. Sends before document. private string printerInit; // Printer Finish String. Sends after document. private string printerFinish; // Printer page init string. Sends before page. private string pageInit; // Font scale factor. private float fontScale = defaultFontScale; // Barcode scale factor (BY..). private static float barcodeScale = defaultBarcodeScale; // Position in ZipScale array by default (8 dpmm(203 dpi) private int scaleIndex = 1; private float leftMargin = 0; private float topMargin = 0; // font private string font = "A"; private string codePage = "^CI28"; // Bitmap for rendering objects private Bitmap pageBitmap = null; // Table with counters for compression the bitmaps private Dictionary countTable; private int[] counts; #endregion Private Fields #region Private Methods /// /// Writes the string value in stream. /// /// /// private void Write(Stream stream, string value) { if (!String.IsNullOrEmpty(value)) { byte[] buf = Encoding.UTF8.GetBytes(value); stream.Write(buf, 0, buf.Length); } } /// /// Writes the string value in stream with CRLF. /// /// /// private void WriteLn(Stream stream, string value) { if (!String.IsNullOrEmpty(value)) { byte[] buf = Encoding.UTF8.GetBytes(value); stream.Write(buf, 0, buf.Length); stream.WriteByte(13); stream.WriteByte(10); } } /// /// Gets the left position in zpl units. /// /// /// private int GetLeft(float left) { return (int)Math.Round(left * zplScaleArray[scaleIndex].PageScale + leftMargin); } /// /// Gets the top position in zpl units. /// /// /// private int GetTop(float top) { return (int)Math.Round(top * zplScaleArray[scaleIndex].PageScale + topMargin); } private int GetWidth(float width, float height, int angle) { if (angle == 90 || angle == 270) return (int)Math.Round(height * zplScaleArray[scaleIndex].PageScale); else return (int)Math.Round(width * zplScaleArray[scaleIndex].PageScale); } private int GetHeight(float width, float height, int angle) { if (angle == 90 || angle == 270) return (int)Math.Round(width * zplScaleArray[scaleIndex].PageScale); else return (int)Math.Round(height * zplScaleArray[scaleIndex].PageScale); } private string GetBarcodeZoom(float zoom, BarcodeBase b) { return (Math.Round(zoom * barcodeScale) * (b is BarcodePDF417 ? 2 : 1)).ToString(); } private string GetZPLText(string source) { source = source.Replace("\\", "\\\\").Replace("\r\n", "\\&").Replace("$", "\\$"); return source; } private string GetOrientation(int angle) { if (angle == 90) return "^FWR"; else if (angle == 180) return "^FWI"; else if (angle == 270) return "^FWB"; else return "^FWN"; } /// /// Exports the TableObject. /// /// private void ExportTableObject(TableBase table) { if (table.ColumnCount > 0 && table.RowCount > 0) { StringBuilder tableBorder = new StringBuilder(64); using (TextObject tableback = new TextObject()) { tableback.Border = table.Border; tableback.Fill = table.Fill; tableback.FillColor = table.FillColor; tableback.Left = table.AbsLeft; tableback.Top = table.AbsTop; float tableWidth = 0; float tableHeight = 0; for (int i = 0; i < table.ColumnCount; i++) tableWidth += table[i, 0].Width; for (int i = 0; i < table.RowCount; i++) tableHeight += table.Rows[i].Height; tableback.Width = (tableWidth < table.Width) ? tableWidth : table.Width; tableback.Height = tableHeight; ExportTextObject(tableback); } AddTable(table); } } private void AddTable(TableBase table) { float y = 0; for (int i = 0; i < table.RowCount; i++) { float x = 0; for (int j = 0; j < table.ColumnCount; j++) { if (!table.IsInsideSpan(table[j, i])) { TableCell textcell = table[j, i]; textcell.Left = x; textcell.Top = y; if (textcell is TextObject) ExportTextObject(textcell as TextObject); else ExportPictureObject(textcell as ReportComponentBase); } x += (table.Columns[j]).Width; } y += (table.Rows[i]).Height; } } // Copied from TIFF export with some changes private Bitmap ConvertToBitonal(Bitmap original) { Bitmap source = null; if (original.PixelFormat != PixelFormat.Format32bppArgb) { source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb); source.SetResolution(original.HorizontalResolution, original.VerticalResolution); using (Graphics g = Graphics.FromImage(source)) g.DrawImageUnscaled(original, 0, 0); } else source = original; BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); int imageSize = sourceData.Stride * sourceData.Height; byte[] sourceBuffer = new byte[imageSize]; Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize); source.UnlockBits(sourceData); Bitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed); BitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed); imageSize = destinationData.Stride * destinationData.Height; byte[] destinationBuffer = new byte[imageSize]; int sourceIndex = 0; int destinationIndex = 0; int pixelTotal = 0; byte destinationValue = 0; int pixelValue = 128; int height = source.Height; int width = source.Width; int threshold = 500; for (int y = 0; y < height; y++) { sourceIndex = y * sourceData.Stride; destinationIndex = y * destinationData.Stride; destinationValue = 0; pixelValue = 128; for (int x = 0; x < width; x++) { pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3]; if (pixelTotal > threshold) destinationValue += (byte)pixelValue; if (pixelValue == 1) { destinationBuffer[destinationIndex++] = destinationValue; destinationValue = 0; pixelValue = 128; } else pixelValue >>= 1; sourceIndex += 4; } if (pixelValue != 128) destinationBuffer[destinationIndex] = destinationValue; } Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize); destination.UnlockBits(destinationData); if (source != original) source.Dispose(); return destination; } private void ExportPictureObject(ReportComponentBase pic) { WriteLn(Stream, SetPosition(GetLeft(pic.AbsLeft), GetTop(pic.AbsTop))); Border existingBorder = pic.Border.Clone(); pic.Border.Lines = BorderLines.None; WriteLn(Stream, DrawPictureObject(pic)); pic.Border = existingBorder; DrawBorders(pic.Border, pic.AbsLeft, pic.AbsTop, pic.Width, pic.Height); } private string DrawPictureObject(ReportComponentBase pic) { string result = String.Empty; if (pic.Width > 0 && pic.Height > 0) { float zoom = zplScaleArray[scaleIndex].PageScale; int picWidth = (int)Math.Ceiling(pic.Width * zoom); int picHeight = (int)Math.Ceiling(pic.Height * zoom); using (Bitmap image = new Bitmap(picWidth, picHeight, PixelFormat.Format32bppArgb)) { DrawObjectOnBitmap(image, pic, false); result = DrawBWPicture(image); } } return result; } private void DrawObjectOnBitmap(Bitmap image, ReportComponentBase pic, bool usePosition) { using (Graphics g = Graphics.FromImage(image)) { using (GraphicCache cache = new GraphicCache()) { if (!usePosition) g.Clear(Color.White); float Left = pic.Width >= 0 ? pic.AbsLeft : pic.AbsLeft + pic.Width; float Top = pic.Height >= 0 ? pic.AbsTop : pic.AbsTop + pic.Height; float zoom = zplScaleArray[scaleIndex].PageScale; if (!usePosition) g.TranslateTransform(-Left * zoom, -Top * zoom); pic.Draw(new FRPaintEventArgs(g, zoom, zoom, cache)); } } } private string DrawBWPicture(Bitmap image) { string result = String.Empty; // Convert to BW using (Bitmap bwImage = ConvertToBitonal(image)) // Save in ZPL { result = CompressBWImage(bwImage); } return result; } private string CompressBWImage(Bitmap image) { BitmapData imgData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed); int imageBitsSize = imgData.Stride * imgData.Height; byte[] picBytes = new byte[imageBitsSize]; Marshal.Copy(imgData.Scan0, picBytes, 0, imageBitsSize); image.UnlockBits(imgData); int widthInBytes = (int)Math.Ceiling(image.Width / 8f); int imageSize = widthInBytes * image.Height; int freeBits = 8 - image.Width % 8; byte lastByteMask = (byte)((1 << freeBits) - 1); StringBuilder zplImage = new StringBuilder(imageSize * 2); zplImage.AppendFormat("^GFA,{0},{1},{2},", imageSize.ToString(), imageSize.ToString(), widthInBytes.ToString()); StringBuilder previousLine = new StringBuilder(); for (int i = 0; i < image.Height; i++) { StringBuilder line = new StringBuilder(widthInBytes * 2); StringBuilder computedLine = new StringBuilder(widthInBytes); bool lastZeros = true; for (int j = 0; j < widthInBytes; j++) { byte b = (byte)~(picBytes[i * imgData.Stride + j]); if (j == widthInBytes - 1) { b = (byte)(b & ~lastByteMask); } if (b != 0) { lastZeros = false; computedLine.Append(line); line.Length = 0; } else { if (!lastZeros) { computedLine.Append(line); line.Length = 0; } lastZeros = true; } line.Append(b.ToString("X2")); } if (lastZeros) computedLine.Append(","); else computedLine.Append(line); if (previousLine.Equals(computedLine)) zplImage.Append(":"); else { zplImage.Append(CompressLine(computedLine)); previousLine = computedLine; } } zplImage.Append("^FS"); return zplImage.ToString(); } private StringBuilder CompressLine(StringBuilder line) { StringBuilder result = new StringBuilder(); char previousChar = '-'; // different initial char int counter = 0; for (int i = 0; i < line.Length; i++) { char currentChar = line[i]; // this line for better understanding if (currentChar == previousChar) // char is repeating { if (counter == 0) // char is not counted { result.Length = result.Length - 1; // remove last char and keep count counter += 2; // add previous and current } else counter++; // keep count } else { if (counter > 0) // current char is different and we have repeated before { result. // append to result Append(GetCount(counter)). // count Append(previousChar). // compressed char Append(currentChar); // current char counter = 0; // reset counter } else result.Append(currentChar); // just add current char to result previousChar = currentChar; // save current char as previous } } if (counter > 0) { result.Append(GetCount(counter)).Append(previousChar); } return result; } private StringBuilder GetCount(int counter) { StringBuilder sb = new StringBuilder(); int remainder = counter; int index = counts.Length - 1; while (remainder > 0 && index >= 0) { if (counts[index] <= remainder) { sb.Append(countTable[counts[index]]); remainder -= counts[index]; } index--; } return sb; } /// /// Exports the LineObject. /// /// private void ExportLineObject(LineObject lineObject) { if (lineObject.Width == 0 || lineObject.Height == 0) ExportRectangle(lineObject.AbsLeft, lineObject.AbsTop, lineObject.Width, lineObject.Height, lineObject.Border.Width); else ExportLine(lineObject.AbsLeft, lineObject.AbsTop, lineObject.Width, lineObject.Height, lineObject.Border.Width); } /// /// Exports the ShapeObject. /// /// private void ExportShapeObject(ShapeObject shapeObject) { if (shapeObject.Shape == ShapeKind.Ellipse) //-V3024 ExportEllipse(shapeObject.AbsLeft, shapeObject.AbsTop, shapeObject.Width, shapeObject.Height, shapeObject.Border.Width); else ExportRectangle(shapeObject.AbsLeft, shapeObject.AbsTop, shapeObject.Width, shapeObject.Height, shapeObject.Border.Width); } private void ExportRectangle(float Left, float Top, float Width, float Height, float LineWidth) { int left = Width > 0 ? GetLeft(Left) : GetLeft(Left + Width); int top = Height > 0 ? GetLeft(Top) : GetTop(Top + Height); int width = (int)Math.Abs(Math.Round(Width * zplScaleArray[scaleIndex].PageScale)); int height = (int)Math.Abs(Math.Round(Height * zplScaleArray[scaleIndex].PageScale)); int lineWidth = (int)Math.Round(LineWidth * zplScaleArray[scaleIndex].PageScale); WriteLn(Stream, SetPosition(left, top)); WriteLn(Stream, DrawRectangle(width, height, lineWidth)); } private void ExportEllipse(float Left, float Top, float Width, float Height, float LineWidth) { int left = Width > 0 ? GetLeft(Left) : GetLeft(Left + Width); int top = Height > 0 ? GetLeft(Top) : GetTop(Top + Height); int width = (int)Math.Abs(Math.Round(Width * zplScaleArray[scaleIndex].PageScale)); int height = (int)Math.Abs(Math.Round(Height * zplScaleArray[scaleIndex].PageScale)); int lineWidth = (int)Math.Round(LineWidth * zplScaleArray[scaleIndex].PageScale); WriteLn(Stream, SetPosition(left, top)); WriteLn(Stream, DrawEllipse(width, height, lineWidth)); } private void ExportLine(float Left, float Top, float Width, float Height, float LineWidth) { int left = Width > 0 ? GetLeft(Left) : GetLeft(Left + Width); int top = Height > 0 ? GetLeft(Top) : GetTop(Top + Height); int width = (int)Math.Abs(Math.Round(Width * zplScaleArray[scaleIndex].PageScale)); int height = (int)Math.Abs(Math.Round(Height * zplScaleArray[scaleIndex].PageScale)); bool direction = (Width > 0 && Height > 0) || (Width < 0 && Height < 0); int lineWidth = (int)Math.Round(LineWidth * zplScaleArray[scaleIndex].PageScale); WriteLn(Stream, SetPosition(left, top)); WriteLn(Stream, DrawLine(width, height, lineWidth, direction)); } /// /// Exports the TextObject. /// /// private void ExportTextObject(TextObject textObject) { // calc the width of object int width = GetWidth(textObject.Width, textObject.Height, textObject.Angle); // calc lines count // to-do: need fix with AdvancedTextRenderer int lines = (int)Math.Round(textObject.Height / Math.Round(textObject.Font.Height * DrawUtils.ScreenDpiFX)); // calc line height int lineHeight = (int)Math.Round(textObject.Font.Height * zplScaleArray[scaleIndex].PageScale); // calc font height int fontHeight = (int)Math.Round(Math.Round(textObject.Font.Height * DrawUtils.ScreenDpiFX) * zplScaleArray[scaleIndex].PageScale / fontScale); // calc font width int fontWidth = (int)Math.Round((float)fontHeight / 2); // calc top position of text int top; if (textObject.VertAlign == VertAlign.Top) top = GetTop(textObject.AbsTop); else if (textObject.VertAlign == VertAlign.Bottom) top = GetTop(textObject.AbsTop) + GetHeight(textObject.Width, textObject.Height, textObject.Angle) - fontHeight * lines; else top = GetTop(textObject.AbsTop) + (int)(GetHeight(textObject.Width, textObject.Height, textObject.Angle) / 2) - (int)Math.Round((float)(fontHeight * lines) / 2); // set-up position //TO DO: for TextObject you need to redo the formula //The text moves to the left by 10 points because of this I put +10 WriteLn(Stream, SetPosition(GetLeft(textObject.AbsLeft) + 10, top)); // set-up the text attribs WriteLn(Stream, SetTextAttributes(width, lines, 0, textObject.HorzAlign, 0)); WriteLn(Stream, GetOrientation(textObject.Angle)); // draw text WriteLn(Stream, DrawText(fontHeight, fontWidth, textObject.Text)); // draw borders DrawBorders(textObject.Border, textObject.AbsLeft, textObject.AbsTop, textObject.Width, textObject.Height); } private void DrawBorders(Border border, float AbsLeft, float AbsTop, float Width, float Height) { if (border.Width > 0) { if (border.Lines == BorderLines.All) ExportRectangle(AbsLeft, AbsTop, Width, Height, border.Width); else { int left = Width > 0 ? GetLeft(AbsLeft) : GetLeft(AbsLeft + Width); int top = Height > 0 ? GetLeft(AbsTop) : GetTop(AbsTop + Height); int width = (int)Math.Abs(Math.Round(Width * zplScaleArray[scaleIndex].PageScale)); int height = (int)Math.Abs(Math.Round(Height * zplScaleArray[scaleIndex].PageScale)); int lineWidth = (int)Math.Round(border.Width * zplScaleArray[scaleIndex].PageScale); if ((BorderLines.Top & border.Lines) != 0) { lineWidth = (int)Math.Round(border.TopLine.Width * zplScaleArray[scaleIndex].PageScale); WriteLn(Stream, SetPosition(left, top)); WriteLn(Stream, DrawRectangle(width, 0, lineWidth)); } if ((BorderLines.Left & border.Lines) != 0) { lineWidth = (int)Math.Round(border.LeftLine.Width * zplScaleArray[scaleIndex].PageScale); WriteLn(Stream, SetPosition(left, top)); WriteLn(Stream, DrawRectangle(0, height, lineWidth)); } if ((BorderLines.Bottom & border.Lines) != 0) { lineWidth = (int)Math.Round(border.BottomLine.Width * zplScaleArray[scaleIndex].PageScale); WriteLn(Stream, SetPosition(left, top + height)); WriteLn(Stream, DrawRectangle(width, 0, lineWidth)); } if ((BorderLines.Right & border.Lines) != 0) { lineWidth = (int)Math.Round(border.RightLine.Width * zplScaleArray[scaleIndex].PageScale); WriteLn(Stream, SetPosition(left + width, top)); WriteLn(Stream, DrawRectangle(0, height, lineWidth)); } } } } private void ExportBarcodeObject(BarcodeObject b) { int height = GetHeight(b.Width, b.Height, b.Angle); WriteLn(Stream, SetPosition(GetLeft(b.AbsLeft), GetTop(b.AbsTop))); if (!(b.Barcode is BarcodeQR)) { WriteLn(Stream, "^BY" + GetBarcodeZoom(b.Zoom, b.Barcode) + ",," + height.ToString()); WriteLn(Stream, GetOrientation(b.Angle)); char printLine = (b.ShowText ? 'Y' : 'N'); //TO DO: It makes sense for some barcodes to set the height if (b.Barcode is Barcode128 || b.Barcode is BarcodeEAN128) WriteLn(Stream, String.Format("^BC,,{0},N,N", printLine)); else if (b.Barcode is Barcode2of5Industrial) WriteLn(Stream, String.Format("^BI,,{0},N", printLine)); else if (b.Barcode is Barcode2of5Interleaved) WriteLn(Stream, String.Format("^B2,,{0},N,N", printLine)); else if (b.Barcode is Barcode2of5Matrix) WriteLn(Stream, String.Format("^BJ,,{0},N", printLine)); else if (b.Barcode is Barcode39Extended) WriteLn(Stream, String.Format("^B3,Y,,{0},N", printLine)); else if (b.Barcode is Barcode39) WriteLn(Stream, String.Format("^B3,N,,{0},N", printLine)); else if (b.Barcode is Barcode93Extended) WriteLn(Stream, String.Format("^BA,,{0},N,N", printLine)); else if (b.Barcode is Barcode93) WriteLn(Stream, String.Format("^BA,,{0},N,N", printLine)); else if (b.Barcode is BarcodeCodabar) WriteLn(Stream, String.Format("^BK,N,{0},N,,", printLine)); else if (b.Barcode is BarcodeUPC_A) WriteLn(Stream, String.Format("^BU,,{0},N,Y", printLine)); else if (b.Barcode is BarcodeUPC_E0) WriteLn(Stream, String.Format("^B9,,{0},N,Y", printLine)); else if (b.Barcode is BarcodeUPC_E1) WriteLn(Stream, String.Format("^B9,,{0},N,Y", printLine)); else if (b.Barcode is BarcodeEAN8) WriteLn(Stream, String.Format("^B8,,{0},N", printLine)); else if (b.Barcode is BarcodeEAN13) WriteLn(Stream, String.Format("^BE,,{0},N", printLine)); else if (b.Barcode is BarcodeIntelligentMail) WriteLn(Stream, String.Format("^BZ,,{0},N,3", printLine)); else if (b.Barcode is BarcodeMSI) WriteLn(Stream, String.Format("^BM,,,{0},N,N", printLine)); else if (b.Barcode is BarcodePDF417) WriteLn(Stream, "^B7,,,,,"); else if (b.Barcode is BarcodePlessey) WriteLn(Stream, String.Format("^BP,,{0},N", printLine)); else if (b.Barcode is BarcodePostNet) WriteLn(Stream, String.Format("^BZ,,{0},N,0", printLine)); else if (b.Barcode is BarcodeAztec) WriteLn(Stream, String.Format("^BO,{0},,,,,", zplScaleArray[scaleIndex].TwoDCodeScale.ToString())); else if (b.Barcode is BarcodeDatamatrix) WriteLn(Stream, "^BX,,,,,,"); else if (b.Barcode is BarcodeMaxiCode) { BarcodeMaxiCode maxiCode = b.Barcode as BarcodeMaxiCode; WriteLn(Stream, String.Format("^BD{0},,", maxiCode.Mode.ToString())); } WriteLn(Stream, "^FD" + GetZPLText(b.Text) + "^FS"); // to-do BarcodeSupplement2, BarcodeSupplement5, BarcodePharmacode - didn't match } else // QR code { WriteLn(Stream, "^BY2,2,0"); WriteLn(Stream, String.Format("^BQ,2,{0}", Math.Round((float)zplScaleArray[scaleIndex].TwoDCodeScale * b.Zoom).ToString())); WriteLn(Stream, "^FDMA," + GetZPLText(b.Text) + "^FS"); } } /// /// Gets the position of object in ZPL code. /// /// /// /// private string SetPosition(int left, int top) { return String.Format("^FO{0},{1}", left, top); } /// /// Gets the text attributes in ZPL code. /// /// /// /// /// /// /// private string SetTextAttributes(int width, int lines, int leading, HorzAlign horizAlign, int gap) { return String.Format("^FB{0},{1},{2},{3},{4}", width, lines, leading, GetHorizAlign(horizAlign), gap ); } /// /// Gets the text with font width and height in ZPL code. /// /// /// /// /// private string DrawText(int fontHeight, int fontWidth, string text) { return String.Format("^A{0},{1},{2}^FD{3}^FS", font, fontHeight, fontWidth, GetZPLText(text) ); } /// /// Gets the horiz align in ZPL code. /// /// /// private string GetHorizAlign(HorzAlign horizAlign) { switch (horizAlign) { case HorzAlign.Left: return "L"; case HorzAlign.Center: return "C"; case HorzAlign.Right: return "R"; default: return "J"; } } /// /// Gets the rectangle in ZPL code. /// /// /// /// /// private string DrawRectangle(int width, int height, int lineWidth) { return String.Format((version == ZplVersions.ZPL2 ? "^LRN" : "") + "^GB{0},{1},{2}^FS", width, height, lineWidth); } private string DrawEllipse(int width, int height, int lineWidth) { return String.Format("^GE{0},{1},{2}^FS", width, height, lineWidth); } private string DrawLine(int width, int height, int lineWidth, bool direction) { return String.Format("^GD{0},{1},{2},,{3}^FS", width.ToString(), height.ToString(), lineWidth.ToString(), direction ? "L" : "R"); } #endregion Private Methods #region Protected Methods /// protected override void Start() { base.Start(); // Init of scale index. switch (density) { case ZplDensity.d6_dpmm_152_dpi: scaleIndex = 0; break; case ZplDensity.d8_dpmm_203_dpi: scaleIndex = 1; break; case ZplDensity.d12_dpmm_300_dpi: scaleIndex = 2; break; case ZplDensity.d24_dpmm_600_dpi: scaleIndex = 3; break; } WriteLn(Stream, printerInit); } /// protected override void Finish() { WriteLn(Stream, printerFinish); } /// protected override string GetFileFilter() { return new MyRes("FileFilters").Get("ZplFile"); } /// protected override void ExportPageBegin(ReportPage page) { base.ExportPageBegin(page); WriteLn(Stream, String.Format("^XA{0}", codePage)); WriteLn(Stream, pageInit); leftMargin = page.LeftMargin * millimeters * zplScaleArray[scaleIndex].PageScale; topMargin = page.TopMargin * millimeters * zplScaleArray[scaleIndex].PageScale; if (printAsBitmap) { pageBitmap = new Bitmap( (int)Math.Round(ExportUtils.GetPageWidth(page) * millimeters * zplScaleArray[scaleIndex].PageScale), (int)Math.Round(ExportUtils.GetPageHeight(page) * millimeters * zplScaleArray[scaleIndex].PageScale), PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(pageBitmap)) g.Clear(Color.White); } } /// protected override void ExportPageEnd(ReportPage page) { if (printAsBitmap) { WriteLn(Stream, SetPosition((int)leftMargin, (int)topMargin)); WriteLn(Stream, DrawBWPicture(pageBitmap)); pageBitmap.Dispose(); } base.ExportPageEnd(page); WriteLn(Stream, "^XZ"); } /// protected override void ExportBand(BandBase band) { base.ExportBand(band); if (band.Parent == null) return; if (printAsBitmap) DrawObjectOnBitmap(pageBitmap, band, true); foreach (Base c in band.ForEachAllConvectedObjects(this)) { if (c is ReportComponentBase && (c as ReportComponentBase).Exportable) { ReportComponentBase bandObject = c as ReportComponentBase; if (printAsBitmap) DrawObjectOnBitmap(pageBitmap, bandObject, true); else { if (bandObject is CellularTextObject) bandObject = (bandObject as CellularTextObject).GetTable(); if (bandObject is TableCell) continue; else if (bandObject is TableBase) ExportTableObject(bandObject as TableBase); else if (bandObject is TextObject) ExportTextObject(bandObject as TextObject); else if (bandObject is ShapeObject) ExportShapeObject(bandObject as ShapeObject); else if (bandObject is LineObject) ExportLineObject(bandObject as LineObject); else if (bandObject is RFIDLabel) ExportRFIDLabel(bandObject as RFIDLabel); else if (bandObject is BarcodeObject) ExportBarcodeObject(bandObject as BarcodeObject); else ExportPictureObject(bandObject); } } } } private void ExportRFIDLabel(RFIDLabel rfidLabel) { //data if (!string.IsNullOrEmpty(rfidLabel.EpcBank.Data)) { //RF parametrs // 1. R - read, W - write, S - password // 2. Format H - Hex, A - ASCII, E - EPC // 3. start block in bank // 4. number of bytes to read or write // 5. index of bank. 0 - Reserved(passwords), 1 - EPC, 2 - TID, 3 - User, E - EPC 20th bit, A - EPC 20th bit with auto adjust bits if (!string.IsNullOrEmpty(rfidLabel.EpcFormat)) { WriteLn(Stream, $"^RB{rfidLabel.EpcFormat}^FS"); WriteLn(Stream, $"^RFW,E^FD{rfidLabel.EpcBank.Data}^FS"); } else if (rfidLabel.RewriteEPCbank) WriteLn(Stream, $"^RFW,{(char)rfidLabel.EpcBank.DataFormat},{rfidLabel.EpcBank.Offset},{rfidLabel.EpcBank.CountByte},1^FD{rfidLabel.EpcBank.Data}^FS");//2,,A/E else if (rfidLabel.UseAdjustForEPC) WriteLn(Stream, $"^RFW,{(char)rfidLabel.EpcBank.DataFormat},2,,E^FD{rfidLabel.EpcBank.Data}^FS"); else WriteLn(Stream, $"^RFW,{(char)rfidLabel.EpcBank.DataFormat},2,,A^FD{rfidLabel.EpcBank.Data}^FS"); } if (!string.IsNullOrEmpty(rfidLabel.TIDBank.Data)) { WriteLn(Stream, $"^RFW,{(char)rfidLabel.TIDBank.DataFormat},{rfidLabel.TIDBank.Offset},{rfidLabel.TIDBank.CountByte},2^FD{rfidLabel.TIDBank.Data}^FS"); } if (!string.IsNullOrEmpty(rfidLabel.UserBank.Data)) { WriteLn(Stream, $"^RFW,{(char)rfidLabel.UserBank.DataFormat},{rfidLabel.UserBank.CountByte},{rfidLabel.UserBank.CountByte},3^FD{rfidLabel.UserBank.Data}^FS"); } if (!string.IsNullOrEmpty(rfidLabel.AccessPassword) && rfidLabel.AccessPassword != "00000000" || !string.IsNullOrEmpty(rfidLabel.KillPassword) && rfidLabel.KillPassword != "00000000") { WriteLn(Stream, $"^RFW,H,P^FD{rfidLabel.AccessPassword}{(string.IsNullOrEmpty(rfidLabel.KillPassword) ? "" : $",{rfidLabel.KillPassword}")}^FS"); } if (!string.IsNullOrEmpty(rfidLabel.AccessPassword) && rfidLabel.AccessPassword != "00000000") WriteLn(Stream, $"^RLM,{(char)rfidLabel.LockKillPassword},{(char)rfidLabel.LockAccessPassword},{(char)rfidLabel.LockEPCBank},{(char)rfidLabel.LockUserBank}"); if (rfidLabel.CountPermaLock > 0) WriteLn(Stream, $"^RLB{rfidLabel.StartPermaLock},{rfidLabel.CountPermaLock}"); WriteLn(Stream, $"^RS,,,,{rfidLabel.ErrorHandle}"); if (rfidLabel.AdaptiveAntenna) WriteLn(Stream, "^RR,1"); if (rfidLabel.ReadPower != 16 || rfidLabel.WritePower != 16) { WriteLn(Stream, $"^RW{rfidLabel.ReadPower},{rfidLabel.WritePower}^FS"); } if (printAsBitmap) DrawObjectOnBitmap(pageBitmap, rfidLabel, true); foreach (Base c in rfidLabel.ForEachAllConvectedObjects(this)) { if (c is ReportComponentBase && (c as ReportComponentBase).Exportable) { ReportComponentBase bandObject = c as ReportComponentBase; if (printAsBitmap) DrawObjectOnBitmap(pageBitmap, bandObject, true); else { if (bandObject is CellularTextObject) bandObject = (bandObject as CellularTextObject).GetTable(); if (bandObject is TableCell) continue; else if (bandObject is TableBase) ExportTableObject(bandObject as TableBase); else if (bandObject is TextObject) ExportTextObject(bandObject as TextObject); else if (bandObject is ShapeObject) ExportShapeObject(bandObject as ShapeObject); else if (bandObject is LineObject) ExportLineObject(bandObject as LineObject); else if (bandObject is RFIDLabel) ExportRFIDLabel(bandObject as RFIDLabel); else if (bandObject is BarcodeObject) ExportBarcodeObject(bandObject as BarcodeObject); else ExportPictureObject(bandObject); } } } } #endregion Protected Methods #region Public Methods /// public override void Serialize(FRWriter writer) { base.Serialize(writer); // Options writer.WriteValue("Density", Density); writer.WriteValue("Version", Version); writer.WriteBool("PrintAsBitmap", PrintAsBitmap); writer.WriteValue("FontScale", FontScale); writer.WriteValue("BarcodeScale", BarcodeScale); // end } #endregion Public Methods /// /// Initializes a new instance of the class. /// public ZplExport() { countTable = new Dictionary(); countTable.Add(1, 'G'); countTable.Add(2, 'H'); countTable.Add(3, 'I'); countTable.Add(4, 'J'); countTable.Add(5, 'K'); countTable.Add(6, 'L'); countTable.Add(7, 'M'); countTable.Add(8, 'N'); countTable.Add(9, 'O'); countTable.Add(10, 'P'); countTable.Add(11, 'Q'); countTable.Add(12, 'R'); countTable.Add(13, 'S'); countTable.Add(14, 'T'); countTable.Add(15, 'U'); countTable.Add(16, 'V'); countTable.Add(17, 'W'); countTable.Add(18, 'X'); countTable.Add(19, 'Y'); countTable.Add(20, 'g'); countTable.Add(40, 'h'); countTable.Add(60, 'i'); countTable.Add(80, 'j'); countTable.Add(100, 'k'); countTable.Add(120, 'l'); countTable.Add(140, 'm'); countTable.Add(160, 'n'); countTable.Add(180, 'o'); countTable.Add(200, 'p'); countTable.Add(220, 'q'); countTable.Add(240, 'r'); countTable.Add(260, 's'); countTable.Add(280, 't'); countTable.Add(300, 'u'); countTable.Add(320, 'v'); countTable.Add(340, 'w'); countTable.Add(360, 'x'); countTable.Add(380, 'y'); countTable.Add(400, 'z'); // prepare for indexed access to keys counts = new int[countTable.Count]; countTable.Keys.CopyTo(counts, 0); } } }