Расшифровка строки Z64 (ZB64)
Я работаю над разбивкой определений этикеток ZPL, созданных программным обеспечением для создания этикеток NiceLabel. По большей части мне не нужно беспокоиться о декодировании Z64, потому что это просто закодированная графика, и мне не нужно изменять базовые данные.
Однако у меня есть строка текста, которая по какой-то причине используется как изображение на этикетке, вероятно, из-за шрифта или чего-то еще.
В любом случае, строка Z64 или ZB64 создается путем сжатия исходных данных с использованием LZ77 и кодирования их как Base64 с последующим добавлением CRC в конце.
ПОЛНЫЙ ПРИМЕР ТЕСТОВОЙ СТРОКИ:
:Z64:eJztkDFOxDAQRb81hRsULmBtruECyRwpZYpFGLmg5AhwFKMUuYal9CtL26QwHsbe3RMguv3lz9P85wD3/CWaiZ+56OjqWA44cwKIAyfeXXL1sQ7YWqd54czltTge+VOdOQsXFp8TrLUw9KEW3+6pLU4Zk3mC0ataonSEzU8JMywGCiFcue+c8YLGvYcLF5a+68WFhbvtRs5jdmVkWolj96vgXe/it7eucT+0+gxV5N5RrdTveQpevhnxO+BEfRe0xIzc/EbUzkn3lhLSIH6DdFeu+c39Hb7c7vksfrJryB8vu6A4cxE/NjpK1/6LkJZ3+nL1gaLt3D33/Ed+AehfkrY=:6C38
ПРИМЕР ЗАДАЧИ ТЕСТА:
eJztkDFOxDAQRb81hRsULmBtruECyRwpZYpFGLmg5AhwFKMUuYal9CtL26QwHsbe3RMguv3lz9P85wD3/CWaiZ+56OjqWA44cwKIAyfeXXL1sQ7YWqd54czltTge+VOdOQsXFp8TrLUw9KEW3+6pLU4Zk3mC0ataonSEzU8JMywGCiFcue+c8YLGvYcLF5a+68WFhbvtRs5jdmVkWolj96vgXe/it7eucT+0+gxV5N5RrdTveQpevhnxO+BEfRe0xIzc/EbUzkn3lhLSIH6DdFeu+c39Hb7c7vksfrJryB8vu6A4cxE/NjpK1/6LkJZ3+nL1gaLt3D33/Ed+AehfkrY=
Мой код для декодирования / распаковки:
static string DecompressZb64(string compressedString)
{
var b64 = SmartWarehouse.Shared.Utils.Parser.ConvertFromBase64(compressedString);
var encoding = new ASCIIEncoding();
var inBytes = Encoding.ASCII.GetBytes(b64);
var outBytes = new byte[inBytes.Length];
try
{
using (var memoryStream = new MemoryStream())
using (var decompressionStream = new DeflateStream(memoryStream, CompressionMode.Decompress))
{
decompressionStream.Read(outBytes, 0, inBytes.Length);
}
return encoding.GetString(outBytes);
}
catch (Exception e)
{
// TODO: DOcument exception
Console.WriteLine(e.Message);
}
return string.Empty;
}
Текущее исключение:
Block length does not match with its complement.
Трассировки стека:
at System.IO.Compression.Inflater.DecodeUncompressedBlock(Boolean& end_of_block)
at System.IO.Compression.Inflater.Decode()
at System.IO.Compression.Inflater.Inflate(Byte[] bytes, Int32 offset, Int32 length)
at System.IO.Compression.DeflateStream.Read(Byte[] array, Int32 offset, Int32 count)
at SmartWarehouse.Tools.Program.DecompressZb64(String compressedString) in C:\Users\[user_dir]\Source\Repos\Handheld.[user].[fork]\SmartWarehouse.Tools\Program.cs:line 511
ОБНОВИТЬ:
Я изучал это и обнаружил, что это сообщение SO, по сути, та же проблема. Итак, я провел еще несколько исследований и нашел эту статью в блоге 2007 года. В нем обсуждается обходной путь путем пропуска первых 2 байтов во входном массиве из-за того, что эти байты фактически не включены в спецификацию RFC.
СМЕНА КОДА:
static string DecompressZb64(string compressedString)
{
var b64 = Convert.FromBase64String(compressedString);
var encoding = new ASCIIEncoding();
var outBytes = new byte[b64.Length - 2];
try
{
using (var memoryStream = new MemoryStream(b64))
{
memoryStream.ReadByte();
memoryStream.ReadByte();
using (var decompressionStream = new DeflateStream(memoryStream, CompressionMode.Decompress))
{
decompressionStream.Read(outBytes, 0, b64.Length - 2);
}
}
return encoding.GetString(outBytes);
}
catch (Exception e)
{
// TODO: DOcument exception
Console.WriteLine(e.Message);
}
return string.Empty;
}
Это изменение кода больше не вызывает исключения, однако оно не распаковывается должным образом и возвращает следующий результат:
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
2 ответа
Эти данные мне нравятся, я извлек из них вот такое изображение:
ht tps:https://stackru.com/images/d08814328a4323fdab2ecce00f677977fea185fd.png
Это монохромное растровое изображение, один бит на пиксель.
Ваш код не читался до конца потока, на самом деле есть 1280 байтов данных изображения, которые затем могут быть декодированы в изображение выше.
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace ZB64Decode
{
public class Program
{
static void Main(string[] args)
{
//this is C#
var sb = new StringBuilder();
sb.AppendLine("^XA");
sb.AppendLine("^UT1,1");
sb.AppendLine("^Uh0,300,64,4000,2,0,F");
sb.AppendLine("^Uh1,300,64,4000,2,0,F");
sb.AppendLine("^UC1,0,1,0,0");
sb.AppendLine("^LH0,0");
sb.AppendLine("^LT0");
sb.AppendLine("^XZ");
sb.AppendLine("^XA");
sb.AppendLine("^PW3543");
sb.AppendLine("^LL512");
sb.AppendLine("^FO532,66^GFA,885,9272,76,:Z64:eJztWkFywyAMDMOBI0/gKTyNPC1P6RN6zKFTNxiCY0AgJE0nh+zJTc0GrdYES1wu/wWzHfiVIuLR2YZpB4FJpZH38UcouP6oRHddogqPEd/9f0WyLzyTGqpsVuLUj5tvoxv8tv3gqSa3WCSZxrjIoMgUzpAGoxnW2wZMdIFHG9tOEhQtekVyze7VSzYMQ/3DVIMTRt/sFtcUA0epZ2o28GCUfi3CCOjbDWHVhMaElRyOB1nss3+C7no7rAqf4DsTM+vr+A7VUYw4rTixeqAmqdUf2bKjESrz96LGwlQWNxRvPVHNw1N+2p9wJ30UWfkIfbKT5YQY1X/5gxVinMqtXCui53vjWVmMCEcmHS/EGOT1ecnKYoQudlXra3ONIphZ3Oh14H7rCzrKdDxXrijYLV3w5Socmr50HcixCUhfNBeQvkxIQPoiVOA92AkqPdISacwsImnMSklyiVgiu8FyF6+EnUbEXjk8SS4Rq+YUviuXyCOUH6IP14er5npX37/rmiO5rkqu90K/Q5Jcux0Ud0OekCwvuZ+Q3OdI7r9EDJZJJPerkvtoiUQWY0m+d0i+Dwk4/5BJ8P2R++p+enk3XIf5I3uSdYDX93gKTnUEywvypLdmBVlVgwInk1U1iFUcqibCKVo1AjHqhc1Qanm1W2qsq5FouFZqS677diyw2r7LcL0Vnjax7rTgHsEQQC+CUsDvl+8vpMYCOGTQogEwaALBLZo+hk2gpRbYpM1llnLpx4V6fMsQ0TQM6KaAmQqisC1ijWiyahwZ7jZUVxfZIcb0m1F96x12dnzALRx9GHf8x6cFWmzwkQAPH2EA4AE26PMh0lmTagLkMye+HDG5P4+HUCbVsHGZIqqzMLPb/wCr2VTW:718B");
sb.AppendLine("^PQ1,0,1,Y^XZ");
var zpl = sb.ToString();
//extract the Z64-String
var z64Data = "";
var bytesPerRow = 0;
foreach (var item in zpl.Split('^'))
{
if (item.StartsWith("GFA"))
{
var sp= item.Split(':');
z64Data = item.Substring(sp[0].Length);
bytesPerRow = Convert.ToInt32(sp[0].Split(',')[3]);
break;
}
}
//convert String to Bitmap
Bitmap decodedBitmap = null;
if (z64Data.StartsWith(":Z64"))
{
var imageData = DecompressZb64(z64Data.Substring(5));
int width = bytesPerRow * 8;
int height = imageData.Length / bytesPerRow;
decodedBitmap = ArrayToBitmap(imageData, width, height, PixelFormat.Format1bppIndexed);
}
Debug.WriteLine(decodedBitmap.Width + ":" + decodedBitmap.Height);
}
public static Bitmap ArrayToBitmap(byte[] bytes, int width, int height, PixelFormat pixelFormat)
{
var image = new Bitmap(width, height, pixelFormat);
var imageData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadWrite, pixelFormat);
try
{
Marshal.Copy(bytes, 0, imageData.Scan0, bytes.Length);
}
finally
{
image.UnlockBits(imageData);
}
return image;
}
public static byte[] DecompressZb64(string compressedString)
{
var b64 = Convert.FromBase64String(compressedString.Split(':')[0]).Skip(2).ToArray();
return Decompress(b64);
}
public static byte[] Decompress(byte[] data)
{
byte[] decompressedArray = null;
try
{
using (MemoryStream decompressedStream = new MemoryStream())
{
using (MemoryStream compressStream = new MemoryStream(data))
{
using (DeflateStream deflateStream = new DeflateStream(compressStream, CompressionMode.Decompress))
{
deflateStream.CopyTo(decompressedStream);
}
}
decompressedArray = decompressedStream.ToArray();
}
}
catch (Exception ex)
{
// do something !
}
return decompressedArray;
}
}
}