feat: 增加打印机接口

This commit is contained in:
2024-12-21 14:22:05 +08:00
parent 38865909af
commit ffab982975
8 changed files with 97 additions and 69 deletions

BIN
after.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
before.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -71,6 +71,12 @@
</dependency>
<dependency>
<groupId>org.openpnp</groupId>
<artifactId>opencv</artifactId>
<version>[4.3.0,)</version>
</dependency>
<dependency>
<groupId>me.lemire.integercompression</groupId>
<artifactId>JavaFastPFOR</artifactId>

View File

@@ -2,26 +2,38 @@ package cn.lihongjie.coal.common;
import cn.hutool.core.util.HexUtil;
import com.google.common.base.Splitter;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import nu.pattern.OpenCV;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.List;
import java.util.function.Function;
import javax.imageio.ImageIO;
@Slf4j
@UtilityClass
public class TscPrinterUtil {
static {
OpenCV.loadLocally();
}
public static String toHex(String text) {
return HexUtil.encodeHexStr(toBytes(text));
@@ -48,44 +60,36 @@ public class TscPrinterUtil {
}
@SneakyThrows
public static byte[] base64ImageToTscBmpImage(String base64Image) {
public static ImageInfo base64ImageToTscBmpImage(String base64Image) {
var image =
ImageIO.read(new ByteArrayInputStream((Base64.getDecoder().decode(base64Image))));
int width = image.getWidth();
byte[] bytes = Base64.getDecoder().decode(base64Image);
int height = image.getHeight();
FileUtils.writeByteArrayToFile(new java.io.File("before.png"), bytes);
ByteArrayInputStream input = new ByteArrayInputStream(bytes);
// width必须是8的倍数
int newWidth = width % 8 == 0 ? width : width + 8 - width % 8;
Mat mat1 = Imgcodecs.imdecode(new MatOfByte(input.readAllBytes()), Imgcodecs.IMREAD_GRAYSCALE);
BitSet bs = new BitSet();
// 循环每一个像素
ByteBuffer buffer = ByteBuffer.allocate(mat1.width() * mat1.height());
for (int i = 0; i < height; i++) {
for (int j = 0; j < newWidth; j++) {
int idx = i * newWidth + j;
if (j < width) {
bs.set(idx, image.getRGB(j, i) != Color.black.getRGB());
for (int i = 0; i < mat1.height(); i++) {
} else {
for (int j = 0; j < mat1.width(); j++) {
bs.set(idx, true);
}
double[] data = mat1.get(i, j);
buffer.put((byte) data[0]);
}
}
TscPrinterUtil.printBS(bs, newWidth);
return bs.toByteArray();
return new ImageInfo(mat1.width() , mat1.height(), bytebufferToBytes(buffer));
}
public static void printBS(BitSet bs, int width) {
StringBuilder sb = new StringBuilder();
sb.append(width);
sb.append("\n");
for (int i = 0; i < bs.length(); i++) {
@@ -97,20 +101,38 @@ public class TscPrinterUtil {
sb.append(bs.get(i) ? "1" : "0").append(" ");
}
log.debug(sb.toString());
log.info(sb.toString());
}
private static byte[] processBitMap(String s) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
int lasted = s.lastIndexOf(",");
ByteBuffer buffer = ByteBuffer.allocate(1000000);
List<String> list = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(s);
for(int i = 0; i < 2; i++) {
buffer.put(list.get(i).getBytes(StandardCharsets.UTF_8));
buffer.put(",".getBytes(StandardCharsets.UTF_8));
}
String prefix = s.substring(0, lasted + 1);
buffer.put(prefix.getBytes(StandardCharsets.UTF_8));
// 剩下的内容为base64
buffer.put(base64ImageToTscBmpImage(s.substring(lasted + 1)));
ImageInfo imageInfo = base64ImageToTscBmpImage(list.get(list.size()-1));
buffer.put(String.valueOf(imageInfo.width / 8).getBytes(StandardCharsets.UTF_8));
buffer.put(",".getBytes(StandardCharsets.UTF_8));
buffer.put(String.valueOf(imageInfo.height).getBytes(StandardCharsets.UTF_8));
buffer.put(",".getBytes(StandardCharsets.UTF_8));
buffer.put("1".getBytes(StandardCharsets.UTF_8));
buffer.put(",".getBytes(StandardCharsets.UTF_8));
buffer.put(imageInfo.data);
buffer.put("\r\n".getBytes(StandardCharsets.UTF_8));
@@ -121,7 +143,7 @@ public class TscPrinterUtil {
String[] lines = StringUtils.split(command, "\n");
ByteBuffer buffer = ByteBuffer.allocate(1024);
ByteBuffer buffer = ByteBuffer.allocate(1000000);
for (String line : lines) {
int i = line.indexOf(" ");
@@ -131,13 +153,16 @@ public class TscPrinterUtil {
buffer.put(Command.of(cmd).process(line));
} else {
buffer.put(line.getBytes(StandardCharsets.UTF_8));
buffer.put(Command.DEFAULT.process(line));
}
}
return bytebufferToBytes(buffer);
}
public record ImageInfo(int width, int height, byte[] data) {
}
public static byte[] bytebufferToBytes(ByteBuffer buffer) {
byte[] bytes = new byte[buffer.position()];
buffer.flip();

View File

@@ -6,6 +6,7 @@ import cn.lihongjie.coal.tscprinter.dto.ProcessCommandRequest;
import cn.lihongjie.coal.tscprinter.dto.ProcessCommandResponse;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -14,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
public class TscPrinterController {
@PostMapping("/processCommand")
public ProcessCommandResponse processCommand(ProcessCommandRequest request) {
public ProcessCommandResponse processCommand(@RequestBody ProcessCommandRequest request) {
return new ProcessCommandResponse(
Base64.encode(TscPrinterUtil.processCommand(request.getCommand())));

View File

@@ -5,7 +5,6 @@ import static cn.lihongjie.coal.common.TscPrinterUtil.processCommand;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.resource.ResourceUtil;
import org.junit.jupiter.api.Test;
@@ -20,22 +19,16 @@ class TscPrinterUtilTest {
public static Stream<Arguments> hexData() {
return Stream.of(
Arguments.of("S", "53"),
Arguments.of("T", "54"),
Arguments.of("C", "43"),
Arguments.of("A", "41"),
Arguments.of("SET TEAR ON", "53 45 54 20 54 45 41 52 20 4f 4e".replace(" ", "")),
Arguments.of("SET TEAR ON\nSET TEAR ON", "53 45 54 20 54 45 41 52 20 4f 4e 0d 0a 53 45 54 20 54 45 41 52 20 4f 4e".replace(" ", "")
)
);
Arguments.of(
"SET TEAR ON\nSET TEAR ON",
"53 45 54 20 54 45 41 52 20 4f 4e 0d 0a 53 45 54 20 54 45 41 52 20 4f 4e"
.replace(" ", "")));
}
@ParameterizedTest
@@ -43,38 +36,41 @@ class TscPrinterUtilTest {
void name(String text, String expectHex) {
assertThat(TscPrinterUtil.toHex(text)).isEqualToIgnoringCase(expectHex);
}
@Test
void test1() {
byte[] bytes = TscPrinterUtil.base64ImageToTscBmpImage(Base64.encode(ResourceUtil.getStream("1.bmp")));
assertThat(bytes).asHexString().isEqualTo("FD");
}
@Test
void test2() {
byte[] bytes = TscPrinterUtil.base64ImageToTscBmpImage(Base64.encode(ResourceUtil.getStream("2x2_1.bmp")));
assertThat(bytes).asHexString().isEqualTo("FEFD");
}
@Test
void test3() {
assertThat(processCommand("SET TEAR ON")).asHexString().isEqualToIgnoringCase("53 45 54 20 54 45 41 52 20 4f 4e 0D 0A".replace(" ", ""));
assertThat(processCommand("SET TEAR ON\nSET TEAR ON")).asHexString().isEqualToIgnoringCase("5345542054454152204F4E0D0A5345542054454152204F4E0D0A".replace(" ", ""));
assertThat(processCommand("SET TEAR ON"))
.asHexString()
.isEqualToIgnoringCase("53 45 54 20 54 45 41 52 20 4f 4e 0D 0A".replace(" ", ""));
assertThat(processCommand("SET TEAR ON\nSET TEAR ON"))
.asHexString()
.isEqualToIgnoringCase(
"5345542054454152204F4E0D0A5345542054454152204F4E0D0A".replace(" ", ""));
}
@Test
void test4() {
byte[] bytes = ResourceUtil.readBytes("cap.bin");
bytes = Arrays.copyOfRange(bytes, 39, bytes.length);
BitSet bs = new BitSet();
for (int j = 0; j < bytes.length; j++) {
byte b = bytes[j];
for (int i = 0; i < 8; i++) {
bs.set(j * 8 + i, (b & (1 << i)) != 0);
}
}
TscPrinterUtil.printBS(bs, 67*8 );
}
}

BIN
src/test/resources/cap.bin Normal file

Binary file not shown.

View File