JavaScript & JQuery

Epson ESC/POS II 호환 카드단말기 출력 명령어

allenspace 2025. 11. 6. 16:48

강조, 확대, 정렬, 밑줄, 커트, 줄바꿈 출력 명령어 - JavaScript

 

1. 기본 명령어 함수

javascript
// ESC/POS 명령어 유틸리티
const ESC = '\x1B';  // ESC
const GS = '\x1D';   // GS

// 강조(Bold) 명령어
function boldOn() {
    return ESC + '\x45' + '\x01';  // ESC E 1
}

function boldOff() {
    return ESC + '\x45' + '\x00';  // ESC E 0
}

// 초기화
function initialize() {
    return ESC + '\x40';  // ESC @
}

// 배수 확대
function setTextSize(width, height) {
    // width, height: 1~8
    const size = ((width - 1) << 4) | (height - 1);
    return GS + '\x21' + String.fromCharCode(size);
}

// 정렬 (0: 왼쪽, 1: 중앙, 2: 오른쪽)
function setAlignment(align) {
    return ESC + '\x61' + String.fromCharCode(align);
}

// 밑줄
function underlineOn() {
    return ESC + '\x2D' + '\x01';  // ESC - 1
}

function underlineOff() {
    return ESC + '\x2D' + '\x00';  // ESC - 0
}

// 반전
function reverseOn() {
    return GS + '\x42' + '\x01';  // GS B 1
}

function reverseOff() {
    return GS + '\x42' + '\x00';  // GS B 0
}

// 용지 커트
function cutPaper() {
    return GS + '\x56' + '\x00';  // GS V 0
}

// 줄바꿈
function lineFeed(lines = 1) {
    return '\n'.repeat(lines);
}

 

2. 영수증 생성 예제

javascript
// 헤어짱몰 결제 영수증 생성
function generatePaymentReceipt(data) {
    let receipt = '';
    
    // 초기화
    receipt += initialize();
    
    // 상호명 (중앙정렬 + 2배 크기 + 강조)
    receipt += setAlignment(1);  // 중앙
    receipt += setTextSize(2, 2);  // 2배 크기
    receipt += boldOn();
    receipt += data.storeName || '헤어짱몰';
    receipt += boldOff();
    receipt += lineFeed();
    receipt += setTextSize(1, 1);  // 원래 크기
    
    // 왼쪽 정렬
    receipt += setAlignment(0);
    receipt += '--------------------------------' + lineFeed();
    
    // 승인금액 (강조)
    receipt += boldOn();
    receipt += '승인금액: ' + formatAmount(data.amount) + '원' + lineFeed();
    receipt += boldOff();
    
    // 카드정보
    receipt += '카드번호: ' + data.cardNo + lineFeed();
    receipt += '할부개월: ' + (data.installment || '일시불') + lineFeed();
    receipt += '승인번호: ' + data.approvalNo + lineFeed();
    receipt += '승인시간: ' + formatDateTime(data.approvalTime) + lineFeed();
    
    receipt += '--------------------------------' + lineFeed();
    
    // 가맹점 정보
    receipt += '가맹점명: ' + data.merchantName + lineFeed();
    receipt += '사업자번호: ' + data.businessNo + lineFeed();
    receipt += '대표자: ' + data.ceoName + lineFeed();
    receipt += 'TEL: ' + data.tel + lineFeed();
    
    receipt += lineFeed(2);
    
    // 서명란
    receipt += setAlignment(1);
    receipt += '(고객 서명)' + lineFeed(3);
    receipt += '___________________' + lineFeed(2);
    
    // 용지 커트
    receipt += cutPaper();
    
    return receipt;
}

// 금액 포맷
function formatAmount(amount) {
    return Number(amount).toLocaleString('ko-KR');
}

// 날짜/시간 포맷
function formatDateTime(dateTime) {
    const date = new Date(dateTime);
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');
    
    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

 

3. 사용 예제

javascript
// 영수증 데이터
const receiptData = {
    storeName: '헤어짱몰 강남점',
    amount: 50000,
    cardNo: '1234-****-****-5678',
    installment: '일시불',
    approvalNo: '12345678',
    approvalTime: new Date(),
    merchantName: '글리티',
    businessNo: '123-45-67890',
    ceoName: '홍길동',
    tel: '02-1234-5678'
};

// 영수증 생성
const receiptText = generatePaymentReceipt(receiptData);

// 출력 (프린터 또는 시리얼 포트로 전송)
console.log(receiptText);

 

4. Web Serial API로 카드단말기 출력

javascript
// 시리얼 포트로 출력 (Chrome 89+)
async function printToSerialPort(receiptText) {
    try {
        // 시리얼 포트 요청
        const port = await navigator.serial.requestPort();
        
        // 포트 열기 (보통 9600, 19200, 115200 등)
        await port.open({ baudRate: 9600 });
        
        // 텍스트를 바이트로 변환
        const encoder = new TextEncoder();
        const data = encoder.encode(receiptText);
        
        // 데이터 전송
        const writer = port.writable.getWriter();
        await writer.write(data);
        writer.releaseLock();
        
        // 포트 닫기
        await port.close();
        
        console.log('출력 완료');
    } catch (error) {
        console.error('출력 오류:', error);
    }
}

// 사용
printToSerialPort(receiptText);

 

5. iframe 프린터 출력 (웹 프린터)

javascript
// 웹 프린터로 출력 (iframe 사용)
function printToWebPrinter(receiptText) {
    // ESC/POS를 HTML로 변환
    const htmlContent = escPosToHtml(receiptText);
    
    // iframe 생성
    const iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
    
    // 내용 작성
    const doc = iframe.contentWindow.document;
    doc.open();
    doc.write(`
        <html>
        <head>
            <style>
                body { font-family: monospace; font-size: 12px; }
                .bold { font-weight: bold; }
                .center { text-align: center; }
                .large { font-size: 24px; }
            </style>
        </head>
        <body>${htmlContent}</body>
        </html>
    `);
    doc.close();
    
    // 프린트
    iframe.contentWindow.print();
    
    // iframe 제거
    setTimeout(() => document.body.removeChild(iframe), 1000);
}

// ESC/POS를 HTML로 변환하는 간단한 함수
function escPosToHtml(text) {
    return text
        .replace(/\x1B\x45\x01/g, '<span class="bold">')
        .replace(/\x1B\x45\x00/g, '</span>')
        .replace(/\x1B\x61\x01/g, '<div class="center">')
        .replace(/\x1B\x61\x00/g, '</div>')
        .replace(/\n/g, '<br>');
}

 

6. 간단한 테스트용 함수

javascript
// 간단한 강조 텍스트 출력
function printBoldText(text) {
    return boldOn() + text + boldOff();
}

// 테스트
console.log('일반 텍스트');
console.log(printBoldText('강조된 텍스트'));
console.log('일반 텍스트');