mirror of
https://codeup.aliyun.com/64f7d6b8ce01efaafef1e678/coal/coal.git
synced 2026-01-25 23:57:12 +08:00
feat: 增加打印机接口
This commit is contained in:
171
src/main/java/cn/lihongjie/coal/common/TscPrinterUtil.java
Normal file
171
src/main/java/cn/lihongjie/coal/common/TscPrinterUtil.java
Normal file
@@ -0,0 +1,171 @@
|
||||
package cn.lihongjie.coal.common;
|
||||
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
@Slf4j
|
||||
@UtilityClass
|
||||
public class TscPrinterUtil {
|
||||
|
||||
public static String toHex(String text) {
|
||||
|
||||
return HexUtil.encodeHexStr(toBytes(text));
|
||||
}
|
||||
|
||||
private static @NotNull String processLineSep(String text) {
|
||||
String placeholder = "PLACEHOLDER_FOR_CRLF";
|
||||
text = text.replace("\r\n", placeholder);
|
||||
|
||||
// Step 2: Replace all occurrences of \n with \r\n
|
||||
text = text.replace("\n", "\r\n");
|
||||
|
||||
// Step 3: Replace the placeholder back to \r\n
|
||||
text = text.replace(placeholder, "\r\n");
|
||||
return text;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(String text) {
|
||||
|
||||
text = processLineSep(text);
|
||||
// convert ascii to byte[]
|
||||
|
||||
return text.getBytes();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static byte[] base64ImageToTscBmpImage(String base64Image) {
|
||||
|
||||
var image =
|
||||
ImageIO.read(new ByteArrayInputStream((Base64.getDecoder().decode(base64Image))));
|
||||
|
||||
int width = image.getWidth();
|
||||
|
||||
int height = image.getHeight();
|
||||
|
||||
// width必须是8的倍数
|
||||
int newWidth = width % 8 == 0 ? width : width + 8 - width % 8;
|
||||
|
||||
BitSet bs = new BitSet();
|
||||
// 循环每一个像素
|
||||
|
||||
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());
|
||||
|
||||
} else {
|
||||
|
||||
bs.set(idx, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TscPrinterUtil.printBS(bs, newWidth);
|
||||
|
||||
return bs.toByteArray();
|
||||
}
|
||||
|
||||
public static void printBS(BitSet bs, int width) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("\n");
|
||||
|
||||
for (int i = 0; i < bs.length(); i++) {
|
||||
|
||||
if (i % width == 0) {
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
sb.append(bs.get(i) ? "1" : "0").append(" ");
|
||||
}
|
||||
|
||||
log.debug(sb.toString());
|
||||
}
|
||||
|
||||
private static byte[] processBitMap(String s) {
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
||||
int lasted = s.lastIndexOf(",");
|
||||
|
||||
String prefix = s.substring(0, lasted + 1);
|
||||
|
||||
buffer.put(prefix.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// 剩下的内容为base64
|
||||
buffer.put(base64ImageToTscBmpImage(s.substring(lasted + 1)));
|
||||
|
||||
buffer.put("\r\n".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
return bytebufferToBytes(buffer);
|
||||
}
|
||||
|
||||
public static byte[] processCommand(String command) {
|
||||
|
||||
String[] lines = StringUtils.split(command, "\n");
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
||||
for (String line : lines) {
|
||||
|
||||
int i = line.indexOf(" ");
|
||||
|
||||
if (i > 0) {
|
||||
String cmd = line.substring(0, i);
|
||||
buffer.put(Command.of(cmd).process(line));
|
||||
|
||||
} else {
|
||||
buffer.put(line.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
return bytebufferToBytes(buffer);
|
||||
}
|
||||
|
||||
public static byte[] bytebufferToBytes(ByteBuffer buffer) {
|
||||
byte[] bytes = new byte[buffer.position()];
|
||||
buffer.flip();
|
||||
buffer.get(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
public enum Command {
|
||||
BITMAP(TscPrinterUtil::processBitMap),
|
||||
DEFAULT(t -> (t + "\r\n").getBytes(StandardCharsets.UTF_8)),
|
||||
;
|
||||
|
||||
private final Function<String, byte[]> processor;
|
||||
|
||||
Command(Function<String, byte[]> processor) {
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
public static Command of(String cmd) {
|
||||
return Arrays.stream(values())
|
||||
.filter(c -> c.name().equalsIgnoreCase(cmd))
|
||||
.findFirst()
|
||||
.orElse(DEFAULT);
|
||||
}
|
||||
|
||||
public byte[] process(String text) {
|
||||
return processor.apply(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,12 @@ public class FileController {
|
||||
@RequestParam("name") String name,
|
||||
@RequestParam("dir") String dir,
|
||||
@RequestParam(value = "url", required = false) String url,
|
||||
@RequestParam(value = "base64", required = false) String base64,
|
||||
@RequestParam(value = "sortKey", required = false) String sortKey,
|
||||
@RequestParam(value = "code", required = false) String code,
|
||||
@RequestParam(value = "remarks", required = false) String remarks
|
||||
) {
|
||||
return this.service.upload(file, name, dir, sortKey, code, remarks, url);
|
||||
return this.service.upload(file, name, dir, sortKey, code, remarks, url, base64);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Base64;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@@ -110,7 +111,7 @@ public class FileService extends BaseService<FileEntity, FileRepository> {
|
||||
String sortKey,
|
||||
String code,
|
||||
String remarks,
|
||||
String url) {
|
||||
String url, String base64) {
|
||||
|
||||
long size = 0;
|
||||
InputStream fis = null;
|
||||
@@ -123,7 +124,12 @@ public class FileService extends BaseService<FileEntity, FileRepository> {
|
||||
HttpUtil.download(url, out, true);
|
||||
fis = new ByteArrayInputStream(out.toByteArray());
|
||||
size = out.size();
|
||||
} else {
|
||||
} else if (StringUtils.isNotBlank(base64)) {
|
||||
|
||||
fis = new ByteArrayInputStream(Base64.getDecoder().decode(base64.replace("data:image/png;base64,", "")));
|
||||
size = fis.available();
|
||||
|
||||
}else {
|
||||
throw new BizException("文件为空");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.lihongjie.coal.tscprinter.controller;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.lihongjie.coal.common.TscPrinterUtil;
|
||||
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.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/tscprinter")
|
||||
public class TscPrinterController {
|
||||
|
||||
@PostMapping("/processCommand")
|
||||
public ProcessCommandResponse processCommand(ProcessCommandRequest request) {
|
||||
|
||||
return new ProcessCommandResponse(
|
||||
Base64.encode(TscPrinterUtil.processCommand(request.getCommand())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.lihongjie.coal.tscprinter.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class ProcessCommandRequest {
|
||||
|
||||
private String command;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.lihongjie.coal.tscprinter.dto;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class ProcessCommandResponse {
|
||||
|
||||
private String base64;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package cn.lihongjie.coal.common;
|
||||
|
||||
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;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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(" ", "")
|
||||
|
||||
|
||||
)
|
||||
|
||||
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("hexData")
|
||||
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(" ", ""));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
BIN
src/test/resources/1.bmp
Normal file
BIN
src/test/resources/1.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 B |
BIN
src/test/resources/2x2_1.bmp
Normal file
BIN
src/test/resources/2x2_1.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 B |
Reference in New Issue
Block a user