@enslo/sd-metadata 1.4.1 → 1.4.2
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.
- package/README.md +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.js +74 -123
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -153,7 +153,7 @@ if (result.status === 'success') {
|
|
|
153
153
|
> For production use, pin to a specific version instead of `@latest`:
|
|
154
154
|
>
|
|
155
155
|
> ```text
|
|
156
|
-
> https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@1.4.
|
|
156
|
+
> https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@1.4.2/dist/index.js
|
|
157
157
|
> ```
|
|
158
158
|
|
|
159
159
|
### Advanced Examples
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -345,6 +345,12 @@ function detectFromCommentJson(comment) {
|
|
|
345
345
|
if ("invokeai_metadata" in parsed) {
|
|
346
346
|
return "invokeai";
|
|
347
347
|
}
|
|
348
|
+
if ("generation_data" in parsed) {
|
|
349
|
+
return "tensorart";
|
|
350
|
+
}
|
|
351
|
+
if ("smproj" in parsed) {
|
|
352
|
+
return "stability-matrix";
|
|
353
|
+
}
|
|
348
354
|
if ("prompt" in parsed && "workflow" in parsed) {
|
|
349
355
|
const workflow = parsed.workflow;
|
|
350
356
|
const prompt = parsed.prompt;
|
|
@@ -574,7 +580,7 @@ function parseFooocus(entries) {
|
|
|
574
580
|
// src/parsers/hf-space.ts
|
|
575
581
|
function parseHfSpace(entries) {
|
|
576
582
|
const entryRecord = buildEntryRecord(entries);
|
|
577
|
-
const parametersText = entryRecord.parameters;
|
|
583
|
+
const parametersText = entryRecord.parameters ?? entryRecord.Comment;
|
|
578
584
|
if (!parametersText) {
|
|
579
585
|
return Result.error({ type: "unsupportedFormat" });
|
|
580
586
|
}
|
|
@@ -727,7 +733,7 @@ function parseNovelAI(entries) {
|
|
|
727
733
|
// src/parsers/ruined-fooocus.ts
|
|
728
734
|
function parseRuinedFooocus(entries) {
|
|
729
735
|
const entryRecord = buildEntryRecord(entries);
|
|
730
|
-
const jsonText = entryRecord.parameters;
|
|
736
|
+
const jsonText = entryRecord.parameters ?? entryRecord.Comment;
|
|
731
737
|
if (!jsonText || !jsonText.startsWith("{")) {
|
|
732
738
|
return Result.error({ type: "unsupportedFormat" });
|
|
733
739
|
}
|
|
@@ -775,7 +781,20 @@ function parseStabilityMatrix(entries) {
|
|
|
775
781
|
...comfyResult.value,
|
|
776
782
|
software: "stability-matrix"
|
|
777
783
|
};
|
|
778
|
-
|
|
784
|
+
let jsonText = entryRecord["parameters-json"];
|
|
785
|
+
if (!jsonText && entryRecord.Comment?.startsWith("{")) {
|
|
786
|
+
const commentParsed = parseJson(
|
|
787
|
+
entryRecord.Comment
|
|
788
|
+
);
|
|
789
|
+
if (commentParsed.ok) {
|
|
790
|
+
const commentData = commentParsed.value;
|
|
791
|
+
if (typeof commentData["parameters-json"] === "string") {
|
|
792
|
+
jsonText = commentData["parameters-json"];
|
|
793
|
+
} else if (typeof commentData["parameters-json"] === "object") {
|
|
794
|
+
jsonText = JSON.stringify(commentData["parameters-json"]);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
779
798
|
if (jsonText) {
|
|
780
799
|
const parsed = parseJson(jsonText);
|
|
781
800
|
if (parsed.ok) {
|
|
@@ -874,7 +893,26 @@ function parseSwarmUI(entries) {
|
|
|
874
893
|
// src/parsers/tensorart.ts
|
|
875
894
|
function parseTensorArt(entries) {
|
|
876
895
|
const entryRecord = buildEntryRecord(entries);
|
|
877
|
-
|
|
896
|
+
let dataText = entryRecord.generation_data;
|
|
897
|
+
let promptChunk = entryRecord.prompt;
|
|
898
|
+
if (!dataText && entryRecord.Comment?.startsWith("{")) {
|
|
899
|
+
const commentParsed = parseJson(
|
|
900
|
+
entryRecord.Comment
|
|
901
|
+
);
|
|
902
|
+
if (commentParsed.ok) {
|
|
903
|
+
const commentData = commentParsed.value;
|
|
904
|
+
if (typeof commentData.generation_data === "string") {
|
|
905
|
+
dataText = commentData.generation_data;
|
|
906
|
+
} else if (typeof commentData.generation_data === "object") {
|
|
907
|
+
dataText = JSON.stringify(commentData.generation_data);
|
|
908
|
+
}
|
|
909
|
+
if (typeof commentData.prompt === "string") {
|
|
910
|
+
promptChunk = commentData.prompt;
|
|
911
|
+
} else if (typeof commentData.prompt === "object") {
|
|
912
|
+
promptChunk = JSON.stringify(commentData.prompt);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
878
916
|
if (!dataText) {
|
|
879
917
|
return Result.error({ type: "unsupportedFormat" });
|
|
880
918
|
}
|
|
@@ -889,7 +927,6 @@ function parseTensorArt(entries) {
|
|
|
889
927
|
const data = parsed.value;
|
|
890
928
|
const width = data.width ?? 0;
|
|
891
929
|
const height = data.height ?? 0;
|
|
892
|
-
const promptChunk = entryRecord.prompt;
|
|
893
930
|
if (!promptChunk) {
|
|
894
931
|
return Result.error({ type: "unsupportedFormat" });
|
|
895
932
|
}
|
|
@@ -1092,9 +1129,7 @@ function detectFormat(data) {
|
|
|
1092
1129
|
// src/utils/exif-constants.ts
|
|
1093
1130
|
var USER_COMMENT_TAG = 37510;
|
|
1094
1131
|
var IMAGE_DESCRIPTION_TAG = 270;
|
|
1095
|
-
var DOCUMENT_NAME_TAG = 269;
|
|
1096
1132
|
var MAKE_TAG = 271;
|
|
1097
|
-
var SOFTWARE_TAG = 305;
|
|
1098
1133
|
var EXIF_IFD_POINTER_TAG = 34665;
|
|
1099
1134
|
|
|
1100
1135
|
// src/readers/exif.ts
|
|
@@ -1152,22 +1187,6 @@ function extractTagsFromIfd(data, ifdOffset, isLittleEndian) {
|
|
|
1152
1187
|
data: prefix ? text.slice(prefix.length + 2) : text
|
|
1153
1188
|
});
|
|
1154
1189
|
}
|
|
1155
|
-
} else if (tag === SOFTWARE_TAG) {
|
|
1156
|
-
const text = decodeAsciiString(tagData);
|
|
1157
|
-
if (text) {
|
|
1158
|
-
segments.push({
|
|
1159
|
-
source: { type: "exifSoftware" },
|
|
1160
|
-
data: text
|
|
1161
|
-
});
|
|
1162
|
-
}
|
|
1163
|
-
} else if (tag === DOCUMENT_NAME_TAG) {
|
|
1164
|
-
const text = decodeAsciiString(tagData);
|
|
1165
|
-
if (text) {
|
|
1166
|
-
segments.push({
|
|
1167
|
-
source: { type: "exifDocumentName" },
|
|
1168
|
-
data: text
|
|
1169
|
-
});
|
|
1170
|
-
}
|
|
1171
1190
|
} else if (tag === USER_COMMENT_TAG) {
|
|
1172
1191
|
const text = decodeUserComment(tagData);
|
|
1173
1192
|
if (text) {
|
|
@@ -1618,10 +1637,6 @@ function sourceToKeyword(source) {
|
|
|
1618
1637
|
return source.prefix ?? "Description";
|
|
1619
1638
|
case "exifMake":
|
|
1620
1639
|
return source.prefix ?? "Make";
|
|
1621
|
-
case "exifSoftware":
|
|
1622
|
-
return "Software";
|
|
1623
|
-
case "exifDocumentName":
|
|
1624
|
-
return "Title";
|
|
1625
1640
|
}
|
|
1626
1641
|
}
|
|
1627
1642
|
|
|
@@ -1786,6 +1801,12 @@ function escapeUnicode(text) {
|
|
|
1786
1801
|
return `\\u${code}`;
|
|
1787
1802
|
});
|
|
1788
1803
|
}
|
|
1804
|
+
function unescapeUnicode(text) {
|
|
1805
|
+
return text.replace(
|
|
1806
|
+
/\\u([0-9a-fA-F]{4})/g,
|
|
1807
|
+
(_, hex) => String.fromCharCode(Number.parseInt(hex, 16))
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1789
1810
|
function hasNonLatin1(text) {
|
|
1790
1811
|
return /[^\x00-\xFF]/.test(text);
|
|
1791
1812
|
}
|
|
@@ -1812,70 +1833,19 @@ function convertA1111PngToSegments(chunks) {
|
|
|
1812
1833
|
if (!parameters) {
|
|
1813
1834
|
return [];
|
|
1814
1835
|
}
|
|
1815
|
-
|
|
1836
|
+
return [
|
|
1816
1837
|
{
|
|
1817
1838
|
source: { type: "exifUserComment" },
|
|
1818
1839
|
data: parameters.text
|
|
1819
1840
|
}
|
|
1820
1841
|
];
|
|
1821
|
-
const software = chunks.find((c) => c.keyword === "Software");
|
|
1822
|
-
if (software) {
|
|
1823
|
-
segments.push({
|
|
1824
|
-
source: { type: "exifSoftware" },
|
|
1825
|
-
data: software.text
|
|
1826
|
-
});
|
|
1827
|
-
}
|
|
1828
|
-
const title = chunks.find((c) => c.keyword === "Title");
|
|
1829
|
-
if (title) {
|
|
1830
|
-
segments.push({
|
|
1831
|
-
source: { type: "exifDocumentName" },
|
|
1832
|
-
data: title.text
|
|
1833
|
-
});
|
|
1834
|
-
}
|
|
1835
|
-
const description = chunks.find((c) => c.keyword === "Description");
|
|
1836
|
-
if (description) {
|
|
1837
|
-
segments.push({
|
|
1838
|
-
source: { type: "exifImageDescription" },
|
|
1839
|
-
data: description.text
|
|
1840
|
-
});
|
|
1841
|
-
}
|
|
1842
|
-
const make = chunks.find((c) => c.keyword === "Make");
|
|
1843
|
-
if (make) {
|
|
1844
|
-
segments.push({
|
|
1845
|
-
source: { type: "exifMake" },
|
|
1846
|
-
data: make.text
|
|
1847
|
-
});
|
|
1848
|
-
}
|
|
1849
|
-
return segments;
|
|
1850
1842
|
}
|
|
1851
1843
|
function convertA1111SegmentsToPng(segments) {
|
|
1852
1844
|
const userComment = segments.find((s) => s.source.type === "exifUserComment");
|
|
1853
1845
|
if (!userComment) {
|
|
1854
1846
|
return [];
|
|
1855
1847
|
}
|
|
1856
|
-
|
|
1857
|
-
"parameters",
|
|
1858
|
-
userComment.data,
|
|
1859
|
-
"dynamic"
|
|
1860
|
-
);
|
|
1861
|
-
const chunks = [...parametersChunks];
|
|
1862
|
-
const software = findSegment(segments, "exifSoftware");
|
|
1863
|
-
if (software) {
|
|
1864
|
-
chunks.push(...createTextChunk("Software", software.data));
|
|
1865
|
-
}
|
|
1866
|
-
const title = findSegment(segments, "exifDocumentName");
|
|
1867
|
-
if (title) {
|
|
1868
|
-
chunks.push(...createTextChunk("Title", title.data));
|
|
1869
|
-
}
|
|
1870
|
-
const description = findSegment(segments, "exifImageDescription");
|
|
1871
|
-
if (description) {
|
|
1872
|
-
chunks.push(...createTextChunk("Description", description.data));
|
|
1873
|
-
}
|
|
1874
|
-
const make = findSegment(segments, "exifMake");
|
|
1875
|
-
if (make) {
|
|
1876
|
-
chunks.push(...createTextChunk("Make", make.data));
|
|
1877
|
-
}
|
|
1878
|
-
return chunks;
|
|
1848
|
+
return createEncodedChunk("parameters", userComment.data, "dynamic");
|
|
1879
1849
|
}
|
|
1880
1850
|
|
|
1881
1851
|
// src/converters/base-json.ts
|
|
@@ -1905,9 +1875,14 @@ function convertKvSegmentsToPng(segments, encodingStrategy) {
|
|
|
1905
1875
|
if (!parsed.ok) {
|
|
1906
1876
|
return [];
|
|
1907
1877
|
}
|
|
1908
|
-
return Object.entries(parsed.value).flatMap(
|
|
1909
|
-
|
|
1910
|
-
|
|
1878
|
+
return Object.entries(parsed.value).flatMap(([keyword, value]) => {
|
|
1879
|
+
const text = stringify(value);
|
|
1880
|
+
return createEncodedChunk(
|
|
1881
|
+
keyword,
|
|
1882
|
+
text !== void 0 ? unescapeUnicode(text) : void 0,
|
|
1883
|
+
encodingStrategy
|
|
1884
|
+
);
|
|
1885
|
+
});
|
|
1911
1886
|
}
|
|
1912
1887
|
|
|
1913
1888
|
// src/converters/comfyui.ts
|
|
@@ -1930,7 +1905,7 @@ var tryParseExtendedFormat = (segments) => {
|
|
|
1930
1905
|
];
|
|
1931
1906
|
};
|
|
1932
1907
|
var tryParseSaveImagePlusFormat = (segments) => {
|
|
1933
|
-
const chunks = convertKvSegmentsToPng(segments, "text-
|
|
1908
|
+
const chunks = convertKvSegmentsToPng(segments, "text-utf8-raw");
|
|
1934
1909
|
return chunks.length > 0 ? chunks : null;
|
|
1935
1910
|
};
|
|
1936
1911
|
function convertComfyUISegmentsToPng(segments) {
|
|
@@ -1972,35 +1947,22 @@ function convertInvokeAISegmentsToPng(segments) {
|
|
|
1972
1947
|
}
|
|
1973
1948
|
|
|
1974
1949
|
// src/converters/novelai.ts
|
|
1975
|
-
var NOVELAI_SOFTWARE = "NovelAI";
|
|
1976
1950
|
var NOVELAI_TITLE = "NovelAI generated image";
|
|
1951
|
+
var NOVELAI_SOFTWARE = "NovelAI";
|
|
1977
1952
|
function convertNovelaiPngToSegments(chunks) {
|
|
1978
|
-
const data = buildUserCommentJson(chunks);
|
|
1979
|
-
const userCommentSegment = {
|
|
1980
|
-
source: { type: "exifUserComment" },
|
|
1981
|
-
data: JSON.stringify(data)
|
|
1982
|
-
};
|
|
1983
1953
|
const description = chunks.find((c) => c.keyword === "Description");
|
|
1984
1954
|
const descriptionSegment = description && {
|
|
1985
1955
|
source: { type: "exifImageDescription" },
|
|
1986
1956
|
data: `\0\0\0\0${description.text}`
|
|
1987
1957
|
};
|
|
1988
|
-
const
|
|
1989
|
-
const
|
|
1990
|
-
source: { type: "
|
|
1991
|
-
data:
|
|
1992
|
-
};
|
|
1993
|
-
const title = chunks.find((c) => c.keyword === "Title");
|
|
1994
|
-
const titleSegment = title && {
|
|
1995
|
-
source: { type: "exifDocumentName" },
|
|
1996
|
-
data: title.text
|
|
1958
|
+
const data = buildUserCommentJson(chunks);
|
|
1959
|
+
const userCommentSegment = {
|
|
1960
|
+
source: { type: "exifUserComment" },
|
|
1961
|
+
data: JSON.stringify(data)
|
|
1997
1962
|
};
|
|
1998
|
-
return [
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
softwareSegment,
|
|
2002
|
-
titleSegment
|
|
2003
|
-
].filter((segment) => Boolean(segment));
|
|
1963
|
+
return [descriptionSegment, userCommentSegment].filter(
|
|
1964
|
+
(segment) => segment !== void 0
|
|
1965
|
+
);
|
|
2004
1966
|
}
|
|
2005
1967
|
function buildUserCommentJson(chunks) {
|
|
2006
1968
|
return NOVELAI_KEY_ORDER.map((key) => {
|
|
@@ -2022,11 +1984,9 @@ var NOVELAI_KEY_ORDER = [
|
|
|
2022
1984
|
function convertNovelaiSegmentsToPng(segments) {
|
|
2023
1985
|
const userCommentSeg = findSegment(segments, "exifUserComment");
|
|
2024
1986
|
const descriptionSeg = findSegment(segments, "exifImageDescription");
|
|
2025
|
-
|
|
2026
|
-
const titleSeg = findSegment(segments, "exifDocumentName");
|
|
2027
|
-
return parseSegments(userCommentSeg, descriptionSeg, softwareSeg, titleSeg);
|
|
1987
|
+
return parseSegments(userCommentSeg, descriptionSeg);
|
|
2028
1988
|
}
|
|
2029
|
-
function parseSegments(userCommentSeg, descriptionSeg
|
|
1989
|
+
function parseSegments(userCommentSeg, descriptionSeg) {
|
|
2030
1990
|
if (!userCommentSeg || !descriptionSeg) {
|
|
2031
1991
|
return [];
|
|
2032
1992
|
}
|
|
@@ -2041,16 +2001,13 @@ function parseSegments(userCommentSeg, descriptionSeg, softwareSeg, titleSeg) {
|
|
|
2041
2001
|
);
|
|
2042
2002
|
return [
|
|
2043
2003
|
// Title (required, use default if missing)
|
|
2044
|
-
createTextChunk(
|
|
2045
|
-
"Title",
|
|
2046
|
-
titleSeg?.data ?? stringify(jsonData.Title) ?? NOVELAI_TITLE
|
|
2047
|
-
),
|
|
2004
|
+
createTextChunk("Title", stringify(jsonData.Title) ?? NOVELAI_TITLE),
|
|
2048
2005
|
// Description (optional, prefer exifImageDescription over JSON)
|
|
2049
2006
|
createEncodedChunk("Description", descriptionText, "dynamic"),
|
|
2050
2007
|
// Software (required, use default if missing)
|
|
2051
2008
|
createTextChunk(
|
|
2052
2009
|
"Software",
|
|
2053
|
-
|
|
2010
|
+
stringify(jsonData.Software) ?? NOVELAI_SOFTWARE
|
|
2054
2011
|
),
|
|
2055
2012
|
// Source (optional)
|
|
2056
2013
|
createTextChunk("Source", stringify(jsonData.Source)),
|
|
@@ -2234,7 +2191,7 @@ var softwareConverters = {
|
|
|
2234
2191
|
// src/writers/exif.ts
|
|
2235
2192
|
function buildExifTiffData(segments) {
|
|
2236
2193
|
const ifd0Segments = segments.filter(
|
|
2237
|
-
(s) => s.source.type === "exifImageDescription" || s.source.type === "exifMake"
|
|
2194
|
+
(s) => s.source.type === "exifImageDescription" || s.source.type === "exifMake"
|
|
2238
2195
|
);
|
|
2239
2196
|
const exifIfdSegments = segments.filter(
|
|
2240
2197
|
(s) => s.source.type === "exifUserComment"
|
|
@@ -2252,12 +2209,6 @@ function buildExifTiffData(segments) {
|
|
|
2252
2209
|
} else if (seg.source.type === "exifMake") {
|
|
2253
2210
|
const data = encodeAsciiTag(seg.data, seg.source.prefix);
|
|
2254
2211
|
ifd0Tags.push({ tag: MAKE_TAG, type: 2, data });
|
|
2255
|
-
} else if (seg.source.type === "exifSoftware") {
|
|
2256
|
-
const data = encodeAsciiTag(seg.data);
|
|
2257
|
-
ifd0Tags.push({ tag: SOFTWARE_TAG, type: 2, data });
|
|
2258
|
-
} else if (seg.source.type === "exifDocumentName") {
|
|
2259
|
-
const data = encodeAsciiTag(seg.data);
|
|
2260
|
-
ifd0Tags.push({ tag: DOCUMENT_NAME_TAG, type: 2, data });
|
|
2261
2212
|
}
|
|
2262
2213
|
}
|
|
2263
2214
|
for (const seg of exifIfdSegments) {
|
|
@@ -2385,7 +2336,7 @@ function writeJpegMetadata(data, segments) {
|
|
|
2385
2336
|
}
|
|
2386
2337
|
const comSegments = segments.filter((s) => s.source.type === "jpegCom");
|
|
2387
2338
|
const exifSegments = segments.filter(
|
|
2388
|
-
(s) => s.source.type === "exifUserComment" || s.source.type === "exifImageDescription" || s.source.type === "exifMake"
|
|
2339
|
+
(s) => s.source.type === "exifUserComment" || s.source.type === "exifImageDescription" || s.source.type === "exifMake"
|
|
2389
2340
|
);
|
|
2390
2341
|
const collectResult = collectNonMetadataSegments(data);
|
|
2391
2342
|
if (!collectResult.ok) {
|
|
@@ -2745,7 +2696,7 @@ function collectNonExifChunks(data) {
|
|
|
2745
2696
|
}
|
|
2746
2697
|
function buildExifChunk(segments) {
|
|
2747
2698
|
const exifSegments = segments.filter(
|
|
2748
|
-
(s) => s.source.type === "exifUserComment" || s.source.type === "exifImageDescription" || s.source.type === "exifMake"
|
|
2699
|
+
(s) => s.source.type === "exifUserComment" || s.source.type === "exifImageDescription" || s.source.type === "exifMake"
|
|
2749
2700
|
);
|
|
2750
2701
|
if (exifSegments.length === 0) {
|
|
2751
2702
|
return null;
|