feat: implement comprehensive ANSI/NIST support (NIEM XML & Traditional)#145
Conversation
Drawcris
left a comment
There was a problem hiding this comment.
All code review feedback has been addressed. Added i18n, normalized minutiae angles, optimized XML queries, and pinned the WSQ library version.
DGrygierczyk
left a comment
There was a problem hiding this comment.
Few comments from my side. Feel free to disagree or resolve if not applicable as im not really deep into this repository
| const { source } = sprite.texture.baseTexture.resource; | ||
| if (source) { | ||
| ctx.drawImage(source, 0, 0); | ||
| return canvas.toDataURL("image/jpeg").split(",")[1] ?? null; |
There was a problem hiding this comment.
image is exported as lossy JPEG - this bakes compression artifacts into evidence-grade fingerprint data. Use lossless PNG (the load path already decodes PNG):
return canvas.toDataURL("image/png").split(",")[1] ?? null;| angleDeg = ((Math.round(angleDeg) % 360) + 360) % 360; | ||
|
|
||
| let categoryCode = "UNK"; | ||
| if (m.typeId === "e6cbde52-5a18-4236-8287-7a1daf941ba9") { |
There was a problem hiding this comment.
These two UUIDs are duplicated from autoMarkWithSourceafis.ts, where they already exist as TYPE_ID_RIDGE_ENDING / TYPE_ID_BIFURCATION (just not exported). Export them at the source and import here so the ids can't drift:
// autoMarkWithSourceafis.ts
export const TYPE_ID_RIDGE_ENDING = "e6cbde52-5a18-4236-8287-7a1daf941ba9";
export const TYPE_ID_BIFURCATION = "f47c4b97-2d62-4959-aa21-edebfa7a756a";|
|
||
| while (pos < buffer.length) { | ||
| const { len, rType, isTagValue } = getRecordInfo(buffer, pos); | ||
| if (len <= 0 || pos + len > buffer.length) break; |
There was a problem hiding this comment.
If the length field is malformed, parseInt returns NaN. NaN <= 0 is false, so this guard passes, then pos += len makes pos NaN and the loop exits - silently dropping every remaining record. Add a finite check:
if (!Number.isFinite(len) || len <= 0 || pos + len > buffer.length) break;| } | ||
|
|
||
| if (minutiaeNodes.length > 0) { | ||
| const importedMarkings = minutiaeNodes.map((node, index) => { |
There was a problem hiding this comment.
This minutiae→RayMarking mapping (coord parsing, the (angleDeg - 90) * π/180 conversion, type resolution + fallback id) is duplicated in loadTraditionalAnsiNistWithDialog.ts. Extract a shared helper so the angle/type logic lives in one place and can't diverge.
| const defaultMarkingsFilePath = `${filePath}.json`; | ||
| if (await exists(defaultMarkingsFilePath)) { | ||
| await loadMarkingsData(defaultMarkingsFilePath, canvasId); | ||
| if (typeof filePathOrData === "string") { |
There was a problem hiding this comment.
Both branches run the same reset trio when no markings file applies. Collapse to one path:
const markingsPath =
typeof filePathOrData === "string" ? `${filePathOrData}.json` : null;
if (markingsPath && (await exists(markingsPath))) {
await loadMarkingsData(markingsPath, canvasId);
} else {
MarkingsStore(canvasId).actions.markings.reset();
MarkingsStore(canvasId).actions.labelGenerator.reset();
MarkingsStore(getOppositeCanvasId(canvasId)).actions.labelGenerator.reset();
}| const typeId = | ||
| resolveSourceafisTypeId(typeStr) || | ||
| MarkingTypesStore.state.types[0]?.id || | ||
| "unknown-type-id"; |
There was a problem hiding this comment.
Fallback id is "unknown-type-id" here but "unknown" in the traditional loader - both are invalid ids that yield markings the UI can't categorize. Pick one real default (e.g. first configured marking type) and use it consistently, or skip the minutia.
| /** | ||
| * Parses fields within a record buffer. | ||
| */ |
There was a problem hiding this comment.
do we need all of those comments for those lines and all of the below ones? the method names and return values should be descriptive enough for all devs to quickly get a grasp what the method do (which for me they are). Not sure what is the convention in repo so @Drawcris and @TheMultii feel free to disagree on that one. Some of them such as the one in line 117 etc. are fine as they are describing not descriptive things but rest of them for me is just a bloat
There was a problem hiding this comment.
I've got a fairly large branch, just waiting for the semester to be over. It removes all those unnecessary comments (emojis included - along with some other stuff). Adding new ones at this point is pointless for me, especially when they add zero value and the functions are self-explanatory anyway.
|
All feedback from the code review has been addressed. I switched the image export to lossless PNG, deduplicated the UUID constants, extracted a shared minutiae mapping helper, added a safety check for malformed record lengths to prevent infinite loops, and consolidated the reset logic. |
|
@Drawcris resolve conflicts |
|
@TheMultii Conflicts have been resolved. |
Key Features Added
1. Modern XML (NIEM) Support
2. Legacy Traditional Binary Support (.an2 / .eft)
3. Image Decoding & Biometric Overlay
@li0ard/wsq.4. UI/UX Improvements
Technical Changes
loadAnsiNistWithDialog.tsandloadTraditionalAnsiNistWithDialog.tsfor specialized loading logic.canvas-header.tsxand translation files.Verification
.an2files containing compressed WSQ and raw grayscale images.