1+ import ExifReader from "exifreader" ;
2+ import { NodeExecution , NodeType } from "@dafthunk/types" ;
3+
4+ import {
5+ ExecutableNode ,
6+ ImageParameter ,
7+ NodeContext ,
8+ } from "../types" ;
9+
10+ /**
11+ * Extracts EXIF data from an image using the ExifReader library.
12+ */
13+ export class ExifReaderNode extends ExecutableNode {
14+ public static readonly nodeType : NodeType = {
15+ id : "exif-reader" ,
16+ name : "EXIF Reader" ,
17+ type : "exif-reader" ,
18+ description : "Extracts EXIF data from an image." ,
19+ category : "Image" ,
20+ icon : "file-text" , // Using 'file-text' as an icon, similar to info.
21+ inputs : [
22+ {
23+ name : "image" ,
24+ type : "image" ,
25+ description : "The input image to extract EXIF data from." ,
26+ required : true ,
27+ } ,
28+ ] ,
29+ outputs : [
30+ {
31+ name : "exifData" ,
32+ type : "json" , // Outputting as a JSON string
33+ description : "EXIF data extracted from the image as a JSON string." ,
34+ } ,
35+ {
36+ name : "imagePassthrough" ,
37+ type : "image" ,
38+ description :
39+ "The original image, passed through for further processing." ,
40+ } ,
41+ ] ,
42+ } ;
43+
44+ async execute ( context : NodeContext ) : Promise < NodeExecution > {
45+ const inputs = context . inputs as {
46+ image ?: ImageParameter ;
47+ } ;
48+
49+ const { image } = inputs ;
50+
51+ if ( ! image || ! image . data ) {
52+ return this . createErrorResult ( "Input image is missing or invalid." ) ;
53+ }
54+
55+ try {
56+ // ExifReader.load() expects a Buffer or ArrayBuffer.
57+ // Assuming image.data is Uint8Array, its .buffer property is ArrayBuffer.
58+ const tags = await ExifReader . load ( image . data . buffer ) ;
59+
60+ // Remove potentially very large MakerNote tag to avoid large JSON output
61+ if ( tags [ "MakerNote" ] ) {
62+ delete tags [ "MakerNote" ] ;
63+ }
64+ // Also remove thumbnail data if present
65+ // Add type assertion to handle complex type of tags["thumbnail"]
66+ const thumbnailTag = tags [ "thumbnail" ] as any ;
67+ if ( thumbnailTag && thumbnailTag . image ) {
68+ delete thumbnailTag . image ;
69+ }
70+
71+
72+ // Convert tags to a JSON string.
73+ // BigInt values need to be handled for JSON.stringify
74+ const replacer = ( _key : string , value : any ) =>
75+ typeof value === "bigint" ? value . toString ( ) : value ;
76+ const exifDataJson = JSON . stringify ( tags , replacer , 2 ) ;
77+
78+ console . log ( exifDataJson ) ;
79+
80+ return this . createSuccessResult ( {
81+ exifData : exifDataJson ,
82+ imagePassthrough : image ,
83+ } ) ;
84+ } catch ( error ) {
85+ const errorMessage =
86+ error instanceof Error
87+ ? error . message
88+ : "Unknown error during EXIF data extraction." ;
89+ console . error ( `[ExifReaderNode] Error: ${ errorMessage } ` , error ) ;
90+ if ( error instanceof Error && error . message . includes ( "No Exif data" ) ) {
91+ return this . createSuccessResult ( {
92+ exifData : "{}" , // Return empty JSON if no EXIF data found
93+ imagePassthrough : image ,
94+ } ) ;
95+ }
96+ return this . createErrorResult ( errorMessage ) ;
97+ }
98+ }
99+ }
0 commit comments