将栅格字节[]图像数据转换为C#中的列格式 [英] Convert raster byte[] image data to column Format in C#
问题描述
我正在尝试将字节数组从Raster
格式的图像(从左到右读取)转换为Column
格式(从上到下读取).
I'm trying to convert a byte array from an image that is in Raster
format, which reads from left to right, to Column
format, which reads from top to bottom.
问题看起来很简单,我们有一个二维的位数组(图像的宽度/高度).在Raster
格式中,您从左到右读取位,在Column
格式中,您从上到下读取位.
The problem looks simple, we have two-dimensional array of bits (width/height of image). In Raster
format, you read the bits from left to right, in Column
format you read the bits from top to bottom.
我尝试这样做以支持ESC/POS
协议的Column
格式打印.我已经有Raster
格式的图片,现在我正尝试将其转换为Column
格式.
I try to do this to support Column
format printing of the ESC/POS
protocol. I already have the image in Raster
format, now I'm trying to convert it to Column
format.
ESC/POS
打印Raster
的文档:
ESC/POS
文档:
- https://reference.epson-biz .com/modules/ref_escpos/index.php?content_id = 106#gs_lparen_cl_fn68
- https://reference.epson-biz.com /modules/ref_escpos/index.php?content_id=90
- https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=106#gs_lparen_cl_fn68
- https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=90
目前,我通过直接用BitArray
处理位进行转换.此解决方案不是最佳解决方案,我认为有必要直接在Byte
中工作.
For the moment, I make the conversion by working on the bits directly with BitArray
. This solution is not optimal, it would be necessary to work directly in Byte
in my opinion.
private byte[] ConvertRasterToColumnFormat(byte[] rasterData, int width, int height)
{
var finalHeight = height;
while (finalHeight % 8 != 0) finalHeight++;
var finalWidth = width;
while (finalWidth % 8 != 0) finalWidth++;
var rasterBitArray = new BitArray(rasterData);
var columnBitArray = new BitArray(finalHeight * finalWidth);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
var rasterPosition = y * finalWidth;
var columnPosition = x * finalHeight;
rasterPosition += (x / 8) * 8;
columnPosition += (y / 8) * 8;
rasterPosition += 7 - x % 8;
columnPosition += 7 - y % 8;
var value = rasterBitArray[rasterPosition];
columnBitArray[columnPosition] = value;
}
}
var result = new byte[columnBitArray.Length / 8];
columnBitArray.CopyTo(result, 0);
return result;
}
.NET Fiddle与测试: https://dotnetfiddle.net/NBRBgt
.NET Fiddle with Tests: https://dotnetfiddle.net/NBRBgt
有人有更好的解决方案吗?
Does anyone have a more optimal solution?
推荐答案
A possible approach could be to grab a 8x8 block of bits, transpose it using bitboard techniques, and then store the bytes of the result. It's not very pretty, but it avoids ever dealing with individual bits, and of course avoids BitArray
(which is slow even among bit-by-bit approaches).
以下代码通过了您的测试用例,但可能应该对其进行更好的测试.
The following code passes your test cases, but probably should be tested better..
private static byte[] ConvertRasterToColumnFormat(byte[] rasterData, int width, int height)
{
int h = height + 7 & -8;
int w = (width + 7) >> 3;
int hsmall = h >> 3;
var result = new byte[h * w];
for (int y = 0; y < height; y += 8)
{
for (int x = 0; x < w; x++)
{
// grab 8x8 block of bits
int i = x + w * y;
ulong block = rasterData[i];
if (i + w < rasterData.Length)
block |= (ulong)rasterData[i + w] << 8;
if (i + w * 2 < rasterData.Length)
block |= (ulong)rasterData[i + w * 2] << 16;
if (i + w * 3 < rasterData.Length)
block |= (ulong)rasterData[i + w * 3] << 24;
if (i + w * 4 < rasterData.Length)
block |= (ulong)rasterData[i + w * 4] << 32;
if (i + w * 5 < rasterData.Length)
block |= (ulong)rasterData[i + w * 5] << 40;
if (i + w * 6 < rasterData.Length)
block |= (ulong)rasterData[i + w * 6] << 48;
if (i + w * 7 < rasterData.Length)
block |= (ulong)rasterData[i + w * 7] << 56;
// transpose 8x8
// https://www.chessprogramming.org/Flipping_Mirroring_and_Rotating#Anti-Diagonal
ulong t;
const ulong k1 = 0xaa00aa00aa00aa00;
const ulong k2 = 0xcccc0000cccc0000;
const ulong k4 = 0xf0f0f0f00f0f0f0f;
t = block ^ (block << 36);
block ^= k4 & (t ^ (block >> 36));
t = k2 & (block ^ (block << 18));
block ^= t ^ (t >> 18);
t = k1 & (block ^ (block << 9));
block ^= t ^ (t >> 9);
// write block to columns
int j = (y >> 3) + h * x;
result[j] = (byte)block;
result[j + hsmall] = (byte)(block >> 8);
result[j + hsmall * 2] = (byte)(block >> 16);
result[j + hsmall * 3] = (byte)(block >> 24);
result[j + hsmall * 4] = (byte)(block >> 32);
result[j + hsmall * 5] = (byte)(block >> 40);
result[j + hsmall * 6] = (byte)(block >> 48);
result[j + hsmall * 7] = (byte)(block >> 56);
}
}
return result;
}
在256x256阵列上使用我的设置(英特尔4770K,x64,.NET Core 3.0)的简单基准测试得出:
A simple benchmark with my setup (Intel 4770K, x64, .NET Core 3.0) on a 256x256 array gave:
old: 1103 ticks
new: 56 ticks
非常明显的区别.
这篇关于将栅格字节[]图像数据转换为C#中的列格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!