hwp-to-svg 0.1.0
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/LICENSE +21 -0
- package/README.md +45 -0
- package/dist/cli/hwp2svg.js +74 -0
- package/dist/fs/idb-fs.d.ts +7 -0
- package/dist/fs/idb-fs.js +81 -0
- package/dist/fs/idb-fs.js.map +1 -0
- package/dist/hwp/constants.d.ts +69 -0
- package/dist/hwp/constants.js +73 -0
- package/dist/hwp/constants.js.map +1 -0
- package/dist/hwp/converter.d.ts +9 -0
- package/dist/hwp/converter.js +130 -0
- package/dist/hwp/converter.js.map +1 -0
- package/dist/hwp/hwp-docinfo.d.ts +11 -0
- package/dist/hwp/hwp-docinfo.js +155 -0
- package/dist/hwp/hwp-docinfo.js.map +1 -0
- package/dist/hwp/hwp-section.d.ts +17 -0
- package/dist/hwp/hwp-section.js +395 -0
- package/dist/hwp/hwp-section.js.map +1 -0
- package/dist/hwp/hwp-types.d.ts +147 -0
- package/dist/hwp/hwp-types.js +5 -0
- package/dist/hwp/hwp-types.js.map +1 -0
- package/dist/hwp/hwp-xml.d.ts +8 -0
- package/dist/hwp/hwp-xml.js +272 -0
- package/dist/hwp/hwp-xml.js.map +1 -0
- package/dist/hwp/parser.d.ts +6 -0
- package/dist/hwp/parser.js +621 -0
- package/dist/hwp/parser.js.map +1 -0
- package/dist/hwp/record.d.ts +24 -0
- package/dist/hwp/record.js +61 -0
- package/dist/hwp/record.js.map +1 -0
- package/dist/hwpx/loader.d.ts +10 -0
- package/dist/hwpx/loader.js +40 -0
- package/dist/hwpx/loader.js.map +1 -0
- package/dist/hwpx/parser.d.ts +17 -0
- package/dist/hwpx/parser.js +469 -0
- package/dist/hwpx/parser.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +85 -0
- package/dist/index.js.map +1 -0
- package/dist/model/types.d.ts +202 -0
- package/dist/model/types.js +9 -0
- package/dist/model/types.js.map +1 -0
- package/dist/renderer/svg-cache.d.ts +7 -0
- package/dist/renderer/svg-cache.js +265 -0
- package/dist/renderer/svg-cache.js.map +1 -0
- package/dist/renderer/svg-renderer.d.ts +11 -0
- package/dist/renderer/svg-renderer.js +95 -0
- package/dist/renderer/svg-renderer.js.map +1 -0
- package/dist/renderer/svg-table.d.ts +49 -0
- package/dist/renderer/svg-table.js +876 -0
- package/dist/renderer/svg-table.js.map +1 -0
- package/dist/renderer/svg-text.d.ts +20 -0
- package/dist/renderer/svg-text.js +218 -0
- package/dist/renderer/svg-text.js.map +1 -0
- package/dist/renderer/svg-types.d.ts +61 -0
- package/dist/renderer/svg-types.js +5 -0
- package/dist/renderer/svg-types.js.map +1 -0
- package/dist/renderer/svg-utils.d.ts +60 -0
- package/dist/renderer/svg-utils.js +205 -0
- package/dist/renderer/svg-utils.js.map +1 -0
- package/dist/xml/dom-parser.d.ts +4 -0
- package/dist/xml/dom-parser.js +5 -0
- package/dist/xml/dom-parser.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jeongbin Park
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# hwp-to-svg
|
|
2
|
+
|
|
3
|
+
Convert HWP/HWPX (한글) documents to SVG, one SVG per page.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install hwp-to-svg
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## CLI Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Convert all pages
|
|
15
|
+
hwp2svg document.hwp -o output/
|
|
16
|
+
|
|
17
|
+
# Convert specific pages
|
|
18
|
+
hwp2svg document.hwpx -o output/ -p 0-2
|
|
19
|
+
hwp2svg document.hwp -o output/ -p 0,2,4
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## API Usage
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { HwpxDocument } from 'hwp-to-svg';
|
|
26
|
+
|
|
27
|
+
const data = await fs.readFile('document.hwp');
|
|
28
|
+
const doc = await HwpxDocument.open(data.buffer);
|
|
29
|
+
const pages = doc.renderAllPages(); // string[] of SVG content
|
|
30
|
+
await doc.close();
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Fonts
|
|
34
|
+
|
|
35
|
+
The SVG output references fonts by name rather than embedding them. Install the
|
|
36
|
+
required Korean fonts system-wide for correct rendering:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cp fonts/*.TTF ~/.local/share/fonts/
|
|
40
|
+
fc-cache -f
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
|
|
45
|
+
MIT
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Polyfill browser APIs for Node.js
|
|
3
|
+
import 'fake-indexeddb/auto';
|
|
4
|
+
import { DOMParser, XMLSerializer } from '@xmldom/xmldom';
|
|
5
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
6
|
+
import { resolve, basename } from 'node:path';
|
|
7
|
+
import { inflateRawSync } from 'node:zlib';
|
|
8
|
+
// Set up browser API polyfills on globalThis
|
|
9
|
+
globalThis.DOMParser = DOMParser;
|
|
10
|
+
globalThis.XMLSerializer = XMLSerializer;
|
|
11
|
+
globalThis.__decompressRawSync = (data) => {
|
|
12
|
+
return new Uint8Array(inflateRawSync(data));
|
|
13
|
+
};
|
|
14
|
+
// Import library AFTER polyfills are set up
|
|
15
|
+
const { HwpxDocument } = await import('../dist/index.js');
|
|
16
|
+
// Fonts are installed system-wide (~/.local/share/fonts/ or system fonts dir).
|
|
17
|
+
// No embedding needed — SVG references fonts by name in font-family attributes.
|
|
18
|
+
// Install fonts with: cp fonts/*.TTF ~/.local/share/fonts/ && fc-cache -f
|
|
19
|
+
// Parse CLI args
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
let inputPath = '';
|
|
22
|
+
let outputDir = './output';
|
|
23
|
+
let pageRange = '';
|
|
24
|
+
for (let i = 0; i < args.length; i++) {
|
|
25
|
+
if (args[i] === '-o' || args[i] === '--output') {
|
|
26
|
+
outputDir = args[++i];
|
|
27
|
+
}
|
|
28
|
+
else if (args[i] === '-p' || args[i] === '--pages') {
|
|
29
|
+
pageRange = args[++i];
|
|
30
|
+
}
|
|
31
|
+
else if (!args[i].startsWith('-')) {
|
|
32
|
+
inputPath = args[i];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!inputPath) {
|
|
36
|
+
console.error('Usage: hwp2svg <input.hwp|hwpx> [-o <output-dir>] [-p <pages>]');
|
|
37
|
+
console.error(' -o, --output Output directory (default: ./output)');
|
|
38
|
+
console.error(' -p, --pages Page range (e.g. "0", "0-2", "1,3,5")');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
function parsePageRange(range, total) {
|
|
42
|
+
if (!range)
|
|
43
|
+
return Array.from({ length: total }, (_, i) => i);
|
|
44
|
+
const pages = [];
|
|
45
|
+
for (const part of range.split(',')) {
|
|
46
|
+
if (part.includes('-')) {
|
|
47
|
+
const [a, b] = part.split('-').map(Number);
|
|
48
|
+
for (let i = a; i <= b && i < total; i++)
|
|
49
|
+
pages.push(i);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const n = Number(part);
|
|
53
|
+
if (n < total)
|
|
54
|
+
pages.push(n);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return pages;
|
|
58
|
+
}
|
|
59
|
+
// Main
|
|
60
|
+
const inputData = readFileSync(resolve(inputPath));
|
|
61
|
+
const doc = await HwpxDocument.open(inputData.buffer);
|
|
62
|
+
const allPages = doc.renderAllPages();
|
|
63
|
+
console.log(`${basename(inputPath)}: ${allPages.length} pages`);
|
|
64
|
+
const pages = parsePageRange(pageRange, allPages.length);
|
|
65
|
+
if (!existsSync(outputDir)) {
|
|
66
|
+
mkdirSync(outputDir, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
for (const idx of pages) {
|
|
69
|
+
const svg = allPages[idx];
|
|
70
|
+
const outPath = resolve(outputDir, `page-${idx}.svg`);
|
|
71
|
+
writeFileSync(outPath, svg);
|
|
72
|
+
console.log(` wrote ${outPath}`);
|
|
73
|
+
}
|
|
74
|
+
await doc.close();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function writeFile(docId: string, path: string, data: Uint8Array | string): Promise<void>;
|
|
2
|
+
export declare function readFile(docId: string, path: string): Promise<Uint8Array | string>;
|
|
3
|
+
export declare function readFileAsString(docId: string, path: string): Promise<string>;
|
|
4
|
+
export declare function exists(docId: string, path: string): Promise<boolean>;
|
|
5
|
+
export declare function readDir(docId: string, prefix: string): Promise<string[]>;
|
|
6
|
+
export declare function deleteFile(docId: string, path: string): Promise<void>;
|
|
7
|
+
export declare function deleteAll(docId: string): Promise<void>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const DB_NAME = 'hwpx-fs';
|
|
2
|
+
const DB_VERSION = 1;
|
|
3
|
+
const STORE_NAME = 'files';
|
|
4
|
+
function openDb() {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
const req = indexedDB.open(DB_NAME, DB_VERSION);
|
|
7
|
+
req.onupgradeneeded = () => {
|
|
8
|
+
req.result.createObjectStore(STORE_NAME);
|
|
9
|
+
};
|
|
10
|
+
req.onsuccess = () => resolve(req.result);
|
|
11
|
+
req.onerror = () => reject(req.error);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function tx(db, mode) {
|
|
15
|
+
return db.transaction(STORE_NAME, mode).objectStore(STORE_NAME);
|
|
16
|
+
}
|
|
17
|
+
function req(r) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
r.onsuccess = () => resolve(r.result);
|
|
20
|
+
r.onerror = () => reject(r.error);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function key(docId, path) {
|
|
24
|
+
return `${docId}/${path}`;
|
|
25
|
+
}
|
|
26
|
+
export async function writeFile(docId, path, data) {
|
|
27
|
+
const db = await openDb();
|
|
28
|
+
await req(tx(db, 'readwrite').put(data, key(docId, path)));
|
|
29
|
+
db.close();
|
|
30
|
+
}
|
|
31
|
+
export async function readFile(docId, path) {
|
|
32
|
+
const db = await openDb();
|
|
33
|
+
const result = await req(tx(db, 'readonly').get(key(docId, path)));
|
|
34
|
+
db.close();
|
|
35
|
+
if (result === undefined)
|
|
36
|
+
throw new Error(`File not found: ${path}`);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
export async function readFileAsString(docId, path) {
|
|
40
|
+
const data = await readFile(docId, path);
|
|
41
|
+
if (typeof data === 'string')
|
|
42
|
+
return data;
|
|
43
|
+
return new TextDecoder().decode(data);
|
|
44
|
+
}
|
|
45
|
+
export async function exists(docId, path) {
|
|
46
|
+
const db = await openDb();
|
|
47
|
+
const count = await req(tx(db, 'readonly').count(key(docId, path)));
|
|
48
|
+
db.close();
|
|
49
|
+
return count > 0;
|
|
50
|
+
}
|
|
51
|
+
export async function readDir(docId, prefix) {
|
|
52
|
+
const db = await openDb();
|
|
53
|
+
const store = tx(db, 'readonly');
|
|
54
|
+
const lo = key(docId, prefix);
|
|
55
|
+
const hi = lo + '\uffff';
|
|
56
|
+
const keys = await req(store.getAllKeys(IDBKeyRange.bound(lo, hi)));
|
|
57
|
+
db.close();
|
|
58
|
+
const prefixLen = docId.length + 1;
|
|
59
|
+
return keys.map(k => k.substring(prefixLen));
|
|
60
|
+
}
|
|
61
|
+
export async function deleteFile(docId, path) {
|
|
62
|
+
const db = await openDb();
|
|
63
|
+
await req(tx(db, 'readwrite').delete(key(docId, path)));
|
|
64
|
+
db.close();
|
|
65
|
+
}
|
|
66
|
+
export async function deleteAll(docId) {
|
|
67
|
+
const db = await openDb();
|
|
68
|
+
const store = tx(db, 'readwrite');
|
|
69
|
+
const lo = `${docId}/`;
|
|
70
|
+
const hi = lo + '\uffff';
|
|
71
|
+
const keys = await req(store.getAllKeys(IDBKeyRange.bound(lo, hi)));
|
|
72
|
+
for (const k of keys) {
|
|
73
|
+
store.delete(k);
|
|
74
|
+
}
|
|
75
|
+
await new Promise((resolve, reject) => {
|
|
76
|
+
store.transaction.oncomplete = () => resolve();
|
|
77
|
+
store.transaction.onerror = () => reject(store.transaction.error);
|
|
78
|
+
});
|
|
79
|
+
db.close();
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=idb-fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idb-fs.js","sourceRoot":"","sources":["../../src/fs/idb-fs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HWP 5.0 Tag IDs and constants.
|
|
3
|
+
* Tag IDs: HWPTAG_BEGIN = 0x010 (16)
|
|
4
|
+
*/
|
|
5
|
+
export declare const HWPTAG_BEGIN = 16;
|
|
6
|
+
export declare const HWPTAG_DOCUMENT_PROPERTIES: number;
|
|
7
|
+
export declare const HWPTAG_ID_MAPPINGS: number;
|
|
8
|
+
export declare const HWPTAG_BIN_DATA: number;
|
|
9
|
+
export declare const HWPTAG_FACE_NAME: number;
|
|
10
|
+
export declare const HWPTAG_BORDER_FILL: number;
|
|
11
|
+
export declare const HWPTAG_CHAR_SHAPE: number;
|
|
12
|
+
export declare const HWPTAG_TAB_DEF: number;
|
|
13
|
+
export declare const HWPTAG_NUMBERING: number;
|
|
14
|
+
export declare const HWPTAG_BULLET: number;
|
|
15
|
+
export declare const HWPTAG_PARA_SHAPE: number;
|
|
16
|
+
export declare const HWPTAG_STYLE: number;
|
|
17
|
+
export declare const HWPTAG_DOC_DATA: number;
|
|
18
|
+
export declare const HWPTAG_DISTRIBUTE_DOC_DATA: number;
|
|
19
|
+
export declare const HWPTAG_COMPATIBLE_DOCUMENT: number;
|
|
20
|
+
export declare const HWPTAG_LAYOUT_COMPATIBILITY: number;
|
|
21
|
+
export declare const HWPTAG_MEMO_SHAPE: number;
|
|
22
|
+
export declare const HWPTAG_FORBIDDEN_CHAR: number;
|
|
23
|
+
export declare const HWPTAG_TRACK_CHANGE: number;
|
|
24
|
+
export declare const HWPTAG_TRACK_CHANGE_AUTHOR: number;
|
|
25
|
+
export declare const HWPTAG_PARA_HEADER: number;
|
|
26
|
+
export declare const HWPTAG_PARA_TEXT: number;
|
|
27
|
+
export declare const HWPTAG_PARA_CHAR_SHAPE: number;
|
|
28
|
+
export declare const HWPTAG_PARA_LINE_SEG: number;
|
|
29
|
+
export declare const HWPTAG_PARA_RANGE_TAG: number;
|
|
30
|
+
export declare const HWPTAG_CTRL_HEADER: number;
|
|
31
|
+
export declare const HWPTAG_LIST_HEADER: number;
|
|
32
|
+
export declare const HWPTAG_PAGE_DEF: number;
|
|
33
|
+
export declare const HWPTAG_FOOTNOTE_SHAPE: number;
|
|
34
|
+
export declare const HWPTAG_PAGE_BORDER_FILL: number;
|
|
35
|
+
export declare const HWPTAG_SHAPE_COMPONENT: number;
|
|
36
|
+
export declare const HWPTAG_TABLE: number;
|
|
37
|
+
export declare const HWPTAG_SHAPE_COMPONENT_LINE: number;
|
|
38
|
+
export declare const HWPTAG_SHAPE_COMPONENT_RECTANGLE: number;
|
|
39
|
+
export declare const HWPTAG_SHAPE_COMPONENT_ELLIPSE: number;
|
|
40
|
+
export declare const HWPTAG_SHAPE_COMPONENT_ARC: number;
|
|
41
|
+
export declare const HWPTAG_SHAPE_COMPONENT_POLYGON: number;
|
|
42
|
+
export declare const HWPTAG_SHAPE_COMPONENT_CURVE: number;
|
|
43
|
+
export declare const HWPTAG_SHAPE_COMPONENT_OLE: number;
|
|
44
|
+
export declare const HWPTAG_SHAPE_COMPONENT_PICTURE: number;
|
|
45
|
+
export declare const HWPTAG_SHAPE_COMPONENT_CONTAINER: number;
|
|
46
|
+
export declare const HWPTAG_CTRL_DATA: number;
|
|
47
|
+
export declare const HWPTAG_EQEDIT: number;
|
|
48
|
+
export declare const HWPTAG_SHAPE_COMPONENT_TEXTART: number;
|
|
49
|
+
export declare const HWPTAG_FORM_OBJECT: number;
|
|
50
|
+
export declare const HWPTAG_MEMO_LIST: number;
|
|
51
|
+
export declare const HWPTAG_CHART_DATA: number;
|
|
52
|
+
export declare const HWPTAG_VIDEO_DATA: number;
|
|
53
|
+
export declare const HWPTAG_SHAPE_COMPONENT_UNKNOWN: number;
|
|
54
|
+
export declare const CTRL_SECTION_COLUMN_DEF = 2;
|
|
55
|
+
export declare const CTRL_FIELD_BEGIN = 3;
|
|
56
|
+
export declare const CTRL_FIELD_END = 4;
|
|
57
|
+
export declare const CTRL_TAB = 9;
|
|
58
|
+
export declare const CTRL_LINE_BREAK = 10;
|
|
59
|
+
export declare const CTRL_DRAWING_TABLE = 11;
|
|
60
|
+
export declare const CTRL_PARA_BREAK = 13;
|
|
61
|
+
export declare const CTRL_HIDDEN_COMMENT = 15;
|
|
62
|
+
export declare const CTRL_HEADER_FOOTER = 16;
|
|
63
|
+
export declare const CTRL_FOOTNOTE_ENDNOTE = 17;
|
|
64
|
+
export declare const CTRL_AUTO_NUMBER = 18;
|
|
65
|
+
export declare const CTRL_PAGE_CTRL = 21;
|
|
66
|
+
export declare const CTRL_BOOKMARK = 22;
|
|
67
|
+
export declare const CTRL_DUTMAL = 23;
|
|
68
|
+
/** HWP file signature */
|
|
69
|
+
export declare const HWP_SIGNATURE = "HWP Document File";
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HWP 5.0 Tag IDs and constants.
|
|
3
|
+
* Tag IDs: HWPTAG_BEGIN = 0x010 (16)
|
|
4
|
+
*/
|
|
5
|
+
export const HWPTAG_BEGIN = 0x010;
|
|
6
|
+
// DocInfo tags
|
|
7
|
+
export const HWPTAG_DOCUMENT_PROPERTIES = HWPTAG_BEGIN + 0;
|
|
8
|
+
export const HWPTAG_ID_MAPPINGS = HWPTAG_BEGIN + 1;
|
|
9
|
+
export const HWPTAG_BIN_DATA = HWPTAG_BEGIN + 2;
|
|
10
|
+
export const HWPTAG_FACE_NAME = HWPTAG_BEGIN + 3;
|
|
11
|
+
export const HWPTAG_BORDER_FILL = HWPTAG_BEGIN + 4;
|
|
12
|
+
export const HWPTAG_CHAR_SHAPE = HWPTAG_BEGIN + 5;
|
|
13
|
+
export const HWPTAG_TAB_DEF = HWPTAG_BEGIN + 6;
|
|
14
|
+
export const HWPTAG_NUMBERING = HWPTAG_BEGIN + 7;
|
|
15
|
+
export const HWPTAG_BULLET = HWPTAG_BEGIN + 8;
|
|
16
|
+
export const HWPTAG_PARA_SHAPE = HWPTAG_BEGIN + 9;
|
|
17
|
+
export const HWPTAG_STYLE = HWPTAG_BEGIN + 10;
|
|
18
|
+
export const HWPTAG_DOC_DATA = HWPTAG_BEGIN + 11;
|
|
19
|
+
export const HWPTAG_DISTRIBUTE_DOC_DATA = HWPTAG_BEGIN + 12;
|
|
20
|
+
export const HWPTAG_COMPATIBLE_DOCUMENT = HWPTAG_BEGIN + 14;
|
|
21
|
+
export const HWPTAG_LAYOUT_COMPATIBILITY = HWPTAG_BEGIN + 15;
|
|
22
|
+
export const HWPTAG_MEMO_SHAPE = HWPTAG_BEGIN + 76;
|
|
23
|
+
export const HWPTAG_FORBIDDEN_CHAR = HWPTAG_BEGIN + 78;
|
|
24
|
+
export const HWPTAG_TRACK_CHANGE = HWPTAG_BEGIN + 80;
|
|
25
|
+
export const HWPTAG_TRACK_CHANGE_AUTHOR = HWPTAG_BEGIN + 81;
|
|
26
|
+
// BodyText tags
|
|
27
|
+
export const HWPTAG_PARA_HEADER = HWPTAG_BEGIN + 50;
|
|
28
|
+
export const HWPTAG_PARA_TEXT = HWPTAG_BEGIN + 51;
|
|
29
|
+
export const HWPTAG_PARA_CHAR_SHAPE = HWPTAG_BEGIN + 52;
|
|
30
|
+
export const HWPTAG_PARA_LINE_SEG = HWPTAG_BEGIN + 53;
|
|
31
|
+
export const HWPTAG_PARA_RANGE_TAG = HWPTAG_BEGIN + 54;
|
|
32
|
+
export const HWPTAG_CTRL_HEADER = HWPTAG_BEGIN + 55;
|
|
33
|
+
export const HWPTAG_LIST_HEADER = HWPTAG_BEGIN + 56;
|
|
34
|
+
export const HWPTAG_PAGE_DEF = HWPTAG_BEGIN + 57;
|
|
35
|
+
export const HWPTAG_FOOTNOTE_SHAPE = HWPTAG_BEGIN + 58;
|
|
36
|
+
export const HWPTAG_PAGE_BORDER_FILL = HWPTAG_BEGIN + 59;
|
|
37
|
+
export const HWPTAG_SHAPE_COMPONENT = HWPTAG_BEGIN + 60;
|
|
38
|
+
export const HWPTAG_TABLE = HWPTAG_BEGIN + 61;
|
|
39
|
+
export const HWPTAG_SHAPE_COMPONENT_LINE = HWPTAG_BEGIN + 62;
|
|
40
|
+
export const HWPTAG_SHAPE_COMPONENT_RECTANGLE = HWPTAG_BEGIN + 63;
|
|
41
|
+
export const HWPTAG_SHAPE_COMPONENT_ELLIPSE = HWPTAG_BEGIN + 64;
|
|
42
|
+
export const HWPTAG_SHAPE_COMPONENT_ARC = HWPTAG_BEGIN + 65;
|
|
43
|
+
export const HWPTAG_SHAPE_COMPONENT_POLYGON = HWPTAG_BEGIN + 66;
|
|
44
|
+
export const HWPTAG_SHAPE_COMPONENT_CURVE = HWPTAG_BEGIN + 67;
|
|
45
|
+
export const HWPTAG_SHAPE_COMPONENT_OLE = HWPTAG_BEGIN + 68;
|
|
46
|
+
export const HWPTAG_SHAPE_COMPONENT_PICTURE = HWPTAG_BEGIN + 69;
|
|
47
|
+
export const HWPTAG_SHAPE_COMPONENT_CONTAINER = HWPTAG_BEGIN + 70;
|
|
48
|
+
export const HWPTAG_CTRL_DATA = HWPTAG_BEGIN + 71;
|
|
49
|
+
export const HWPTAG_EQEDIT = HWPTAG_BEGIN + 72;
|
|
50
|
+
export const HWPTAG_SHAPE_COMPONENT_TEXTART = HWPTAG_BEGIN + 74;
|
|
51
|
+
export const HWPTAG_FORM_OBJECT = HWPTAG_BEGIN + 75;
|
|
52
|
+
export const HWPTAG_MEMO_LIST = HWPTAG_BEGIN + 77;
|
|
53
|
+
export const HWPTAG_CHART_DATA = HWPTAG_BEGIN + 79;
|
|
54
|
+
export const HWPTAG_VIDEO_DATA = HWPTAG_BEGIN + 82;
|
|
55
|
+
export const HWPTAG_SHAPE_COMPONENT_UNKNOWN = HWPTAG_BEGIN + 99;
|
|
56
|
+
// Control character codes
|
|
57
|
+
export const CTRL_SECTION_COLUMN_DEF = 2;
|
|
58
|
+
export const CTRL_FIELD_BEGIN = 3;
|
|
59
|
+
export const CTRL_FIELD_END = 4;
|
|
60
|
+
export const CTRL_TAB = 9;
|
|
61
|
+
export const CTRL_LINE_BREAK = 10;
|
|
62
|
+
export const CTRL_DRAWING_TABLE = 11;
|
|
63
|
+
export const CTRL_PARA_BREAK = 13;
|
|
64
|
+
export const CTRL_HIDDEN_COMMENT = 15;
|
|
65
|
+
export const CTRL_HEADER_FOOTER = 16;
|
|
66
|
+
export const CTRL_FOOTNOTE_ENDNOTE = 17;
|
|
67
|
+
export const CTRL_AUTO_NUMBER = 18;
|
|
68
|
+
export const CTRL_PAGE_CTRL = 21;
|
|
69
|
+
export const CTRL_BOOKMARK = 22;
|
|
70
|
+
export const CTRL_DUTMAL = 23;
|
|
71
|
+
/** HWP file signature */
|
|
72
|
+
export const HWP_SIGNATURE = 'HWP Document File';
|
|
73
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/hwp/constants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HWP 5.0 binary → HWPX XML converter.
|
|
3
|
+
* Reads OLE2 compound documents using the `cfb` package and generates
|
|
4
|
+
* HWPX XML files, writing them to the IndexedDB FS.
|
|
5
|
+
*/
|
|
6
|
+
declare global {
|
|
7
|
+
var __decompressRawSync: ((data: Uint8Array) => Uint8Array) | undefined;
|
|
8
|
+
}
|
|
9
|
+
export declare function convertHwpToHwpx(data: ArrayBuffer, docId: string): Promise<number>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HWP 5.0 binary → HWPX XML converter.
|
|
3
|
+
* Reads OLE2 compound documents using the `cfb` package and generates
|
|
4
|
+
* HWPX XML files, writing them to the IndexedDB FS.
|
|
5
|
+
*/
|
|
6
|
+
import * as CFB from 'cfb';
|
|
7
|
+
import { dataView } from './record.js';
|
|
8
|
+
import * as TAG from './constants.js';
|
|
9
|
+
import * as fs from '../fs/idb-fs.js';
|
|
10
|
+
import { parseDocInfoData } from './hwp-docinfo.js';
|
|
11
|
+
import { parseSectionRecords } from './hwp-section.js';
|
|
12
|
+
import { generateHeaderXml, generateSectionXml, generateContentHpf, generateVersionXml } from './hwp-xml.js';
|
|
13
|
+
// ── Decompression ──
|
|
14
|
+
async function decompressRaw(data) {
|
|
15
|
+
const ds = new DecompressionStream('deflate-raw');
|
|
16
|
+
const writer = ds.writable.getWriter();
|
|
17
|
+
const reader = ds.readable.getReader();
|
|
18
|
+
writer.write(data);
|
|
19
|
+
writer.close();
|
|
20
|
+
const chunks = [];
|
|
21
|
+
let done = false;
|
|
22
|
+
while (!done) {
|
|
23
|
+
const result = await reader.read();
|
|
24
|
+
if (result.done) {
|
|
25
|
+
done = true;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
chunks.push(result.value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const totalLen = chunks.reduce((acc, c) => acc + c.length, 0);
|
|
32
|
+
const out = new Uint8Array(totalLen);
|
|
33
|
+
let offset = 0;
|
|
34
|
+
for (const chunk of chunks) {
|
|
35
|
+
out.set(chunk, offset);
|
|
36
|
+
offset += chunk.length;
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
// ── Stream access ──
|
|
41
|
+
async function getStream(cfb, path, decompress) {
|
|
42
|
+
const entry = CFB.find(cfb, `/${path}`);
|
|
43
|
+
if (!entry)
|
|
44
|
+
throw new Error(`Stream not found: ${path}`);
|
|
45
|
+
let buf = new Uint8Array(entry.content);
|
|
46
|
+
if (decompress && buf.length > 0) {
|
|
47
|
+
try {
|
|
48
|
+
if (typeof globalThis.__decompressRawSync === 'function') {
|
|
49
|
+
buf = globalThis.__decompressRawSync(buf);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
buf = await decompressRaw(buf);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Some streams might not actually be compressed
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return buf;
|
|
60
|
+
}
|
|
61
|
+
// ── FileHeader ──
|
|
62
|
+
function parseFileHeader(cfb) {
|
|
63
|
+
const entry = CFB.find(cfb, '/FileHeader');
|
|
64
|
+
if (!entry)
|
|
65
|
+
throw new Error('FileHeader stream not found');
|
|
66
|
+
const buf = new Uint8Array(entry.content);
|
|
67
|
+
const view = dataView(buf);
|
|
68
|
+
let sig = '';
|
|
69
|
+
for (let i = 0; i < 32 && buf[i] !== 0; i++) {
|
|
70
|
+
sig += String.fromCharCode(buf[i]);
|
|
71
|
+
}
|
|
72
|
+
if (!sig.startsWith(TAG.HWP_SIGNATURE)) {
|
|
73
|
+
throw new Error(`Invalid HWP signature: ${sig}`);
|
|
74
|
+
}
|
|
75
|
+
const ver = view.getUint32(32, true);
|
|
76
|
+
const flags = view.getUint32(36, true);
|
|
77
|
+
return {
|
|
78
|
+
version: {
|
|
79
|
+
major: (ver >> 24) & 0xFF,
|
|
80
|
+
minor: (ver >> 16) & 0xFF,
|
|
81
|
+
patch: (ver >> 8) & 0xFF,
|
|
82
|
+
revision: ver & 0xFF,
|
|
83
|
+
},
|
|
84
|
+
flags,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// ── BinData extraction ──
|
|
88
|
+
async function extractBinData(cfb, docId, binDataItems) {
|
|
89
|
+
for (const item of binDataItems) {
|
|
90
|
+
if (item.type === 'embedding' && item.binDataId !== undefined && item.extension) {
|
|
91
|
+
const streamName = `BIN${item.binDataId.toString(16).toUpperCase().padStart(4, '0')}.${item.extension}`;
|
|
92
|
+
const entry = CFB.find(cfb, `/BinData/${streamName}`);
|
|
93
|
+
if (entry) {
|
|
94
|
+
const data = new Uint8Array(entry.content);
|
|
95
|
+
await fs.writeFile(docId, `BinData/${streamName}`, data);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// ── Main export ──
|
|
101
|
+
export async function convertHwpToHwpx(data, docId) {
|
|
102
|
+
const uint8 = new Uint8Array(data);
|
|
103
|
+
const cfb = CFB.read(uint8, { type: 'array' });
|
|
104
|
+
const header = parseFileHeader(cfb);
|
|
105
|
+
const isCompressed = (header.flags & 1) !== 0;
|
|
106
|
+
// Parse DocInfo
|
|
107
|
+
const docInfoBuf = await getStream(cfb, 'DocInfo', isCompressed);
|
|
108
|
+
const docInfo = parseDocInfoData(docInfoBuf);
|
|
109
|
+
// Write header.xml
|
|
110
|
+
const headerXml = generateHeaderXml(docInfo);
|
|
111
|
+
await fs.writeFile(docId, 'Contents/header.xml', headerXml);
|
|
112
|
+
// Parse and write each section
|
|
113
|
+
const sectionCount = docInfo.sectionCount;
|
|
114
|
+
for (let i = 0; i < sectionCount; i++) {
|
|
115
|
+
const secBuf = await getStream(cfb, `BodyText/Section${i}`, isCompressed);
|
|
116
|
+
const { pageDef, paragraphs } = parseSectionRecords(secBuf);
|
|
117
|
+
const sectionXml = generateSectionXml(i, pageDef, paragraphs);
|
|
118
|
+
await fs.writeFile(docId, `Contents/section${i}.xml`, sectionXml);
|
|
119
|
+
}
|
|
120
|
+
// Write manifest
|
|
121
|
+
const contentHpf = generateContentHpf(sectionCount);
|
|
122
|
+
await fs.writeFile(docId, 'Contents/content.hpf', contentHpf);
|
|
123
|
+
// Write version.xml
|
|
124
|
+
const versionXml = generateVersionXml(header);
|
|
125
|
+
await fs.writeFile(docId, 'version.xml', versionXml);
|
|
126
|
+
// Extract embedded binary data
|
|
127
|
+
await extractBinData(cfb, docId, docInfo.binDataItems);
|
|
128
|
+
return sectionCount;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converter.js","sourceRoot":"","sources":["../../src/hwp/converter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HWP DocInfo stream parsing: fonts, char shapes, para shapes, border fills, bin data.
|
|
3
|
+
*/
|
|
4
|
+
import type { FontFaceInfo, CharShapeInfo, ParaShapeInfo, BorderFillInfo, BinDataItemInfo, DocInfoData } from './hwp-types.js';
|
|
5
|
+
export declare const BORDER_WIDTHS: number[];
|
|
6
|
+
export declare function parseFontFace(data: Uint8Array): FontFaceInfo;
|
|
7
|
+
export declare function parseCharShape(data: Uint8Array): CharShapeInfo;
|
|
8
|
+
export declare function parseParaShape(data: Uint8Array): ParaShapeInfo;
|
|
9
|
+
export declare function parseBorderFill(data: Uint8Array, id: number): BorderFillInfo;
|
|
10
|
+
export declare function parseBinDataItem(data: Uint8Array): BinDataItemInfo;
|
|
11
|
+
export declare function parseDocInfoData(buf: Uint8Array): DocInfoData;
|