При печати монохромного растрового изображения также печатается одна дополнительная вертикальная линия.

Я печатаю изображение растровой карты монохромного изображения на термопринтере, где я могу распечатать изображение, но в крайнем правом углу печатается одна вертикальная линия. (Линия проходит сверху справа вниз справа и имеет толщину почти 2 мм)

Bitmap image = new Bitmap(imagePath, false);
 int imageDepth = System.Drawing.Bitmap.GetPixelFormatSize(image.PixelFormat);

 Rectangle monoChromeBitmapRectangle = new Rectangle(0, 0, image.Width, image.Height);
 BitmapData monoChromebmpData = null;
 int stride = 0;

 monoChromebmpData = image.LockBits(monoChromeBitmapRectangle, ImageLockMode.ReadOnly, resizedImage.PixelFormat);
 IntPtr ptr = monoChromebmpData.Scan0;
 stride = monoChromebmpData.Stride;
 int numbytes = stride * image.Height;
 byte[] bitmapFileData = new byte[numbytes];
 Marshal.Copy(ptr, bitmapFileData, 0, numbytes);

 image.UnlockBits(monoChromebmpData);

 //Invert bitmap colors
  for (int i = 0; i < bitmapFileData.Length; i++)
  {
      bitmapFileData[i] ^= 0xFF;
  }

 StringBuilder hexaDecimalImageDataString = new StringBuilder(bitmapFileData.Length * 2);
 foreach (byte b in bitmapFileData)
    hexaDecimalImageDataString.AppendFormat("{0:X2}", b);

return hexaDecimalImageDataString;

Здесь я конвертирую монохромное растровое изображение в байтовый массив и из байтового массива в шестнадцатеричную строку. Я погуглил на форумах, но такого рода ошибки не обсуждаются. (Может быть, я делаю глупую ошибку) Кто-нибудь может подсказать, где именно я делаю ошибку.

Заранее спасибо.

Привет, Шива.


person siva Rapolu    schedule 21.08.2013    source источник


Ответы (3)


Вы возвращаете monoChromebmpData.Stride * image.Height байтов, т.е. каждая строка изображения будет иметь ширину ровно monoChromebmpData.Stride * 8 пикселей, но, вероятно, исходное изображение имеет меньшую ширину в пикселях, следовательно, дополнительная вертикальная линия справа.

Попробуйте что-то вроде этого:

byte[] masks = new byte[]{0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
int byteWidth = (image.Width+7)/8;
int nBits = imageWidth % 8;
byte[] actualBitmapFileData = new byte[byteWidth*image.Height];
int yFrom = 0;
for (int y=0; y<image.Height; y++) {
  for (int x=0; x<byteWidth-1; x++) {
    actualBitmapFileData[y*byteWidth + x] = (bitmapFileData[yFrom + x] ^ 0xFF);
  }
  int lastX = byteWidth - 1;
  actualBitmapFileData[y*byteWidth + lastX] = (bitmapFileData[yFrom + lastX] ^ 0xFF) & masks[nBits];
  yFrom += stride;
}

он создает массив actualBitmapFileData для bitmapFileData с правильным размером.

Обратите внимание, что последний байт каждой строки будет содержать только nBits пикселей, поэтому его необходимо «замаскировать», чтобы убрать лишний бит, не соответствующий ни одному пикселю. Это делается с помощью & masks[nBits], где masks - это массив из 8 байтов с 8 масками для использования. Фактические значения маски зависят от того, как работает принтер: вам может потребоваться установить дополнительные биты на 0 или 1, а дополнительные биты могут быть наиболее значимыми или наименее значимыми. Значения маски, использованные выше, предполагают, что наиболее значимые биты отображаются справа и что замаскированные биты должны быть установлены на 0. В зависимости от того, как работает принтер, может потребоваться поменять местами биты и / или установить замаскированные биты на 1 вместо нуля (дополнение маски и использование | вместо &)

person MiMo    schedule 21.08.2013
comment
Спасибо за ответ, насколько я понимаю, в каждую строку я вставляю дополнительные данные, которые вызывают эту вертикальную линию. Есть ли способ узнать значение маски (MSV / LSV), поскольку я не знаю, как получить :-(. Или есть способ прочитать данные растрового изображения построчно и удалить последний байт, что-то вроде этого ? подойдет ли мне этот подход? - person siva Rapolu; 21.08.2013

По соображениям производительности каждая горизонтальная строка в растровом изображении буферизуется до границы DWORD (см. этот ответ для получения более подробной информации). Итак, если ширина вашего растрового изображения, умноженная на бит на пиксель (bpp), не делится на 32 (DWORD = 32 бита), тогда она дополняется дополнительными битами. Таким образом, растровое изображение размером 238x40 1bpp имеет объем памяти 8 DWORD на строку или 256 бит.

Stride объекта BitmapData - количество байтов, которые каждая строка вашего растрового изображения потребляет в памяти. Когда вы захватываете байтовый массив, вы также захватываете это заполнение.

Перед преобразованием массива байтов в шестнадцатеричный необходимо обрезать буфер до конца. Следующая функция должна это сделать.

public static byte[] TruncatePadding(byte[] PaddedImage, int Width, int Stride, int BitsPerPixel)
{
    //Stride values can be negative
    Stride = Math.Abs(Stride);
    //Get the actual number of bytes each row contains.
    int shortStride = (int)Math.Ceiling((double)(Width*BitsPerPixel/8));
    //Figure out the height of the image from the array data
    int height = PaddedImage.Length / Stride;

    if (height < 1)
        return null;

    //Allocate the new array based on the image width
    byte[] truncatedImage = new byte[shortStride * height];

    //Copy the data minus the padding to a new array
    for(int i = 0; i < height; i++)
        Buffer.BlockCopy(PaddedImage,i*Stride,truncatedImage,i*shortStride,shortStride);

    return truncatedImage;
}
person MyItchyChin    schedule 21.08.2013
comment
Спасибо MyltchnyChin, ваше объяснение по чтению данных изображений по строкам помогло мне. Вы можете прокомментировать мой пост, если кто-то объяснил это другим способом. Спасибо :-) - person siva Rapolu; 23.08.2013

Комментарии MiMo и MyItchyChin очень помогли мне в решении проблемы.

Проблема в том, что в конце получается лишняя строка. Таким образом, технически при печати каждой строки изображения последние несколько байтов неверны.

Причина возникновения этой проблемы в том, что размер изображения может быть любым, но при отправке на принтер ширина байта должна делиться на восемь. В моем случае мой принтер ожидает байтов в качестве входных данных, поэтому я должен быть осторожен при передаче изображения.

Предположим, у меня есть изображение размером 168x168.

byteWidth = Math.Ceiling(bitmapDataWidth / 8.0);

так что byteWidth здесь 21. В соответствии с ожиданием принтера, я выполнил операцию сдвига влево до 24, что делится на 8, поэтому фактически я увеличил размер изображения на 3 байта, а затем начал читать байтовую информацию. Строка, о которой я говорю, - это лишние 3 байта. Поскольку данных нет, печатается черная линия.

Я написал логику таким образом, что байтовый массив не влияет на операции сдвига, поэтому у меня это сработало.

Первые дни для меня в обработке изображений, поэтому, пожалуйста, не обращайте внимания, если я сделал глупую ошибку и объяснил решение здесь.

person siva Rapolu    schedule 23.08.2013