@willwade/aac-processors 0.1.17 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,11 @@ import * as path from 'path';
4
4
  import Database from 'better-sqlite3';
5
5
  import { dotNetTicksToDate } from '../../utils/dotnetTicks';
6
6
  // Minimal Snap helpers (stubs) to align with processors/<engine>/helpers pattern
7
+ // NOTE: Snap files can store different types of image data in PageSetData:
8
+ // - PNG/JPEG binaries: Actual images that can be displayed
9
+ // - Vector graphics: Custom format (d7 cd c6 9a) requiring rendering engine
10
+ //
11
+ // We extract PNG/JPEG images but skip vector graphics (requires renderer).
7
12
  // NOTE: Snap buttons currently do not populate resolvedImageEntry; these helpers
8
13
  // therefore return empty collections until image resolution is implemented.
9
14
  function collectFiles(root, matcher, maxDepth = 3) {
@@ -105,6 +110,9 @@ export function openImage(dbOrFile, entryPath) {
105
110
  .prepare('SELECT Id, Identifier, Data FROM PageSetData WHERE Identifier = ?')
106
111
  .get(entryPath);
107
112
  if (row && row.Data && row.Data.length > 0) {
113
+ // Snap files can store different types of image data:
114
+ // 1. PNG/JPEG binaries (actual images) - return as-is
115
+ // 2. Vector graphics (custom format d7 cd c6 9a) - return but may not be displayable
108
116
  return row.Data;
109
117
  }
110
118
  return null;
@@ -15,41 +15,6 @@ function mapSnapVisibility(visible) {
15
15
  }
16
16
  return visible === 0 ? 'Hidden' : 'Visible';
17
17
  }
18
- /**
19
- * Detect image MIME type from binary data using magic bytes
20
- * @param buffer Image data buffer
21
- * @returns MIME type string (defaults to 'image/png' if unknown)
22
- */
23
- function detectImageMimeType(buffer) {
24
- if (!buffer || buffer.length < 8) {
25
- return 'image/png';
26
- }
27
- // Check for PNG: 89 50 4E 47 0D 0A 1A 0A
28
- if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47) {
29
- return 'image/png';
30
- }
31
- // Check for JPEG: FF D8 FF
32
- if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
33
- return 'image/jpeg';
34
- }
35
- // Check for GIF: 47 49 46 38 (GIF8)
36
- if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x38) {
37
- return 'image/gif';
38
- }
39
- // Check for WebP: 52 49 46 46 ... 57 45 42 50 (RIFF...WEBP)
40
- if (buffer[0] === 0x52 &&
41
- buffer[1] === 0x49 &&
42
- buffer[2] === 0x46 &&
43
- buffer[3] === 0x46 &&
44
- buffer[8] === 0x57 &&
45
- buffer[9] === 0x45 &&
46
- buffer[10] === 0x42 &&
47
- buffer[11] === 0x50) {
48
- return 'image/webp';
49
- }
50
- // Default to PNG
51
- return 'image/png';
52
- }
53
18
  class SnapProcessor extends BaseProcessor {
54
19
  constructor(symbolResolver = null, options = {}) {
55
20
  super(options);
@@ -465,14 +430,30 @@ class SnapProcessor extends BaseProcessor {
465
430
  `)
466
431
  .get(btnRow.PageSetImageId);
467
432
  if (imageData && imageData.Data && imageData.Data.length > 0) {
468
- const mimeType = detectImageMimeType(imageData.Data);
469
- const base64 = imageData.Data.toString('base64');
470
- buttonImage = `data:${mimeType};base64,${base64}`;
471
- buttonParameters.image_id = imageData.Identifier;
472
- // NOTE: We don't include imageData in parameters because Buffers don't serialize
473
- // correctly across server/client boundaries (Next.js SSR, JSON, etc.)
474
- // The data URL in buttonImage is sufficient for display purposes.
475
- // For conversions, images can be reloaded from the source file/database.
433
+ // Snap files can store different types of image data:
434
+ // 1. PNG/JPEG binaries (actual images) - extract and display
435
+ // 2. Vector graphics (custom format d7 cd c6 9a) - skip (requires renderer)
436
+ const data = imageData.Data;
437
+ // Check for PNG: 89 50 4E 47
438
+ const isPng = data.length > 4 &&
439
+ data[0] === 0x89 &&
440
+ data[1] === 0x50 &&
441
+ data[2] === 0x4e &&
442
+ data[3] === 0x47;
443
+ // Check for JPEG: FF D8 FF
444
+ const isJpeg = data.length > 3 && data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff;
445
+ if (isPng || isJpeg) {
446
+ // Actual PNG/JPEG image - can be displayed
447
+ const mimeType = isPng ? 'image/png' : 'image/jpeg';
448
+ const base64 = data.toString('base64');
449
+ buttonImage = `data:${mimeType};base64,${base64}`;
450
+ buttonParameters.image_id = imageData.Identifier;
451
+ }
452
+ else {
453
+ // Vector graphics or other format - skip rendering
454
+ // Store identifier but don't create image URL
455
+ buttonParameters.image_id = imageData.Identifier;
456
+ }
476
457
  }
477
458
  }
478
459
  catch (e) {
@@ -43,6 +43,11 @@ const path = __importStar(require("path"));
43
43
  const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
44
44
  const dotnetTicks_1 = require("../../utils/dotnetTicks");
45
45
  // Minimal Snap helpers (stubs) to align with processors/<engine>/helpers pattern
46
+ // NOTE: Snap files can store different types of image data in PageSetData:
47
+ // - PNG/JPEG binaries: Actual images that can be displayed
48
+ // - Vector graphics: Custom format (d7 cd c6 9a) requiring rendering engine
49
+ //
50
+ // We extract PNG/JPEG images but skip vector graphics (requires renderer).
46
51
  // NOTE: Snap buttons currently do not populate resolvedImageEntry; these helpers
47
52
  // therefore return empty collections until image resolution is implemented.
48
53
  function collectFiles(root, matcher, maxDepth = 3) {
@@ -144,6 +149,9 @@ function openImage(dbOrFile, entryPath) {
144
149
  .prepare('SELECT Id, Identifier, Data FROM PageSetData WHERE Identifier = ?')
145
150
  .get(entryPath);
146
151
  if (row && row.Data && row.Data.length > 0) {
152
+ // Snap files can store different types of image data:
153
+ // 1. PNG/JPEG binaries (actual images) - return as-is
154
+ // 2. Vector graphics (custom format d7 cd c6 9a) - return but may not be displayable
147
155
  return row.Data;
148
156
  }
149
157
  return null;
@@ -18,41 +18,6 @@ function mapSnapVisibility(visible) {
18
18
  }
19
19
  return visible === 0 ? 'Hidden' : 'Visible';
20
20
  }
21
- /**
22
- * Detect image MIME type from binary data using magic bytes
23
- * @param buffer Image data buffer
24
- * @returns MIME type string (defaults to 'image/png' if unknown)
25
- */
26
- function detectImageMimeType(buffer) {
27
- if (!buffer || buffer.length < 8) {
28
- return 'image/png';
29
- }
30
- // Check for PNG: 89 50 4E 47 0D 0A 1A 0A
31
- if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47) {
32
- return 'image/png';
33
- }
34
- // Check for JPEG: FF D8 FF
35
- if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
36
- return 'image/jpeg';
37
- }
38
- // Check for GIF: 47 49 46 38 (GIF8)
39
- if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x38) {
40
- return 'image/gif';
41
- }
42
- // Check for WebP: 52 49 46 46 ... 57 45 42 50 (RIFF...WEBP)
43
- if (buffer[0] === 0x52 &&
44
- buffer[1] === 0x49 &&
45
- buffer[2] === 0x46 &&
46
- buffer[3] === 0x46 &&
47
- buffer[8] === 0x57 &&
48
- buffer[9] === 0x45 &&
49
- buffer[10] === 0x42 &&
50
- buffer[11] === 0x50) {
51
- return 'image/webp';
52
- }
53
- // Default to PNG
54
- return 'image/png';
55
- }
56
21
  class SnapProcessor extends baseProcessor_1.BaseProcessor {
57
22
  constructor(symbolResolver = null, options = {}) {
58
23
  super(options);
@@ -468,14 +433,30 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
468
433
  `)
469
434
  .get(btnRow.PageSetImageId);
470
435
  if (imageData && imageData.Data && imageData.Data.length > 0) {
471
- const mimeType = detectImageMimeType(imageData.Data);
472
- const base64 = imageData.Data.toString('base64');
473
- buttonImage = `data:${mimeType};base64,${base64}`;
474
- buttonParameters.image_id = imageData.Identifier;
475
- // NOTE: We don't include imageData in parameters because Buffers don't serialize
476
- // correctly across server/client boundaries (Next.js SSR, JSON, etc.)
477
- // The data URL in buttonImage is sufficient for display purposes.
478
- // For conversions, images can be reloaded from the source file/database.
436
+ // Snap files can store different types of image data:
437
+ // 1. PNG/JPEG binaries (actual images) - extract and display
438
+ // 2. Vector graphics (custom format d7 cd c6 9a) - skip (requires renderer)
439
+ const data = imageData.Data;
440
+ // Check for PNG: 89 50 4E 47
441
+ const isPng = data.length > 4 &&
442
+ data[0] === 0x89 &&
443
+ data[1] === 0x50 &&
444
+ data[2] === 0x4e &&
445
+ data[3] === 0x47;
446
+ // Check for JPEG: FF D8 FF
447
+ const isJpeg = data.length > 3 && data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff;
448
+ if (isPng || isJpeg) {
449
+ // Actual PNG/JPEG image - can be displayed
450
+ const mimeType = isPng ? 'image/png' : 'image/jpeg';
451
+ const base64 = data.toString('base64');
452
+ buttonImage = `data:${mimeType};base64,${base64}`;
453
+ buttonParameters.image_id = imageData.Identifier;
454
+ }
455
+ else {
456
+ // Vector graphics or other format - skip rendering
457
+ // Store identifier but don't create image URL
458
+ buttonParameters.image_id = imageData.Identifier;
459
+ }
479
460
  }
480
461
  }
481
462
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@willwade/aac-processors",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "A comprehensive TypeScript library for processing AAC (Augmentative and Alternative Communication) file formats with translation support",
5
5
  "main": "dist/index.js",
6
6
  "browser": "dist/browser/index.browser.js",