Skip to content

Commit

Permalink
feat: preview ps24 with image
Browse files Browse the repository at this point in the history
  • Loading branch information
Xiphoseer committed Jan 11, 2025
1 parent 2f37ec9 commit a882ea4
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 89 deletions.
4 changes: 2 additions & 2 deletions crates/sdo-web/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use signum::raster;
use wasm_bindgen::JsValue;
use web_sys::Blob;

use crate::glue::slice_to_blob;
use crate::glue::{js_error_with_cause, slice_to_blob};

/// Convert a raster page to a PNG image blob
pub(super) fn page_to_blob(page: &raster::Page) -> Result<Blob, JsValue> {
let mut buffer = Cursor::new(Vec::<u8>::new());
page.to_alpha_image()
.write_to(&mut buffer, ImageOutputFormat::Png)
.unwrap();
.map_err(|e| js_error_with_cause(e, "Failed to encode image as PNG"))?;
let bytes: &[u8] = buffer.get_ref();
slice_to_blob(bytes, "image/png")
}
6 changes: 6 additions & 0 deletions crates/sdo-web/src/glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,9 @@ pub(crate) fn slice_to_blob(bytes: &[u8], mime_type: &str) -> Result<Blob, JsVal
bag
})
}

pub(crate) fn js_error_with_cause<E: std::error::Error>(e: E, message: &str) -> js_sys::Error {
let err = js_sys::Error::new(message);
err.set_cause(&JsError::from(e).into());
err
}
189 changes: 104 additions & 85 deletions crates/sdo-web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use bstr::BStr;
use convert::page_to_blob;
use dom::blob_image_el;
use glue::{js_file_data, js_input_files_iter, slice_to_blob};
use glue::{js_error_with_cause, js_file_data, js_input_files_iter, slice_to_blob};
use js_sys::{Array, JsString, Uint8Array};
use log::{info, warn, Level};
use sdo_pdf::{generate_pdf, MetaInfo};
Expand All @@ -13,7 +13,7 @@ use signum::{
cache::{AsyncIterator, ChsetCache, VfsDirEntry, VFS},
editor::{parse_eset, ESet},
encoding::decode_atari_str,
printer::parse_ps24,
printer::{parse_ps24, PSet},
FontKind,
},
docs::{
Expand All @@ -24,7 +24,7 @@ use signum::{
tebu::PageText,
DocumentInfo, GenerationContext, Overrides, SDoc,
},
raster::{self, render_doc_page, render_editor_text},
raster::{self, render_doc_page, render_editor_text, render_printer_char},
util::FourCC,
};
use std::{ffi::OsStr, fmt::Write, io::BufWriter};
Expand Down Expand Up @@ -290,92 +290,83 @@ impl Handle {
}

fn parse_eset<'a>(&self, data: &'a [u8]) -> Result<ESet<'a>, JsValue> {
match parse_eset(data) {
Ok((_, eset)) => Ok(eset),
Err(e) => {
log::error!("Failed to parse editor font: {}", e);
Err(JsError::new("Failed to parse editor font").into())
let (_, eset) =
parse_eset(data).map_err(|e| js_error_with_cause(e, "Failed to parse editor font"))?;
Ok(eset)
}

fn parse_ps24<'a>(&mut self, data: &'a [u8]) -> Result<PSet<'a>, JsValue> {
let (_, pset) = parse_ps24(data)
.map_err(|e| js_error_with_cause(e, "Failed to parse printer font (24-needle)"))?;
Ok(pset)
}

fn _show_ps24(&mut self, pset: &PSet<'_>) -> Result<(), JsValue> {
let el_table = self.document.create_element("table")?;
self.output.append_child(&el_table)?;
for crow in pset.chars.chunks(16) {
let el_tr = self.document.create_element("tr")?;
el_table.append_child(&el_tr)?;
for c in crow {
//log::info!("Char {:x}{:x} {}x{}", rdx, idx, c.width, c.height);
let el_td = self.document.create_element("td")?;
el_tr.append_child(&el_td)?;
if c.height > 0 {
let page = raster::Page::from(c);
let blob = page_to_blob(&page)?;
let img_el = blob_image_el(&blob)?;
el_td.append_child(&img_el)?;
}
}
}
}

fn _parse_ps24(&mut self, data: &[u8]) -> Result<(), JsValue> {
log::info!("Signum 24-Needle Printer Bitmap Font");
match parse_ps24(data) {
Ok((_, pset)) => {
log::info!("Parsed Printer Font");
let el_table = self.document.create_element("table")?;
self.output.append_child(&el_table)?;
for crow in pset.chars.chunks(16) {
let el_tr = self.document.create_element("tr")?;
el_table.append_child(&el_tr)?;
for c in crow {
//log::info!("Char {:x}{:x} {}x{}", rdx, idx, c.width, c.height);
let el_td = self.document.create_element("td")?;
el_tr.append_child(&el_td)?;
if c.height > 0 {
let page = raster::Page::from(c);
let blob = page_to_blob(&page)?;
let img_el = blob_image_el(&blob)?;
el_td.append_child(&img_el)?;
}
}
}

let char_capital_a = &pset.chars[b'A' as usize];
let page = raster::Page::from(char_capital_a);
let blob = page_to_blob(&page)?;

let window = window().ok_or("expected window")?;
let _p = window.create_image_bitmap_with_blob(&blob)?;

let canvas = self
.document
.create_element("canvas")?
.dyn_into::<HtmlCanvasElement>()?;
canvas.set_width(700);
canvas.set_height(900);
self.output.append_child(&canvas)?;
let ctx = canvas
.get_context("2d")?
.ok_or("context")?
.dyn_into::<CanvasRenderingContext2d>()?;

let callback = Closure::new(move |_v: JsValue| {
let img = _v.dyn_into::<ImageBitmap>().unwrap();
let w = img.width() * 10;
let h = img.height() * 10;
ctx.set_fill_style_str("green");
//ctx.fill_rect(0.0, 0.0, 150.0, 100.0);
ctx.draw_image_with_image_bitmap_and_dw_and_dh(
&img, 10.0, 10.0, w as f64, h as f64,
)
.unwrap();

// Implement the rest of https://potrace.sourceforge.net/potrace.pdf
for (x, y) in page.vertices() {
ctx.fill_rect((9 + x * 10) as f64, (9 + y * 10) as f64, 2.0, 2.0);
}
let char_capital_a = &pset.chars[b'A' as usize];
let page = raster::Page::from(char_capital_a);
let blob = page_to_blob(&page)?;

ctx.set_stroke_style_str("blue");
if let Some(mut iter) = page.first_outline() {
log_val("Test", &JsValue::TRUE);
let (x0, y0) = iter.next().unwrap();
ctx.begin_path();
ctx.move_to((10 + x0 * 10) as f64, (10 + y0 * 10) as f64);
for (x, y) in iter {
ctx.line_to((10 + x * 10) as f64, (10 + y * 10) as f64);
}
ctx.stroke();
}
});
let _ = _p.then(&callback);
self.closures.push(callback);
let window = window().ok_or("expected window")?;
let _p = window.create_image_bitmap_with_blob(&blob)?;

let canvas = self
.document
.create_element("canvas")?
.dyn_into::<HtmlCanvasElement>()?;
canvas.set_width(700);
canvas.set_height(900);
self.output.append_child(&canvas)?;
let ctx = canvas
.get_context("2d")?
.ok_or("context")?
.dyn_into::<CanvasRenderingContext2d>()?;

let callback = Closure::new(move |_v: JsValue| {
let img = _v.dyn_into::<ImageBitmap>().unwrap();
let w = img.width() * 10;
let h = img.height() * 10;
ctx.set_fill_style_str("green");
//ctx.fill_rect(0.0, 0.0, 150.0, 100.0);
ctx.draw_image_with_image_bitmap_and_dw_and_dh(&img, 10.0, 10.0, w as f64, h as f64)
.unwrap();

// Implement the rest of https://potrace.sourceforge.net/potrace.pdf
for (x, y) in page.vertices() {
ctx.fill_rect((9 + x * 10) as f64, (9 + y * 10) as f64, 2.0, 2.0);
}
Err(e) => {
log::error!("Failed to parse printer font: {}", e);

ctx.set_stroke_style_str("blue");
if let Some(mut iter) = page.first_outline() {
log_val("Test", &JsValue::TRUE);
let (x0, y0) = iter.next().unwrap();
ctx.begin_path();
ctx.move_to((10 + x0 * 10) as f64, (10 + y0 * 10) as f64);
for (x, y) in iter {
ctx.line_to((10 + x * 10) as f64, (10 + y * 10) as f64);
}
ctx.stroke();
}
}
});
let _ = _p.then(&callback);
self.closures.push(callback);
Ok(())
}

Expand Down Expand Up @@ -578,6 +569,7 @@ impl Handle {

#[wasm_bindgen(js_name = onChange)]
pub async fn on_change(&mut self) -> Result<(), JsValue> {
self.reset()?;
for file in js_input_files_iter(&self.input)? {
let file = file?;
let arr = js_file_data(&file).await?;
Expand Down Expand Up @@ -609,12 +601,16 @@ impl Handle {
self.sdoc_card(card, &doc).await?;
}
FourCC::ESET => {
log::info!("{}: Signum Editor Bitmap Font", name);
log::info!("{name}: Signum Editor Bitmap Font");
let eset = self.parse_eset(data)?;
log::info!("{name}: Parsed editor font");
self.eset_card(card, &eset, name)?;
}
FourCC::PS24 => {
// self.parse_ps24(&data)
log::info!("{name}: Signum 24-Needle Printer Bitmap Font");
let pset = self.parse_ps24(data)?;
log::info!("{name}: Parsed printer font (24 needle)");
self.pset_card(card, &pset, name)?;
}
k => {
log::warn!("Unknown File Format '{}'", k);
Expand Down Expand Up @@ -677,6 +673,29 @@ impl Handle {
Ok(())
}

fn pset_card(
&mut self,
list_item: &Element,
pset: &PSet<'_>,
name: &str,
) -> Result<(), JsValue> {
let ch = name
.chars()
.next()
.and_then(|c| c.try_into().ok())
.unwrap_or(b'A');
let page = render_printer_char(ch, pset)
.ok_or_else(|| JsError::new("Failed to render printer char"))?;
let (width, height) = (page.bit_width(), page.bit_height());
log::trace!("Page generated ({width}x{height})");
if width > 0 && height > 0 {
let blob = page_to_blob(&page)?;
let img = blob_image_el(&blob)?;
list_item.append_child(&img)?;
}
Ok(())
}

async fn sdoc_card(&mut self, list_item: &Element, doc: &SDoc<'_>) -> Result<(), JsValue> {
let header_info = self.document.create_element("div")?;
header_info.class_list().add_1("mb-2")?;
Expand Down
8 changes: 7 additions & 1 deletion crates/signum/src/raster/font.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bstr::BStr;

use crate::chsets::editor::ESet;
use crate::chsets::{editor::ESet, printer::PSet};

use super::{DrawPrintErr, Page};

Expand Down Expand Up @@ -30,3 +30,9 @@ pub fn render_editor_text(text: &BStr, eset: &ESet) -> Result<Page, DrawPrintErr
}
Ok(page)
}

/// Get a character from a page
pub fn render_printer_char(char: u8, pset: &PSet<'_>) -> Option<Page> {
let pchar = pset.chars.get(char as usize)?;
Some(Page::from(pchar))
}
2 changes: 1 addition & 1 deletion crates/signum/src/raster/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod trace;
mod util;

pub use doc::render_doc_page;
pub use font::render_editor_text;
pub use font::{render_editor_text, render_printer_char};
pub use page::Page;
pub use trace::{straight_up_to, Dir};

Expand Down
10 changes: 10 additions & 0 deletions crates/signum/src/raster/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ impl Page {
}
}

/// The width in B/W pixels
pub fn bit_width(&self) -> u32 {
self.width
}

/// The height in B/W pixels
pub fn bit_height(&self) -> u32 {
self.height
}

/// Return the number of bytes per line
pub fn bytes_per_line(&self) -> u32 {
self.bytes_per_line
Expand Down

0 comments on commit a882ea4

Please sign in to comment.