///|
pub(all) enum ReportFormat {
ReportText
ReportJson
} derive(Eq, @debug.Debug)
///|
pub(all) struct AssetReport {
parse_ok : Bool
validation_ok : Bool
frame_count : Int
tag_count : Int
slice_count : Int
layer_count : Int
duration_ms : Int
fps : Int
manifest_bytes : Int
message : String
} derive(Eq, @debug.Debug)
///|
pub fn AssetReport::empty() -> AssetReport {
{
parse_ok: false,
validation_ok: false,
frame_count: 0,
tag_count: 0,
slice_count: 0,
layer_count: 0,
duration_ms: 0,
fps: 0,
manifest_bytes: 0,
message: "",
}
}
///|
pub fn analyze_sprite_sheet_json(input : String) -> AssetReport {
let parsed = parse_sprite_sheet_json(input)
if !parsed.ok {
{ ..AssetReport::empty(), message: parsed.error.message }
} else {
let validation = validate_sprite_sheet(parsed.sheet)
let manifest = export_runtime_manifest(parsed.sheet)
{
parse_ok: true,
validation_ok: validation.ok,
frame_count: parsed.sheet.frames.length(),
tag_count: parsed.sheet.meta.frame_tags.length(),
slice_count: parsed.sheet.meta.slices.length(),
layer_count: parsed.sheet.meta.layers.length(),
duration_ms: parsed.sheet.duration_ms(),
fps: infer_frame_rate(parsed.sheet),
manifest_bytes: manifest.length(),
message: validation.summary(),
}
}
}
///|
pub fn asset_report_from_json(
input : String,
format? : ReportFormat = ReportText,
) -> String {
let parsed = parse_sprite_sheet_json(input)
if !parsed.ok {
format_parse_error(parsed.error, format)
} else {
let validation = validate_sprite_sheet(parsed.sheet)
let library = build_animation_library(parsed.sheet)
let boxes = build_frame_box_table(parsed.sheet)
let manifest = export_runtime_manifest_from_parts(
parsed.sheet,
library,
boxes,
)
match format {
ReportText =>
render_text_report(parsed.sheet, validation, library, boxes, manifest)
ReportJson =>
render_json_report(parsed.sheet, validation, library, boxes, manifest)
}
}
}
///|
fn format_parse_error(error : PixelAnimError, format : ReportFormat) -> String {
match format {
ReportText =>
"MoonPixelAnimKit report\nparse: failed\nerror: \{error.message}"
ReportJson =>
"{" +
"\"parse\":\"failed\"," +
"\"error\":" +
json_quote(error.message) +
"," +
"\"code\":" +
json_quote(error.code()) +
"}"
}
}
///|
fn render_text_report(
sheet : SpriteSheet,
validation : ValidationReport,
library : AnimationLibrary,
boxes : FrameBoxTable,
manifest : String,
) -> String {
let lines : Array[String] = []
lines.push("MoonPixelAnimKit asset report")
lines.push("parse: ok")
lines.push("validation: " + validation.summary())
lines.push("image: " + sheet.meta.image)
lines.push("atlas: \{sheet.meta.size.width}x\{sheet.meta.size.height}")
lines.push("frames: \{sheet.frames.length()}")
lines.push("tags: \{sheet.meta.frame_tags.length()}")
lines.push("layers: \{sheet.meta.layers.length()}")
lines.push("slices: \{sheet.meta.slices.length()}")
lines.push("duration: \{sheet.duration_ms()} ms")
lines.push("estimated fps: \{infer_frame_rate(sheet)}")
lines.push("runtime clips: \{library.clips.length()}")
lines.push("runtime boxes: \{boxes.boxes.length()}")
lines.push("manifest bytes: \{manifest.length()}")
if validation.issues.length() > 0 {
lines.push("issues:")
for issue in validation.issues {
lines.push(
"- [" +
issue.severity.to_string() +
"] " +
issue.code +
" " +
issue.path +
": " +
issue.message,
)
}
}
join_strings(lines, "\n")
}
///|
fn render_json_report(
sheet : SpriteSheet,
validation : ValidationReport,
library : AnimationLibrary,
boxes : FrameBoxTable,
manifest : String,
) -> String {
"{" +
"\"parse\":\"ok\"," +
"\"validation\":" +
json_quote(if validation.ok { "ok" } else { "failed" }) +
"," +
"\"image\":" +
json_quote(sheet.meta.image) +
"," +
"\"atlas\":" +
size_to_json(sheet.meta.size) +
"," +
"\"frames\":\{sheet.frames.length()}," +
"\"tags\":\{sheet.meta.frame_tags.length()}," +
"\"layers\":\{sheet.meta.layers.length()}," +
"\"slices\":\{sheet.meta.slices.length()}," +
"\"duration\":\{sheet.duration_ms()}," +
"\"fps\":\{infer_frame_rate(sheet)}," +
"\"clips\":\{library.clips.length()}," +
"\"boxes\":\{boxes.boxes.length()}," +
"\"manifestBytes\":\{manifest.length()}," +
"\"issues\":\{validation.issues.length()}" +
"}"
}
///|
pub fn ase_binary_report(
bytes : Array[Int],
format? : ReportFormat = ReportText,
) -> String {
let parsed = parse_aseprite_binary(bytes)
if !parsed.ok {
format_parse_error(parsed.error, format)
} else {
let validation = validate_ase_file(parsed.file)
match format {
ReportText => render_ase_text_report(parsed.file, validation)
ReportJson => render_ase_json_report(parsed.file, validation)
}
}
}
///|
fn render_ase_text_report(
file : AseFile,
validation : ValidationReport,
) -> String {
let lines : Array[String] = []
lines.push("MoonPixelAnimKit ASE report")
lines.push("parse: ok")
lines.push("validation: " + validation.summary())
lines.push("canvas: \{file.header.width}x\{file.header.height}")
lines.push("frames: \{file.frames.length()}")
lines.push("color depth: \{file.header.color_depth}")
lines.push("chunks: \{file.chunk_count()}")
lines.push("compressed cels: \{ase_has_compressed_cels(file)}")
join_strings(lines, "\n")
}
///|
fn render_ase_json_report(
file : AseFile,
validation : ValidationReport,
) -> String {
"{" +
"\"parse\":\"ok\"," +
"\"validation\":" +
json_quote(if validation.ok { "ok" } else { "failed" }) +
"," +
"\"width\":\{file.header.width}," +
"\"height\":\{file.header.height}," +
"\"frames\":\{file.frames.length()}," +
"\"colorDepth\":\{file.header.color_depth}," +
"\"chunks\":\{file.chunk_count()}," +
"\"compressedCels\":\{ase_has_compressed_cels(file)}" +
"}"
}