1 điểm bởi GN⁺ 2024-05-20 | 1 bình luận | Chia sẻ qua WhatsApp
  • Bắt đầu từ trình tạo chữ cái dạng khối bằng JavaScript, rồi sau hai tháng mở rộng để dựng cả chữ viết tay liền nét bằng mã
  • Các ký tự được đặt tọa độ cốt lõi bằng công cụ p5js, làm mượt bằng đường cong Chaikin rồi chuyển thành đường nét có độ dày thay đổi
  • Với chữ viết tay liền nét, cách nối khác nhau tùy từng cặp chữ, nên phần đầu và cuối đường nét được gắn thẻ 0~3 để phân biệt trạng thái không thể nối, đường cơ sở, phía trên đường cơ sở và gần x-height
  • Khi tạo từ, hệ thống chọn một trong 2~3 đường nét cho mỗi chữ, rồi thêm, xóa hoặc thay điểm theo độ cao nối của chữ kề bên, sau đó thêm độ rung bằng Perlin noise
  • Sau khi thu gọn, lớp chữ viết tay liền nét có kích thước 26.1kb, lớn hơn 9.7kb của chữ dạng khối, do có nhiều đường nét và các hàm hiệu chỉnh theo chữ lân cận

Mở rộng từ cách tạo chữ dạng khối sang chữ viết tay liền nét

  • Trình tạo bảng chữ cái dạng khối trước đó định nghĩa các điểm cốt lõi của đường nét từng chữ bằng mã
    • Mỗi chữ đặt khoảng 10 điểm
    • Dùng thuật toán đường cong Chaikin để làm mượt đường nét
    • Chuyển đường nét thành dạng có độ dày thay đổi theo chiều dài
    • Dùng p5js để vẽ hình dạng cuối cùng
  • Với chữ dạng khối, các tọa độ được viết trực tiếp trong mã, và phải chỉnh tay các điểm cho đến khi chữ trông tự nhiên
  • Khi triển khai chữ viết tay, tác giả tạo riêng một công cụ thiết kế chữ cái để giảm bớt công việc lặp đi lặp lại này

Công cụ thiết kế đường nét chữ trong p5js

  • Tác giả tạo và dùng một công cụ để định nghĩa và xuất các điểm cốt lõi trong trình biên tập p5js
  • Công cụ hiển thị đồng thời các chữ mẫu để tham chiếu về tỷ lệ và ngữ cảnh, cùng vùng để thiết kế chữ mới
    • Khi nhấp chuột để đặt các điểm cốt lõi của đường nét, kết quả sau khi áp dụng đường cong Chaikin sẽ được hiển thị
    • Nhấn phím p để chuyển sang chế độ chỉnh sửa
    • Chọn một điểm rồi kéo để điều chỉnh vị trí
    • Nhấn phím enter để xuất đường nét ra console
  • Mỗi chữ có 2~3 phương án và đường nét kết quả có dạng mảng tọa độ {x, y}
  • Để lấy chính nét chữ của mình làm chuẩn, tác giả tự viết ví dụ chữ thường và chữ hoa, rồi nạp ảnh đó vào công cụ tạo chữ để đồ theo
    • Dùng phím w/a/s/d để di chuyển ảnh
    • Dùng phím r/e để phóng to hoặc thu nhỏ ảnh
    • Các con số viết trên giấy là tọa độ x/y để khớp vùng đó với cửa sổ tạo chữ

Bài toán nối nét và thẻ 0~3

  • Với một số cặp chữ, chỉ cần nối đường các điểm cốt lõi của chữ sau vào cuối đường của chữ trước rồi áp dụng đường cong Chaikin một lần là đã cho kết quả tự nhiên
  • Nhưng ở một số tổ hợp, nét nối lại làm hỏng hình dạng chữ
    • Trong na, điểm cuối của n thấp còn điểm đầu của a cao, nên nét nối có thể cắt chéo qua a và khiến nó trông giống e
    • Trong ti, t kết thúc ngay trên đường cơ sở còn i bắt đầu từ đường cơ sở, tạo ra một gờ nối không tự nhiên
  • Thay vì viết quy tắc cho từng cặp chữ cụ thể, tác giả gắn thông tin độ cao nối bằng số vào phần đầu và cuối của mỗi đường nét
    • 0: không thể nối với chữ khác
    • 1: nối với chữ khác ở gần đường cơ sở
    • 2: nối với chữ khác ngay trên đường cơ sở
    • 3: nối với chữ khác ở gần x-height
  • Ngay cả cùng một chữ, cách thêm hoặc xóa điểm cũng thay đổi tùy vị trí đầu từ hay chữ đứng trước, đứng sau
    • Nếu a đứng đầu từ thì điểm thêm vào sẽ trông gượng
    • Với a sau w, nét có thể cắt qua a theo cách khác
    • Khi t nối với k, hình dạng có thể bị biến đổi
  • Tác giả đã thử mọi cặp chữ và tạo ra tính biến thể bằng nhiều lựa chọn đường nét cùng các chỉnh sửa theo chữ lân cận
  • Lý tưởng nhất là mỗi chữ có 5~6 phương án đường nét, nhưng vẫn phải cân bằng với kích thước tệp

Quy trình tạo từ

  • Khi tạo từ, trước hết hệ thống chọn một trong 2~3 đường nét cơ sở cho mỗi ký tự
  • Thông tin nối ở đầu và cuối của đường nét được truyền cho các chữ liền kề
    • Ngay cả cùng một chữ, thông tin điểm cuối cũng có thể khác tùy phương án đường nét được chọn, nên phải chọn xong toàn bộ đường nét chữ trước
  • Sau đó các đường nét cơ sở sẽ được điều chỉnh để khớp với chữ lân cận
    • Nếu độ cao kết thúc của chữ trước là 2, có thể xóa một điểm đầu của đường nét hiện tại
    • Nếu độ cao bắt đầu của chữ sau là 1, có thể thêm một điểm ở vị trí nhất định
  • Hàm điều chỉnh hoạt động khác nhau tùy từng chữ
    • Hàm điều chỉnh của q có 70% xác suất thêm một chỗ ngắt ở cuối, đồng thời thay hoặc thêm điểm tùy thông tin kết thúc của chữ trước hay thông tin bắt đầu của chữ sau
    • Hàm điều chỉnh của n có 30% xác suất tạo ngắt hoặc di chuyển điểm cuối khi chữ sau bắt đầu từ 3
  • Khi ghép các đường nét cơ sở của mọi chữ, các giá trị 1, 2, 3 bị bỏ qua, còn nếu gặp 0 thì bắt đầu một đường mới để tạo chỗ ngắt
  • Đường đã ghép sau đó được áp dụng đường cong Chaikin, chuyển thành dạng có độ dày thay đổi, rồi thêm chút rung nhẹ bằng Perlin noise

Dung lượng và cách sử dụng

  • Lớp chữ cho dạng khối có kích thước 9.7kb, còn lớp chữ viết tay liền nét sau khi minify hiện là 26.1kb
  • Lý do chữ viết tay lớn hơn là vì mỗi chữ có nhiều đường nét và có các hàm điều chỉnh điểm theo chữ lân cận
  • Vẫn còn một số ý tưởng để tiếp tục cắt giảm
    • Hiện tại các chữ được thiết kế theo cỡ font cơ sở 20 rồi mới resize
    • Vì vậy có nhiều tọa độ như x: 14.5
    • Nếu đổi cỡ cơ sở thành 200 thì có thể dùng 145 thay cho số thập phân, nhờ đó giảm được dung lượng cho từng chữ
    • Thay đổi này cần làm cẩn thận nên đang nằm trong danh sách việc cần làm sau
  • Mục đích chính của bộ chữ viết tay này là dùng cho tiêu đề, nhãn và ghi chú nguệch ngoạc trong diagram mà tác giả đang thực hiện
  • Dùng các đường nét được mã hóa thay cho font giúp thao tác trực tiếp trên đường path, chẳng hạn thay đổi vị trí ký tự hoặc độ dày bên trong từng chữ riêng lẻ
  • Tác giả cũng cung cấp bản in Meaningful Nonsense dùng phiên bản phát triển hơn của mã chữ viết tay này; mỗi bản in là một kết quả riêng được tạo ra khi có đơn đặt hàng

1 bình luận

 
GN⁺ 2024-05-20
Ý kiến trên Hacker News
  • Nếu mã hóa chữ viết tay của tôi thì có vẻ có thể xem nó như một hàm băm một chiều
    Đọc lại sau này thì hoàn toàn không có cách nào giải mã được rốt cuộc mình đã định viết gì

    • Nghe như một thử thách đấy! https://www.handwritingocr.com :)
    • Vì thế mà hồi đại học tôi đã phải cố tình bỏ kiểu chữ viết tay nối nét của mình
    • Tôi cũng vậy, chỉ sau vài tiếng là đến chính tôi cũng không thể giải mã nổi nữa
  • Video YouTube của Stuff Made Here nói về nội dung tương tự khá hay: https://www.youtube.com/watch?v=cQO2XTP7QDw
    Họ còn giải thích cả quá trình thử-sai nên xem rất thú vị, và kho lưu trữ tổng hợp chữ viết tay này cũng đáng xem: https://github.com/sjvasquez/handwriting-synthesis

  • Tác phẩm nghệ thuật ở cuối khá đẹp
    Không biết bước tiếp theo có phải là biến nó thành một phông chữ thực sự để có thể gõ trong bất kỳ chương trình nào không

    • Phông chữ cho máy vẽ plotter cũng đã có rồi
      Khác với phông chữ mà ta thường nghĩ tới, nó phải là đường dẫn để lần theo chứ không phải đường viền để tô kín
    • Nếu đã có các đường cong thì làm việc đó khá dễ
      Chỉ là có thể sẽ hơi tẻ nhạt nếu phải làm thủ công hoặc muốn làm theo cách đó
    • Tôi rất thích cách bài này pha trộn công nghệ và nghệ thuật
  • Tôi không thật sự hiểu đoạn nói rằng việc nối chữ không khớp
    Với tôi, cốt lõi của chữ viết tay nối nét là không nhấc bút khỏi giấy, nên cách nối các chữ vốn đã là một phần của hành động viết rồi
    Có vẻ tác giả thực ra không viết theo kiểu đó nên mới nảy sinh vấn đề
    Dù vậy, phần còn lại của bài về cách giải quyết bằng phương pháp đơn giản nhất để vẽ nhiều chữ trên màn hình mà không đụng vào phông chữ thì rất thú vị

    • Câu “cốt lõi của chữ viết tay nối nét là không nhấc bút khỏi giấy” tự nó không sai, nhưng cách diễn giải thì khác
      Trong chữ viết tay nối nét, liên kết giữa các chữ phụ thuộc vào ngữ cảnh
      Ví dụ, hình dạng có thể thay đổi để dễ đọc tùy việc sau ba hay o, và ngay cả trong một từ đôi khi bạn vẫn muốn nhấc bút giữa các chữ
      Như vậy cũng không có nghĩa là phá vỡ “quy tắc” của chữ viết tay nối nét
      Có thể bạn đã được dạy khác và cách dạy đó cũng đúng, nhưng tôi không biết kiểu chữ viết tay nối nét nào mà các liên kết lại không phụ thuộc vào ngữ cảnh
    • Có vẻ mấu chốt là mỗi cặp chữ cái có một cách ăn khớp khác nhau, và điều đó cần được xử lý
    • Mọi cặp chữ cái đều nối với nhau theo những cách khác nhau
      Ngay cả với những phông chữ không nối nét, cũng cần mã hóa việc các chuỗi nhiều chữ trông ra sao, tương tự như kerning
  • Đẹp quá! Tôi mong sẽ có thêm nhiều phông chữ chữ viết tay nối nét hơn nữa
    Đây là tác phẩm tôi làm cách đây 2 năm: https://certik.github.io/slabikar-otf/

  • Hay thật, nhưng giá như chữ của tôi đủ đẹp để đáng làm thành phông chữ của riêng mình :)
    Thay vì < 14.5, nếu đổi kích thước mặc định thành 200 thì có thể định nghĩa dấu chấm là 145, nhờ vậy bớt được một ký tự dấu thập phân
    Tôi thấy có một hàm tên adjust; tôi không rành đặc tả phông chữ, nhưng có lẽ có thể serialize 0,{x:12.2,y:13.2} thành dạng khác như 0,[12.2,13.2] rồi chuyển đổi trong hàm adjust chăng

    • Cũng như các kỹ năng khác, chữ viết tay có thể cải thiện chỉ với một chút nỗ lực