@enslo/sd-metadata 1.4.0 → 1.4.1
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.ja.md +1 -1
- package/README.md +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +158 -169
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -153,7 +153,7 @@ if (result.status === 'success') {
|
|
|
153
153
|
> 本番環境では `@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.1/dist/index.js
|
|
157
157
|
> ```
|
|
158
158
|
|
|
159
159
|
### 応用例
|
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.1/dist/index.js
|
|
157
157
|
> ```
|
|
158
158
|
|
|
159
159
|
### Advanced Examples
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -314,7 +314,7 @@ function detectSoftware(entries) {
|
|
|
314
314
|
return null;
|
|
315
315
|
}
|
|
316
316
|
function detectUniqueKeywords(entryRecord) {
|
|
317
|
-
if (entryRecord.Software
|
|
317
|
+
if (entryRecord.Software?.startsWith("NovelAI")) {
|
|
318
318
|
return "novelai";
|
|
319
319
|
}
|
|
320
320
|
if ("invokeai_metadata" in entryRecord) {
|
|
@@ -671,7 +671,7 @@ function parseInvokeAI(entries) {
|
|
|
671
671
|
// src/parsers/novelai.ts
|
|
672
672
|
function parseNovelAI(entries) {
|
|
673
673
|
const entryRecord = buildEntryRecord(entries);
|
|
674
|
-
if (entryRecord.Software
|
|
674
|
+
if (!entryRecord.Software?.startsWith("NovelAI")) {
|
|
675
675
|
return Result.error({ type: "unsupportedFormat" });
|
|
676
676
|
}
|
|
677
677
|
const commentText = entryRecord.Comment;
|
|
@@ -1092,7 +1092,9 @@ function detectFormat(data) {
|
|
|
1092
1092
|
// src/utils/exif-constants.ts
|
|
1093
1093
|
var USER_COMMENT_TAG = 37510;
|
|
1094
1094
|
var IMAGE_DESCRIPTION_TAG = 270;
|
|
1095
|
+
var DOCUMENT_NAME_TAG = 269;
|
|
1095
1096
|
var MAKE_TAG = 271;
|
|
1097
|
+
var SOFTWARE_TAG = 305;
|
|
1096
1098
|
var EXIF_IFD_POINTER_TAG = 34665;
|
|
1097
1099
|
|
|
1098
1100
|
// src/readers/exif.ts
|
|
@@ -1150,6 +1152,22 @@ function extractTagsFromIfd(data, ifdOffset, isLittleEndian) {
|
|
|
1150
1152
|
data: prefix ? text.slice(prefix.length + 2) : text
|
|
1151
1153
|
});
|
|
1152
1154
|
}
|
|
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
|
+
}
|
|
1153
1171
|
} else if (tag === USER_COMMENT_TAG) {
|
|
1154
1172
|
const text = decodeUserComment(tagData);
|
|
1155
1173
|
if (text) {
|
|
@@ -1580,7 +1598,7 @@ function tryExpandNovelAIWebpFormat(text) {
|
|
|
1580
1598
|
return null;
|
|
1581
1599
|
}
|
|
1582
1600
|
const outer = outerParsed.value;
|
|
1583
|
-
if (typeof outer !== "object" || outer === null || outer.Software
|
|
1601
|
+
if (typeof outer !== "object" || outer === null || typeof outer.Software === "string" && !outer.Software.startsWith("NovelAI") || typeof outer.Comment !== "string") {
|
|
1584
1602
|
return null;
|
|
1585
1603
|
}
|
|
1586
1604
|
const entries = [{ keyword: "Software", text: "NovelAI" }];
|
|
@@ -1600,6 +1618,10 @@ function sourceToKeyword(source) {
|
|
|
1600
1618
|
return source.prefix ?? "Description";
|
|
1601
1619
|
case "exifMake":
|
|
1602
1620
|
return source.prefix ?? "Make";
|
|
1621
|
+
case "exifSoftware":
|
|
1622
|
+
return "Software";
|
|
1623
|
+
case "exifDocumentName":
|
|
1624
|
+
return "Title";
|
|
1603
1625
|
}
|
|
1604
1626
|
}
|
|
1605
1627
|
|
|
@@ -1758,29 +1780,6 @@ var stringify = (value) => {
|
|
|
1758
1780
|
};
|
|
1759
1781
|
|
|
1760
1782
|
// src/converters/chunk-encoding.ts
|
|
1761
|
-
var CHUNK_ENCODING_STRATEGIES = {
|
|
1762
|
-
// Dynamic selection tools
|
|
1763
|
-
a1111: "dynamic",
|
|
1764
|
-
forge: "dynamic",
|
|
1765
|
-
"forge-neo": "dynamic",
|
|
1766
|
-
"sd-webui": "dynamic",
|
|
1767
|
-
invokeai: "dynamic",
|
|
1768
|
-
novelai: "dynamic",
|
|
1769
|
-
"sd-next": "dynamic",
|
|
1770
|
-
easydiffusion: "dynamic",
|
|
1771
|
-
// Unicode escape tools (spec-compliant)
|
|
1772
|
-
comfyui: "text-unicode-escape",
|
|
1773
|
-
swarmui: "text-unicode-escape",
|
|
1774
|
-
fooocus: "text-unicode-escape",
|
|
1775
|
-
"ruined-fooocus": "text-unicode-escape",
|
|
1776
|
-
"hf-space": "text-unicode-escape",
|
|
1777
|
-
// Raw UTF-8 tools (non-compliant but compatible)
|
|
1778
|
-
"stability-matrix": "text-utf8-raw",
|
|
1779
|
-
tensorart: "text-utf8-raw"
|
|
1780
|
-
};
|
|
1781
|
-
function getEncodingStrategy(tool) {
|
|
1782
|
-
return CHUNK_ENCODING_STRATEGIES[tool] ?? "text-unicode-escape";
|
|
1783
|
-
}
|
|
1784
1783
|
function escapeUnicode(text) {
|
|
1785
1784
|
return text.replace(/[\u0100-\uffff]/g, (char) => {
|
|
1786
1785
|
const code = char.charCodeAt(0).toString(16).padStart(4, "0");
|
|
@@ -1813,27 +1812,74 @@ function convertA1111PngToSegments(chunks) {
|
|
|
1813
1812
|
if (!parameters) {
|
|
1814
1813
|
return [];
|
|
1815
1814
|
}
|
|
1816
|
-
|
|
1815
|
+
const segments = [
|
|
1817
1816
|
{
|
|
1818
1817
|
source: { type: "exifUserComment" },
|
|
1819
1818
|
data: parameters.text
|
|
1820
1819
|
}
|
|
1821
1820
|
];
|
|
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;
|
|
1822
1850
|
}
|
|
1823
1851
|
function convertA1111SegmentsToPng(segments) {
|
|
1824
1852
|
const userComment = segments.find((s) => s.source.type === "exifUserComment");
|
|
1825
1853
|
if (!userComment) {
|
|
1826
1854
|
return [];
|
|
1827
1855
|
}
|
|
1828
|
-
|
|
1856
|
+
const parametersChunks = createEncodedChunk(
|
|
1829
1857
|
"parameters",
|
|
1830
1858
|
userComment.data,
|
|
1831
|
-
|
|
1859
|
+
"dynamic"
|
|
1832
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;
|
|
1833
1879
|
}
|
|
1834
1880
|
|
|
1835
|
-
// src/converters/
|
|
1836
|
-
function
|
|
1881
|
+
// src/converters/base-json.ts
|
|
1882
|
+
function convertKvPngToSegments(chunks) {
|
|
1837
1883
|
const data = {};
|
|
1838
1884
|
for (const chunk of chunks) {
|
|
1839
1885
|
const parsed = parseJson(chunk.text);
|
|
@@ -1850,6 +1896,24 @@ function convertComfyUIPngToSegments(chunks) {
|
|
|
1850
1896
|
}
|
|
1851
1897
|
];
|
|
1852
1898
|
}
|
|
1899
|
+
function convertKvSegmentsToPng(segments, encodingStrategy) {
|
|
1900
|
+
const userComment = findSegment(segments, "exifUserComment");
|
|
1901
|
+
if (!userComment) {
|
|
1902
|
+
return [];
|
|
1903
|
+
}
|
|
1904
|
+
const parsed = parseJson(userComment.data);
|
|
1905
|
+
if (!parsed.ok) {
|
|
1906
|
+
return [];
|
|
1907
|
+
}
|
|
1908
|
+
return Object.entries(parsed.value).flatMap(
|
|
1909
|
+
([keyword, value]) => createEncodedChunk(keyword, stringify(value), encodingStrategy)
|
|
1910
|
+
);
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
// src/converters/comfyui.ts
|
|
1914
|
+
function convertComfyUIPngToSegments(chunks) {
|
|
1915
|
+
return convertKvPngToSegments(chunks);
|
|
1916
|
+
}
|
|
1853
1917
|
var tryParseExtendedFormat = (segments) => {
|
|
1854
1918
|
const imageDescription = findSegment(segments, "exifImageDescription");
|
|
1855
1919
|
const make = findSegment(segments, "exifMake");
|
|
@@ -1857,34 +1921,17 @@ var tryParseExtendedFormat = (segments) => {
|
|
|
1857
1921
|
return null;
|
|
1858
1922
|
}
|
|
1859
1923
|
return [
|
|
1860
|
-
...createEncodedChunk("prompt", make?.data,
|
|
1924
|
+
...createEncodedChunk("prompt", make?.data, "text-unicode-escape"),
|
|
1861
1925
|
...createEncodedChunk(
|
|
1862
1926
|
"workflow",
|
|
1863
1927
|
imageDescription?.data,
|
|
1864
|
-
|
|
1928
|
+
"text-unicode-escape"
|
|
1865
1929
|
)
|
|
1866
1930
|
];
|
|
1867
1931
|
};
|
|
1868
1932
|
var tryParseSaveImagePlusFormat = (segments) => {
|
|
1869
|
-
const
|
|
1870
|
-
|
|
1871
|
-
return null;
|
|
1872
|
-
}
|
|
1873
|
-
const parsed = parseJson(userComment.data);
|
|
1874
|
-
if (!parsed.ok) {
|
|
1875
|
-
return createEncodedChunk(
|
|
1876
|
-
"prompt",
|
|
1877
|
-
userComment.data,
|
|
1878
|
-
getEncodingStrategy("comfyui")
|
|
1879
|
-
);
|
|
1880
|
-
}
|
|
1881
|
-
return Object.entries(parsed.value).flatMap(
|
|
1882
|
-
([keyword, value]) => createEncodedChunk(
|
|
1883
|
-
keyword,
|
|
1884
|
-
stringify(value),
|
|
1885
|
-
getEncodingStrategy("comfyui")
|
|
1886
|
-
)
|
|
1887
|
-
);
|
|
1933
|
+
const chunks = convertKvSegmentsToPng(segments, "text-unicode-escape");
|
|
1934
|
+
return chunks.length > 0 ? chunks : null;
|
|
1888
1935
|
};
|
|
1889
1936
|
function convertComfyUISegmentsToPng(segments) {
|
|
1890
1937
|
return tryParseExtendedFormat(segments) ?? tryParseSaveImagePlusFormat(segments) ?? [];
|
|
@@ -1911,93 +1958,49 @@ function convertEasyDiffusionSegmentsToPng(segments) {
|
|
|
1911
1958
|
if (!parsed.ok) {
|
|
1912
1959
|
return [];
|
|
1913
1960
|
}
|
|
1914
|
-
return Object.entries(parsed.value).flatMap(
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
return createEncodedChunk(
|
|
1918
|
-
keyword,
|
|
1919
|
-
text,
|
|
1920
|
-
getEncodingStrategy("easydiffusion")
|
|
1921
|
-
);
|
|
1922
|
-
});
|
|
1961
|
+
return Object.entries(parsed.value).flatMap(
|
|
1962
|
+
([keyword, value]) => createEncodedChunk(keyword, stringify(value), "dynamic")
|
|
1963
|
+
);
|
|
1923
1964
|
}
|
|
1924
1965
|
|
|
1925
1966
|
// src/converters/invokeai.ts
|
|
1926
1967
|
function convertInvokeAIPngToSegments(chunks) {
|
|
1927
|
-
|
|
1928
|
-
for (const chunk of chunks) {
|
|
1929
|
-
const parsed = parseJson(chunk.text);
|
|
1930
|
-
if (parsed.ok) {
|
|
1931
|
-
data[chunk.keyword] = parsed.value;
|
|
1932
|
-
} else {
|
|
1933
|
-
data[chunk.keyword] = chunk.text;
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
return [
|
|
1937
|
-
{
|
|
1938
|
-
source: { type: "exifUserComment" },
|
|
1939
|
-
data: JSON.stringify(data)
|
|
1940
|
-
}
|
|
1941
|
-
];
|
|
1968
|
+
return convertKvPngToSegments(chunks);
|
|
1942
1969
|
}
|
|
1943
1970
|
function convertInvokeAISegmentsToPng(segments) {
|
|
1944
|
-
|
|
1945
|
-
if (!userComment) {
|
|
1946
|
-
return [];
|
|
1947
|
-
}
|
|
1948
|
-
const parsed = parseJson(userComment.data);
|
|
1949
|
-
if (!parsed.ok) {
|
|
1950
|
-
return createEncodedChunk(
|
|
1951
|
-
"invokeai_metadata",
|
|
1952
|
-
userComment.data,
|
|
1953
|
-
getEncodingStrategy("invokeai")
|
|
1954
|
-
);
|
|
1955
|
-
}
|
|
1956
|
-
const metadataText = stringify(parsed.value.invokeai_metadata);
|
|
1957
|
-
const graphText = stringify(parsed.value.invokeai_graph);
|
|
1958
|
-
const chunks = [
|
|
1959
|
-
...createEncodedChunk(
|
|
1960
|
-
"invokeai_metadata",
|
|
1961
|
-
metadataText,
|
|
1962
|
-
getEncodingStrategy("invokeai")
|
|
1963
|
-
),
|
|
1964
|
-
...createEncodedChunk(
|
|
1965
|
-
"invokeai_graph",
|
|
1966
|
-
graphText,
|
|
1967
|
-
getEncodingStrategy("invokeai")
|
|
1968
|
-
)
|
|
1969
|
-
];
|
|
1970
|
-
if (chunks.length > 0) {
|
|
1971
|
-
return chunks;
|
|
1972
|
-
}
|
|
1973
|
-
return createEncodedChunk(
|
|
1974
|
-
"invokeai_metadata",
|
|
1975
|
-
userComment.data,
|
|
1976
|
-
getEncodingStrategy("invokeai")
|
|
1977
|
-
);
|
|
1971
|
+
return convertKvSegmentsToPng(segments, "dynamic");
|
|
1978
1972
|
}
|
|
1979
1973
|
|
|
1980
1974
|
// src/converters/novelai.ts
|
|
1981
|
-
var NOVELAI_TITLE = "NovelAI generated image";
|
|
1982
1975
|
var NOVELAI_SOFTWARE = "NovelAI";
|
|
1976
|
+
var NOVELAI_TITLE = "NovelAI generated image";
|
|
1983
1977
|
function convertNovelaiPngToSegments(chunks) {
|
|
1984
|
-
const comment = chunks.find((c) => c.keyword === "Comment");
|
|
1985
|
-
if (!comment) {
|
|
1986
|
-
return [];
|
|
1987
|
-
}
|
|
1988
|
-
const description = chunks.find((c) => c.keyword === "Description");
|
|
1989
1978
|
const data = buildUserCommentJson(chunks);
|
|
1990
|
-
const descriptionSegment = description ? [
|
|
1991
|
-
{
|
|
1992
|
-
source: { type: "exifImageDescription" },
|
|
1993
|
-
data: `\0\0\0\0${description.text}`
|
|
1994
|
-
}
|
|
1995
|
-
] : [];
|
|
1996
1979
|
const userCommentSegment = {
|
|
1997
1980
|
source: { type: "exifUserComment" },
|
|
1998
1981
|
data: JSON.stringify(data)
|
|
1999
1982
|
};
|
|
2000
|
-
|
|
1983
|
+
const description = chunks.find((c) => c.keyword === "Description");
|
|
1984
|
+
const descriptionSegment = description && {
|
|
1985
|
+
source: { type: "exifImageDescription" },
|
|
1986
|
+
data: `\0\0\0\0${description.text}`
|
|
1987
|
+
};
|
|
1988
|
+
const software = chunks.find((c) => c.keyword === "Software");
|
|
1989
|
+
const softwareSegment = software && {
|
|
1990
|
+
source: { type: "exifSoftware" },
|
|
1991
|
+
data: software.text
|
|
1992
|
+
};
|
|
1993
|
+
const title = chunks.find((c) => c.keyword === "Title");
|
|
1994
|
+
const titleSegment = title && {
|
|
1995
|
+
source: { type: "exifDocumentName" },
|
|
1996
|
+
data: title.text
|
|
1997
|
+
};
|
|
1998
|
+
return [
|
|
1999
|
+
userCommentSegment,
|
|
2000
|
+
descriptionSegment,
|
|
2001
|
+
softwareSegment,
|
|
2002
|
+
titleSegment
|
|
2003
|
+
].filter((segment) => Boolean(segment));
|
|
2001
2004
|
}
|
|
2002
2005
|
function buildUserCommentJson(chunks) {
|
|
2003
2006
|
return NOVELAI_KEY_ORDER.map((key) => {
|
|
@@ -2019,9 +2022,11 @@ var NOVELAI_KEY_ORDER = [
|
|
|
2019
2022
|
function convertNovelaiSegmentsToPng(segments) {
|
|
2020
2023
|
const userCommentSeg = findSegment(segments, "exifUserComment");
|
|
2021
2024
|
const descriptionSeg = findSegment(segments, "exifImageDescription");
|
|
2022
|
-
|
|
2025
|
+
const softwareSeg = findSegment(segments, "exifSoftware");
|
|
2026
|
+
const titleSeg = findSegment(segments, "exifDocumentName");
|
|
2027
|
+
return parseSegments(userCommentSeg, descriptionSeg, softwareSeg, titleSeg);
|
|
2023
2028
|
}
|
|
2024
|
-
function parseSegments(userCommentSeg, descriptionSeg) {
|
|
2029
|
+
function parseSegments(userCommentSeg, descriptionSeg, softwareSeg, titleSeg) {
|
|
2025
2030
|
if (!userCommentSeg || !descriptionSeg) {
|
|
2026
2031
|
return [];
|
|
2027
2032
|
}
|
|
@@ -2034,20 +2039,18 @@ function parseSegments(userCommentSeg, descriptionSeg) {
|
|
|
2034
2039
|
descriptionSeg,
|
|
2035
2040
|
stringify(jsonData.Description)
|
|
2036
2041
|
);
|
|
2037
|
-
const descriptionChunks = descriptionText ? createEncodedChunk(
|
|
2038
|
-
"Description",
|
|
2039
|
-
descriptionText,
|
|
2040
|
-
getEncodingStrategy("novelai")
|
|
2041
|
-
) : [];
|
|
2042
2042
|
return [
|
|
2043
2043
|
// Title (required, use default if missing)
|
|
2044
|
-
createTextChunk(
|
|
2044
|
+
createTextChunk(
|
|
2045
|
+
"Title",
|
|
2046
|
+
titleSeg?.data ?? stringify(jsonData.Title) ?? NOVELAI_TITLE
|
|
2047
|
+
),
|
|
2045
2048
|
// Description (optional, prefer exifImageDescription over JSON)
|
|
2046
|
-
|
|
2049
|
+
createEncodedChunk("Description", descriptionText, "dynamic"),
|
|
2047
2050
|
// Software (required, use default if missing)
|
|
2048
2051
|
createTextChunk(
|
|
2049
2052
|
"Software",
|
|
2050
|
-
stringify(jsonData.Software) ?? NOVELAI_SOFTWARE
|
|
2053
|
+
softwareSeg?.data ?? stringify(jsonData.Software) ?? NOVELAI_SOFTWARE
|
|
2051
2054
|
),
|
|
2052
2055
|
// Source (optional)
|
|
2053
2056
|
createTextChunk("Source", stringify(jsonData.Source)),
|
|
@@ -2075,17 +2078,13 @@ function createPngToSegments(keyword) {
|
|
|
2075
2078
|
return !chunk ? [] : [{ source: { type: "exifUserComment" }, data: chunk.text }];
|
|
2076
2079
|
};
|
|
2077
2080
|
}
|
|
2078
|
-
function createSegmentsToPng(keyword) {
|
|
2081
|
+
function createSegmentsToPng(keyword, encodingStrategy) {
|
|
2079
2082
|
return (segments) => {
|
|
2080
2083
|
const userComment = segments.find(
|
|
2081
2084
|
(s) => s.source.type === "exifUserComment"
|
|
2082
2085
|
);
|
|
2083
2086
|
if (!userComment) return [];
|
|
2084
|
-
return createEncodedChunk(
|
|
2085
|
-
keyword,
|
|
2086
|
-
userComment.data,
|
|
2087
|
-
getEncodingStrategy(keyword)
|
|
2088
|
-
);
|
|
2087
|
+
return createEncodedChunk(keyword, userComment.data, encodingStrategy);
|
|
2089
2088
|
};
|
|
2090
2089
|
}
|
|
2091
2090
|
|
|
@@ -2096,11 +2095,10 @@ function convertSwarmUIPngToSegments(chunks) {
|
|
|
2096
2095
|
return [];
|
|
2097
2096
|
}
|
|
2098
2097
|
const parsed = parseJson(parametersChunk.text);
|
|
2099
|
-
const data = parsed.ok ? parsed.value : parametersChunk.text;
|
|
2100
2098
|
const segments = [
|
|
2101
2099
|
{
|
|
2102
2100
|
source: { type: "exifUserComment" },
|
|
2103
|
-
data:
|
|
2101
|
+
data: parsed.ok ? JSON.stringify(parsed.value) : parametersChunk.text
|
|
2104
2102
|
}
|
|
2105
2103
|
];
|
|
2106
2104
|
const promptChunk = chunks.find((c) => c.keyword === "prompt");
|
|
@@ -2114,27 +2112,13 @@ function convertSwarmUIPngToSegments(chunks) {
|
|
|
2114
2112
|
}
|
|
2115
2113
|
function convertSwarmUISegmentsToPng(segments) {
|
|
2116
2114
|
const userComment = findSegment(segments, "exifUserComment");
|
|
2117
|
-
if (!userComment) {
|
|
2118
|
-
return [];
|
|
2119
|
-
}
|
|
2120
|
-
const chunks = [];
|
|
2121
2115
|
const make = findSegment(segments, "exifMake");
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
)
|
|
2129
|
-
);
|
|
2130
|
-
}
|
|
2131
|
-
chunks.push(
|
|
2132
|
-
...createEncodedChunk(
|
|
2133
|
-
"parameters",
|
|
2134
|
-
userComment.data,
|
|
2135
|
-
getEncodingStrategy("swarmui")
|
|
2136
|
-
)
|
|
2137
|
-
);
|
|
2116
|
+
const chunks = [
|
|
2117
|
+
// Restore node graph first if present (extended format)
|
|
2118
|
+
createEncodedChunk("prompt", make?.data, "text-unicode-escape"),
|
|
2119
|
+
// Add parameters chunk second (always present)
|
|
2120
|
+
createEncodedChunk("parameters", userComment?.data, "text-unicode-escape")
|
|
2121
|
+
].flat();
|
|
2138
2122
|
return chunks;
|
|
2139
2123
|
}
|
|
2140
2124
|
|
|
@@ -2203,11 +2187,11 @@ var convertEasyDiffusion = createFormatConverter(
|
|
|
2203
2187
|
);
|
|
2204
2188
|
var convertFooocus = createFormatConverter(
|
|
2205
2189
|
createPngToSegments("Comment"),
|
|
2206
|
-
createSegmentsToPng("Comment")
|
|
2190
|
+
createSegmentsToPng("Comment", "text-unicode-escape")
|
|
2207
2191
|
);
|
|
2208
2192
|
var convertRuinedFooocus = createFormatConverter(
|
|
2209
2193
|
createPngToSegments("parameters"),
|
|
2210
|
-
createSegmentsToPng("parameters")
|
|
2194
|
+
createSegmentsToPng("parameters", "text-unicode-escape")
|
|
2211
2195
|
);
|
|
2212
2196
|
var convertSwarmUI = createFormatConverter(
|
|
2213
2197
|
convertSwarmUIPngToSegments,
|
|
@@ -2219,7 +2203,7 @@ var convertInvokeAI = createFormatConverter(
|
|
|
2219
2203
|
);
|
|
2220
2204
|
var convertHfSpace = createFormatConverter(
|
|
2221
2205
|
createPngToSegments("parameters"),
|
|
2222
|
-
createSegmentsToPng("parameters")
|
|
2206
|
+
createSegmentsToPng("parameters", "text-unicode-escape")
|
|
2223
2207
|
);
|
|
2224
2208
|
var softwareConverters = {
|
|
2225
2209
|
// NovelAI
|
|
@@ -2250,7 +2234,7 @@ var softwareConverters = {
|
|
|
2250
2234
|
// src/writers/exif.ts
|
|
2251
2235
|
function buildExifTiffData(segments) {
|
|
2252
2236
|
const ifd0Segments = segments.filter(
|
|
2253
|
-
(s) => s.source.type === "exifImageDescription" || s.source.type === "exifMake"
|
|
2237
|
+
(s) => s.source.type === "exifImageDescription" || s.source.type === "exifMake" || s.source.type === "exifSoftware" || s.source.type === "exifDocumentName"
|
|
2254
2238
|
);
|
|
2255
2239
|
const exifIfdSegments = segments.filter(
|
|
2256
2240
|
(s) => s.source.type === "exifUserComment"
|
|
@@ -2268,6 +2252,12 @@ function buildExifTiffData(segments) {
|
|
|
2268
2252
|
} else if (seg.source.type === "exifMake") {
|
|
2269
2253
|
const data = encodeAsciiTag(seg.data, seg.source.prefix);
|
|
2270
2254
|
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 });
|
|
2271
2261
|
}
|
|
2272
2262
|
}
|
|
2273
2263
|
for (const seg of exifIfdSegments) {
|
|
@@ -2395,7 +2385,7 @@ function writeJpegMetadata(data, segments) {
|
|
|
2395
2385
|
}
|
|
2396
2386
|
const comSegments = segments.filter((s) => s.source.type === "jpegCom");
|
|
2397
2387
|
const exifSegments = segments.filter(
|
|
2398
|
-
(s) => s.source.type === "exifUserComment" || s.source.type === "exifImageDescription" || s.source.type === "exifMake"
|
|
2388
|
+
(s) => s.source.type === "exifUserComment" || s.source.type === "exifImageDescription" || s.source.type === "exifMake" || s.source.type === "exifSoftware" || s.source.type === "exifDocumentName"
|
|
2399
2389
|
);
|
|
2400
2390
|
const collectResult = collectNonMetadataSegments(data);
|
|
2401
2391
|
if (!collectResult.ok) {
|
|
@@ -2755,7 +2745,7 @@ function collectNonExifChunks(data) {
|
|
|
2755
2745
|
}
|
|
2756
2746
|
function buildExifChunk(segments) {
|
|
2757
2747
|
const exifSegments = segments.filter(
|
|
2758
|
-
(s) => s.source.type === "exifUserComment" || s.source.type === "exifImageDescription" || s.source.type === "exifMake"
|
|
2748
|
+
(s) => s.source.type === "exifUserComment" || s.source.type === "exifImageDescription" || s.source.type === "exifMake" || s.source.type === "exifSoftware" || s.source.type === "exifDocumentName"
|
|
2759
2749
|
);
|
|
2760
2750
|
if (exifSegments.length === 0) {
|
|
2761
2751
|
return null;
|
|
@@ -3002,8 +2992,7 @@ function writeAsWebUI(data, metadata) {
|
|
|
3002
2992
|
return Result.ok(writeResult.value);
|
|
3003
2993
|
}
|
|
3004
2994
|
function createPngChunks(text) {
|
|
3005
|
-
|
|
3006
|
-
return createEncodedChunk("parameters", text, strategy);
|
|
2995
|
+
return createEncodedChunk("parameters", text, "dynamic");
|
|
3007
2996
|
}
|
|
3008
2997
|
function createExifSegments(text) {
|
|
3009
2998
|
return [
|