Không thể in Tiếng Việt bằng máy in nhiệt CSN-A2

Xin chào mọi người. Mình đang làm thử chức năng in hóa đơn từ PC sang máy in nhiệt thông qua cổng UART. Mọi chuyện khá thuận lợi khi có thể in được bình thường nhưng đang có vấn đề với font chữ Tiếng Việt. Theo tài liệu của hãng đưa thì có hỗ trợ

Link doc

Mình chạy code như sau :

//Obj for send byte array to printer via uart port
Rs232_printer *printer = new Rs232_printer();
//Command Initialize
QByteArray InitCmd = "\x1B\x40";
printer->sendData(InitCmd.data(),InitCmd.size());
//Select character code table 
QByteArray vietCode = "\x1B\x74\x35";
printer->sendData(vietCode.data(),vietCode.size());
//Print sample
QString text  = "HÓA ĐƠN BÁN HÀNG";
QByteArray Header = vietCode+ text.toUtf8();
printer->sendData(Header.data(),Header.size());

Kết quả mình in ra được là : HA N BN HNG

Theo manual thì mã 35 Vietnam là theo decimal, mà bạn lại truyền là 0x35.
Bạn đổi thành 0x23 thử nhé

QByteArray vietCode = "\x1B\x74\x23";
2 Likes

Mình đã thử nhưng vẫn không được. Mình chạy thì nó ra như thế này
image

Có vẻ bạn phải map từng Vietnamese character với Table code của nó


Ví dụ Ó thành 0xD3, Ơ thành 0xD5
Chứ truyền thẳng QString chắc nó không hiểu đâu.

Bạn thử:
QString text = "H\xD3A Đ\xD5N B\xC1N H\xC0NG"; xem. Nếu không được thì phải chuyển qua Byte array thử. Mình không biết QString đó nó lưu như thế nào.

5 Likes

tôi rảnh ngồi viết hàm chuyển mấy chữ tiếng Việt trong QString sang CP1258 đây. Ko biết xài trình dịch nào nên viết theo C++11 cho tương thích với mấy trình dịch cũ. Cách xài là:

#include "utf16tocp1258.h"
...
const std::string kVietCode = "\x1B\x74\x23";
QString text = "HÓA ĐƠN BÁN HÀNG";
std::string textToPrint = kVietCode + wsToCp1258(text);
printer->sendData(textToPrint.data(), textToPrint.size());

thêm 2 file này vào executable nữa là được:

utf16tocp1258.h

#pragma once

#include <sstream>
#include <type_traits>
#include <cstdint>

auto findVnUtf16ToCp1258Char(char16_t wch) -> uint16_t;

template <class...>
using void_t = void;

template <typename, typename = void>
struct has_unicode_memfn : std::false_type {};

template <typename T>
struct has_unicode_memfn<T, void_t<decltype(std::declval<T>().unicode())>> : std::true_type {};

template <class WideChar>
typename std::enable_if<has_unicode_memfn<WideChar>::value, char16_t>::type toChar16(WideChar wc) {
    return static_cast<char16_t>(wc.unicode());
}

template <class WideChar>
typename std::enable_if<std::is_integral<WideChar>::value, char16_t>::type toChar16(WideChar wc) {
    return static_cast<char16_t>(wc);
}

template <class WideString>
void printWsToCp1258(std::ostream& os, const WideString& ws) {
    for (auto wc : ws) {
        const char16_t ch = toChar16(wc);
        auto ch1258 = findVnUtf16ToCp1258Char(ch);
        if (ch1258 != 0) {
            for (; ch1258; ch1258 >>= 8) os << static_cast<char>(ch1258 % 256);
        } else {
            os << static_cast<char>(ch);
        }
    }
}

template <class WideString>
auto wsToCp1258(const WideString& ws) -> std::string {
    std::ostringstream oss;
    printWsToCp1258(oss, ws);
    return oss.str();
}

utf16tocp1258.cpp

#include "utf16tocp1258.h"
#include <array>
#include <utility>

auto vnUtf16ToCp1258PerfHash(char16_t wch) -> uint32_t {
    static const std::array<uint8_t, 21> assoValues{24,  71, 38,  1,   0, 22, 48, 95, 97, 96, 137,
                                                    118, 81, 111, 121, 3, 20, 12, 16, 8,  47};
    return assoValues[wch % 16] + assoValues[(wch >> 4) % 16 + 5] + assoValues[(wch >> 12) % 16 + 3]; // NOLINT
}

auto findVnUtf16ToCp1258Char(char16_t wch) -> uint16_t {
    static const std::array<std::pair<char16_t, uint16_t>, 217> vnUtf16ToCp1258Mapping{{
        {0, 0},        {0, 0},        {0, 0},        {7844, 60610}, {7843, 53857}, {0, 0},        {7855, 60643},
        {431, 221},    {7908, 62037}, {7907, 62197}, {227, 56929},  {7919, 57085}, {7876, 57034}, {7875, 53994},
        {195, 56897},  {7887, 53871}, {7892, 53972}, {7891, 52468}, {0, 0},        {7903, 54005}, {7860, 57027},
        {7859, 53987}, {0, 0},        {7871, 60650}, {259, 227},    {7845, 60642}, {0, 0},        {7840, 62017},
        {416, 213},    {0, 0},        {7909, 62069}, {0, 0},        {7904, 57045}, {0, 0},        {7877, 57066},
        {0, 0},        {7872, 52426}, {0, 0},        {7893, 54004}, {213, 56911},  {7888, 60628}, {7842, 53825},
        {7861, 57059}, {0, 0},        {7856, 52419}, {432, 253},    {7906, 62165}, {7924, 62041}, {7923, 52345},
        {0, 0},        {7874, 53962}, {7846, 52418}, {0, 0},        {0, 0},        {7890, 52436}, {210, 52303},
        {7910, 53845}, {0, 0},        {7858, 53955}, {0, 0},        {7878, 62154}, {258, 195},    {0, 0},
        {0, 0},        {7894, 57044}, {0, 0},        {0, 0},        {0, 0},        {7862, 62147}, {7925, 62073},
        {245, 56943},  {7920, 62173}, {0, 0},        {272, 208},    {7841, 62049}, {417, 245},    {0, 0},
        {0, 0},        {0, 0},        {7905, 57077}, {0, 0},        {0, 0},        {0, 0},        {7873, 52458},
        {7852, 62146}, {7922, 52313}, {242, 52335},  {7889, 60660}, {0, 0},        {7916, 53981}, {236, 52329},
        {7857, 52451}, {0, 0},        {7884, 62031}, {204, 52297},  {7926, 53849}, {0, 0},        {7900, 52437},
        {7847, 52450}, {7849, 53986}, {7848, 53954}, {7868, 56901}, {0, 0},        {7911, 53877}, {7913, 60669},
        {7912, 60637}, {0, 0},        {7879, 62186}, {7881, 53865}, {7880, 53833}, {0, 0},        {7895, 57076},
        {7897, 62196}, {7896, 62164}, {7853, 62178}, {7863, 62179}, {7865, 62053}, {7864, 62021}, {7921, 62205},
        {7917, 54013}, {273, 240},    {7851, 57058}, {0, 0},        {7885, 62063}, {7854, 60611}, {0, 0},
        {7915, 52477}, {7901, 52469}, {221, 60505},  {7918, 57053}, {7883, 62057}, {7869, 56933}, {0, 0},
        {7886, 53839}, {7899, 60661}, {0, 0},        {0, 0},        {7902, 53973}, {7867, 53861}, {0, 0},
        {7850, 57026}, {7870, 60618}, {7927, 53881}, {7929, 56953}, {7928, 56921}, {7914, 52445}, {0, 0},
        {0, 0},        {0, 0},        {7882, 62025}, {0, 0},        {0, 0},        {0, 0},        {7898, 60629},
        {0, 0},        {0, 0},        {0, 0},        {7866, 53829}, {0, 0},        {253, 60537},  {0, 0},
        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},
        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},
        {0, 0},        {0, 0},        {119, 117},    {0, 0},        {0, 0},        {0, 0},        {0, 0},
        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},
        {0, 0},        {0, 0},        {0, 0},        {297, 56937},  {296, 56905},  {0, 0},        {0, 0},
        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},
        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},
        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {0, 0},        {361, 56949},  {360, 56917},
    }};
    constexpr char16_t kMinVnUtf16 = 119;
    constexpr char16_t kMaxVnUtf16 = 7929;
    if (wch > kMaxVnUtf16 || wch < kMinVnUtf16) return 0;
    const auto key = vnUtf16ToCp1258PerfHash(wch);
    if (key >= vnUtf16ToCp1258Mapping.size()) return 0;
    const auto& u16_cp1258 = vnUtf16ToCp1258Mapping[key]; // NOLINT
    return wch == u16_cp1258.first ? u16_cp1258.second : 0;
}

(cái hàm findVnUtf16ToCp1258Char đáng lẽ xài std::unordered_map chứa cái bảng mapping kia được rồi toy rảnh nên xài gperf tìm perfect hash cho cái bảng này)

6 Likes

Dành 1 like và lời khen cho bạn nhưng tiếc là chủ topic đã lặn mất tiêu rồi. Haizzz

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?