在CSN-A2热敏打印机上打印非纯色图像时出现图像错误。

huangapple go评论96阅读模式
英文:

Image error when printing non-solid color image on CSN-A2 thermal printer

问题

我已经创建了一些代码,实现了ESC/POS ESC *位图打印命令[1]在CSN-A2[2]上的实现。该代码使用ImageMagick将任意图像转换为黑白,并使用抖动算法。如果我将纯黑白图像发送到打印机,它会正常打印。如果我发送其他图像,图像中的各种矩形会出现问题。

使用以下代码,我生成命令,然后将其发送到通过串行连接连接的CSN-A2。

我已经将imageSlice写出来,以确认之前的转换步骤是否正确,并确认它们是正确的。

英文:

I have created some code that implements the ESC/POS ESC * bit image printing command [1] for a CSN-A2 [2]. That code uses ImageMagick to convert an arbitrary image to black and white and uses a dithering algorithm. If I send a purely black and white image to the printer, it prints fine. If I send it anything else, various rectangles in the image are messed up.

在CSN-A2热敏打印机上打印非纯色图像时出现图像错误。

[1] https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=88
[2] https://cdn-shop.adafruit.com/datasheets/CSN-A2+User+Manual.pdf

Using the following code, I generate the command and then send it to the CSN-A2, which is attached via a serial connection.
I have

package test

import (
	"bytes"
	"context"
	"encoding/binary"
	"fmt"

	"gopkg.in/gographics/imagick.v2/imagick"
)

type EscStarArtworkTransformer struct {
	maxWidth uint
}

func NewEscStarArtworkTransformer(maxWidth uint) *EscStarArtworkTransformer {
	return &EscStarArtworkTransformer{
		maxWidth: maxWidth,
	}
}

func (t *EscStarArtworkTransformer) Transform(ctx context.Context, mw *imagick.MagickWand) ([]byte, error) {
	logger := FromLoggerContext(ctx)

	density := uint(24)

	if mw.GetImageWidth() > t.maxWidth {
		if err := mw.ThumbnailImage(t.maxWidth, mw.GetImageHeight()*t.maxWidth/mw.GetImageWidth()); err != nil {
			panic(err) // TODO
		}
	}

	{
		pattern := imagick.NewMagickWand()
		defer pattern.Destroy()

		if err := pattern.ReadImage("pattern:gray50"); err != nil {
			panic(err) // TODO
		}

		if err := mw.RemapImage(pattern, imagick.DITHER_METHOD_FLOYD_STEINBERG); err != nil {
			panic(err) // TODO
		}
	}

	{
		extendHeight := density - (mw.GetImageHeight() % density)
		if extendHeight != 0 && extendHeight != density {
			if err := mw.SetGravity(imagick.GRAVITY_NORTH); err != nil {
				panic(err) // TODO
			}

			pw := imagick.NewPixelWand()
			defer pw.Destroy()

			pw.SetColor("white")

			if err := mw.SetBackgroundColor(pw); err != nil {
				panic(err) // TODO
			}

			if err := mw.ExtentImage(mw.GetImageWidth(), mw.GetImageHeight()+extendHeight, 0, 0); err != nil {
				panic(err) // TODO
			}
		}
	}

	{
		pw := imagick.NewPixelWand()
		defer pw.Destroy()

		if err := mw.RotateImage(pw, 270); err != nil {
			panic(err) // TODO
		}
	}

	if err := mw.FlipImage(); err != nil {
		panic(err) // TODO
	}

	imageHeight := mw.GetImageHeight()
	imageWidth := mw.GetImageWidth()

	widthBuffer := new(bytes.Buffer)
	if err := binary.Write(widthBuffer, binary.LittleEndian, uint16(imageHeight)); err != nil {
		logger.WithError(err).Error("failed to convert image width to binary little endian")
		return nil, fmt.Errorf("convert image width to binary little endian: %w", err)
	}

	data := []byte{0x1b, 0x33, 0}

	rowHeader := []byte{0x1b, 0x2a, 0x21} // ESC * 33
	rowHeader = append(rowHeader, widthBuffer.Bytes()...)

	for left := uint(0); left < imageWidth; left += density {
		imageSlice := mw.Clone()
		defer imageSlice.Destroy()

		if err := imageSlice.CropImage(density, imageHeight, int(left), 0); err != nil {
			logger.WithError(err).Error("failed to crop image slice", err)
			return nil, fmt.Errorf("crop image slice: %w", err)
		}

		exportedPixels, err := imageSlice.ExportImagePixels(0, 0, uint(density), imageHeight, "I", imagick.PIXEL_CHAR)
		if err != nil {
			logger.WithError(err).Error("failed to export image slice pixels")
			return nil, fmt.Errorf("export image slice pixels: %w", err)
		}

		exportedBytes, ok := exportedPixels.([]byte)
		if !ok {
			logger.Error("failed to convert exported image slice pixels to bytes")
			return nil, fmt.Errorf("convert exported image slice pixels to bytes")
		}

		rasterizedRow := make([]byte, (len(exportedBytes)+7)/8)
		for i, x := range exportedBytes {
			if x == 0xff {
				rasterizedRow[i/8] |= 0x80 >> uint(i%8)
			}
		}

		data = append(data, rowHeader...)
		data = append(data, rasterizedRow...)
		data = append(data, 0x0a)
	}

	data = append(data, 0x1b, 0x32) // ESC 2

	return data, nil
}

I have written out the imageSlices to confirm the previous transformation steps worked and confirmed they are correct.

答案1

得分: 1

问题是,当我将数据传输到打印机时,我没有为stty提供正确的设置。我还没有弄清楚具体哪些设置是错误的,但以下是我现在正在使用的设置,它可以正常工作。

stty -F /dev/serial0 0:0:cbe:0:3:1c:7f:15:4:0:0:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

英文:

The problem was, when I was piping the data to the printer, I had not provided the correct settings to stty. I haven't figured out precisely which ones were wrong yet, but here's what I'm using now, which works.

stty -F /dev/serial0 0:0:cbe:0:3:1c:7f:15:4:0:0:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

huangapple
  • 本文由 发表于 2023年3月19日 03:10:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75778087.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定