label-studio-converter 1.0.0 → 1.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/README.md +580 -20
- package/dist/bash-complete.cjs +316 -74
- package/dist/bash-complete.cjs.map +1 -1
- package/dist/bash-complete.js +316 -74
- package/dist/bash-complete.js.map +1 -1
- package/dist/cli.cjs +316 -74
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +316 -74
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +199 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -16
- package/dist/index.d.ts +31 -16
- package/dist/index.js +199 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -40,7 +40,96 @@ module.exports = __toCommonJS(lib_exports);
|
|
|
40
40
|
|
|
41
41
|
// src/lib/label-studio.ts
|
|
42
42
|
var turf = __toESM(require("@turf/turf"), 1);
|
|
43
|
-
|
|
43
|
+
|
|
44
|
+
// src/lib/geometry.ts
|
|
45
|
+
function roundToPrecision(value, precision) {
|
|
46
|
+
if (precision < 0) {
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
const multiplier = Math.pow(10, precision);
|
|
50
|
+
return Math.round(value * multiplier) / multiplier;
|
|
51
|
+
}
|
|
52
|
+
function roundPoints(points, precision) {
|
|
53
|
+
if (precision < 0) {
|
|
54
|
+
return points;
|
|
55
|
+
}
|
|
56
|
+
return points.map(
|
|
57
|
+
([x, y]) => [roundToPrecision(x, precision), roundToPrecision(y, precision)]
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
function calculateCenter(points) {
|
|
61
|
+
const sum = points.reduce((acc, [x, y]) => [acc[0] + x, acc[1] + y], [
|
|
62
|
+
0,
|
|
63
|
+
0
|
|
64
|
+
]);
|
|
65
|
+
return [sum[0] / points.length, sum[1] / points.length];
|
|
66
|
+
}
|
|
67
|
+
function getMinimumBoundingRect(points) {
|
|
68
|
+
const minX = Math.min(...points.map(([x]) => x));
|
|
69
|
+
const maxX = Math.max(...points.map(([x]) => x));
|
|
70
|
+
const minY = Math.min(...points.map(([, y]) => y));
|
|
71
|
+
const maxY = Math.max(...points.map(([, y]) => y));
|
|
72
|
+
return {
|
|
73
|
+
minX,
|
|
74
|
+
minY,
|
|
75
|
+
maxX,
|
|
76
|
+
maxY,
|
|
77
|
+
width: maxX - minX,
|
|
78
|
+
height: maxY - minY
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function normalizeShape(points) {
|
|
82
|
+
if (points.length < 3) {
|
|
83
|
+
return points;
|
|
84
|
+
}
|
|
85
|
+
const { minX, minY, maxX, maxY } = getMinimumBoundingRect(points);
|
|
86
|
+
return [
|
|
87
|
+
[minX, minY],
|
|
88
|
+
[maxX, minY],
|
|
89
|
+
[maxX, maxY],
|
|
90
|
+
[minX, maxY]
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
function resizeBoundingBox(points, widthIncrement, heightIncrement) {
|
|
94
|
+
if (points.length === 0) {
|
|
95
|
+
return points;
|
|
96
|
+
}
|
|
97
|
+
const center = calculateCenter(points);
|
|
98
|
+
const bbox = getMinimumBoundingRect(points);
|
|
99
|
+
const newWidth = Math.max(1, bbox.width + widthIncrement);
|
|
100
|
+
const newHeight = Math.max(1, bbox.height + heightIncrement);
|
|
101
|
+
const scaleX = newWidth / bbox.width;
|
|
102
|
+
const scaleY = newHeight / bbox.height;
|
|
103
|
+
return points.map(([x, y]) => {
|
|
104
|
+
const relX = x - center[0];
|
|
105
|
+
const relY = y - center[1];
|
|
106
|
+
return [center[0] + relX * scaleX, center[1] + relY * scaleY];
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function transformPoints(points, options) {
|
|
110
|
+
let result = points;
|
|
111
|
+
if (options.normalizeShape && options.normalizeShape === "rectangle") {
|
|
112
|
+
result = normalizeShape(result);
|
|
113
|
+
}
|
|
114
|
+
if (options.widthIncrement !== void 0 || options.heightIncrement !== void 0) {
|
|
115
|
+
result = resizeBoundingBox(
|
|
116
|
+
result,
|
|
117
|
+
options.widthIncrement ?? 0,
|
|
118
|
+
options.heightIncrement ?? 0
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/lib/label-studio.ts
|
|
125
|
+
var labelStudioToPPOCR = async (data, options) => {
|
|
126
|
+
const {
|
|
127
|
+
baseImageDir,
|
|
128
|
+
normalizeShape: normalizeShape2,
|
|
129
|
+
widthIncrement = 0,
|
|
130
|
+
heightIncrement = 0,
|
|
131
|
+
precision = 0
|
|
132
|
+
} = options || {};
|
|
44
133
|
const resultMap = /* @__PURE__ */ new Map();
|
|
45
134
|
for (const task of data) {
|
|
46
135
|
let imagePath = task.file_upload || "";
|
|
@@ -91,6 +180,12 @@ var labelStudioToPPOCR = async (data, baseImageDir) => {
|
|
|
91
180
|
}
|
|
92
181
|
}
|
|
93
182
|
if (points && points.length > 0) {
|
|
183
|
+
points = transformPoints(points, {
|
|
184
|
+
normalizeShape: normalizeShape2,
|
|
185
|
+
widthIncrement,
|
|
186
|
+
heightIncrement
|
|
187
|
+
});
|
|
188
|
+
points = roundPoints(points, precision);
|
|
94
189
|
let dt_score = 1;
|
|
95
190
|
try {
|
|
96
191
|
const firstPoint = points[0];
|
|
@@ -116,7 +211,14 @@ var labelStudioToPPOCR = async (data, baseImageDir) => {
|
|
|
116
211
|
}
|
|
117
212
|
return resultMap;
|
|
118
213
|
};
|
|
119
|
-
var minLabelStudioToPPOCR = async (data,
|
|
214
|
+
var minLabelStudioToPPOCR = async (data, options) => {
|
|
215
|
+
const {
|
|
216
|
+
baseImageDir,
|
|
217
|
+
normalizeShape: normalizeShape2,
|
|
218
|
+
widthIncrement = 0,
|
|
219
|
+
heightIncrement = 0,
|
|
220
|
+
precision = 0
|
|
221
|
+
} = options || {};
|
|
120
222
|
const resultMap = /* @__PURE__ */ new Map();
|
|
121
223
|
for (const item of data) {
|
|
122
224
|
let imagePath = item.ocr || "";
|
|
@@ -128,43 +230,62 @@ var minLabelStudioToPPOCR = async (data, baseImageDir) => {
|
|
|
128
230
|
if (baseImageDir) {
|
|
129
231
|
imagePath = `${baseImageDir}/${imagePath.split("/").pop() || imagePath}`;
|
|
130
232
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
[
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
233
|
+
const numAnnotations = Math.max(
|
|
234
|
+
item.poly?.length || 0,
|
|
235
|
+
item.bbox?.length || 0,
|
|
236
|
+
item.transcription?.length || 0
|
|
237
|
+
);
|
|
238
|
+
for (let i = 0; i < numAnnotations; i++) {
|
|
239
|
+
let points;
|
|
240
|
+
if (item.poly && item.poly.length > i && item.poly[i]) {
|
|
241
|
+
const poly = item.poly[i];
|
|
242
|
+
if (poly) {
|
|
243
|
+
const { points: polyPoints } = poly;
|
|
244
|
+
points = polyPoints;
|
|
245
|
+
}
|
|
246
|
+
} else if (item.bbox && item.bbox.length > i && item.bbox[i]) {
|
|
247
|
+
const bbox = item.bbox[i];
|
|
248
|
+
if (bbox) {
|
|
249
|
+
const { x, y, width, height } = bbox;
|
|
250
|
+
points = [
|
|
251
|
+
[x, y],
|
|
252
|
+
[x + width, y],
|
|
253
|
+
[x + width, y + height],
|
|
254
|
+
[x, y + height]
|
|
255
|
+
];
|
|
256
|
+
}
|
|
155
257
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
258
|
+
if (!points) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
points = transformPoints(points, {
|
|
262
|
+
normalizeShape: normalizeShape2,
|
|
263
|
+
widthIncrement,
|
|
264
|
+
heightIncrement
|
|
265
|
+
});
|
|
266
|
+
points = roundPoints(points, precision);
|
|
267
|
+
const transcription = item.transcription && item.transcription.length > i ? item.transcription[i] : "";
|
|
268
|
+
let dt_score = 1;
|
|
269
|
+
try {
|
|
270
|
+
const firstPoint = points[0];
|
|
271
|
+
if (firstPoint) {
|
|
272
|
+
const polygon2 = turf.polygon([points.concat([firstPoint])]);
|
|
273
|
+
const area2 = turf.area(polygon2);
|
|
274
|
+
dt_score = Math.min(1, Math.max(0.5, area2 / 1e4));
|
|
275
|
+
}
|
|
276
|
+
} catch {
|
|
277
|
+
dt_score = 0.8;
|
|
278
|
+
}
|
|
279
|
+
const annotation = {
|
|
280
|
+
transcription: transcription ?? "",
|
|
281
|
+
points,
|
|
282
|
+
dt_score
|
|
283
|
+
};
|
|
284
|
+
if (!resultMap.has(imagePath)) {
|
|
285
|
+
resultMap.set(imagePath, []);
|
|
286
|
+
}
|
|
287
|
+
resultMap.get(imagePath).push(annotation);
|
|
166
288
|
}
|
|
167
|
-
resultMap.get(imagePath).push(annotation);
|
|
168
289
|
}
|
|
169
290
|
return resultMap;
|
|
170
291
|
};
|
|
@@ -177,6 +298,7 @@ var import_image_size = __toESM(require("image-size"), 1);
|
|
|
177
298
|
|
|
178
299
|
// src/constants.ts
|
|
179
300
|
var DEFAULT_LABEL_NAME = "Text";
|
|
301
|
+
var DEFAULT_LABEL_STUDIO_PRECISION = -1;
|
|
180
302
|
|
|
181
303
|
// src/lib/ppocr-label.ts
|
|
182
304
|
var ppocrToLabelStudio = async (data, options) => {
|
|
@@ -186,7 +308,11 @@ var ppocrToLabelStudio = async (data, options) => {
|
|
|
186
308
|
inputDir,
|
|
187
309
|
toFullJson = true,
|
|
188
310
|
taskId = 1,
|
|
189
|
-
labelName = DEFAULT_LABEL_NAME
|
|
311
|
+
labelName = DEFAULT_LABEL_NAME,
|
|
312
|
+
normalizeShape: normalizeShape2,
|
|
313
|
+
widthIncrement = 0,
|
|
314
|
+
heightIncrement = 0,
|
|
315
|
+
precision = DEFAULT_LABEL_STUDIO_PRECISION
|
|
190
316
|
} = options || {};
|
|
191
317
|
if (toFullJson) {
|
|
192
318
|
return ppocrToFullLabelStudio(
|
|
@@ -195,7 +321,11 @@ var ppocrToLabelStudio = async (data, options) => {
|
|
|
195
321
|
baseServerUrl,
|
|
196
322
|
inputDir,
|
|
197
323
|
taskId,
|
|
198
|
-
labelName
|
|
324
|
+
labelName,
|
|
325
|
+
normalizeShape2,
|
|
326
|
+
widthIncrement,
|
|
327
|
+
heightIncrement,
|
|
328
|
+
precision
|
|
199
329
|
);
|
|
200
330
|
} else {
|
|
201
331
|
return ppocrToMinLabelStudio(
|
|
@@ -203,11 +333,15 @@ var ppocrToLabelStudio = async (data, options) => {
|
|
|
203
333
|
imagePath,
|
|
204
334
|
baseServerUrl,
|
|
205
335
|
inputDir,
|
|
206
|
-
labelName
|
|
336
|
+
labelName,
|
|
337
|
+
normalizeShape2,
|
|
338
|
+
widthIncrement,
|
|
339
|
+
heightIncrement,
|
|
340
|
+
precision
|
|
207
341
|
);
|
|
208
342
|
}
|
|
209
343
|
};
|
|
210
|
-
var ppocrToFullLabelStudio = (data, imagePath, baseServerUrl, inputDir, taskId = 1, labelName = DEFAULT_LABEL_NAME) => {
|
|
344
|
+
var ppocrToFullLabelStudio = (data, imagePath, baseServerUrl, inputDir, taskId = 1, labelName = DEFAULT_LABEL_NAME, normalizeShape2, widthIncrement = 0, heightIncrement = 0, precision = DEFAULT_LABEL_STUDIO_PRECISION) => {
|
|
211
345
|
const newBaseServerUrl = baseServerUrl.replace(/\/+$/, "") + (baseServerUrl === "" ? "" : "/");
|
|
212
346
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
213
347
|
let original_width = 1920;
|
|
@@ -234,11 +368,16 @@ var ppocrToFullLabelStudio = (data, imagePath, baseServerUrl, inputDir, taskId =
|
|
|
234
368
|
id: taskId,
|
|
235
369
|
completed_by: 1,
|
|
236
370
|
result: data.map((item) => {
|
|
237
|
-
|
|
371
|
+
let { points } = item;
|
|
372
|
+
points = transformPoints(points, {
|
|
373
|
+
normalizeShape: normalizeShape2,
|
|
374
|
+
widthIncrement,
|
|
375
|
+
heightIncrement
|
|
376
|
+
});
|
|
238
377
|
const annotationId = (0, import_node_crypto.randomUUID)().slice(0, 10);
|
|
239
378
|
const polygonPoints = points.map(([x, y]) => [
|
|
240
|
-
(x ?? 0) / original_width * 100,
|
|
241
|
-
(y ?? 0) / original_height * 100
|
|
379
|
+
roundToPrecision((x ?? 0) / original_width * 100, precision),
|
|
380
|
+
roundToPrecision((y ?? 0) / original_height * 100, precision)
|
|
242
381
|
]);
|
|
243
382
|
return [
|
|
244
383
|
// 1. Polygon geometry only
|
|
@@ -332,7 +471,7 @@ var ppocrToFullLabelStudio = (data, imagePath, baseServerUrl, inputDir, taskId =
|
|
|
332
471
|
];
|
|
333
472
|
return result;
|
|
334
473
|
};
|
|
335
|
-
var ppocrToMinLabelStudio = (data, imagePath, baseServerUrl, inputDir, labelName = "text") => {
|
|
474
|
+
var ppocrToMinLabelStudio = (data, imagePath, baseServerUrl, inputDir, labelName = "text", normalizeShape2, widthIncrement = 0, heightIncrement = 0, precision = DEFAULT_LABEL_STUDIO_PRECISION) => {
|
|
336
475
|
const newBaseServerUrl = baseServerUrl.replace(/\/+$/, "") + (baseServerUrl === "" ? "" : "/");
|
|
337
476
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
338
477
|
let original_width = 1920;
|
|
@@ -351,12 +490,23 @@ var ppocrToMinLabelStudio = (data, imagePath, baseServerUrl, inputDir, labelName
|
|
|
351
490
|
original_width = dimensions.width;
|
|
352
491
|
original_height = dimensions.height;
|
|
353
492
|
return data.map((item, index) => {
|
|
354
|
-
|
|
493
|
+
let { points } = item;
|
|
494
|
+
points = transformPoints(points, {
|
|
495
|
+
normalizeShape: normalizeShape2,
|
|
496
|
+
widthIncrement,
|
|
497
|
+
heightIncrement
|
|
498
|
+
});
|
|
499
|
+
const roundedPoints = points.map(
|
|
500
|
+
([x, y]) => [
|
|
501
|
+
roundToPrecision(x ?? 0, precision),
|
|
502
|
+
roundToPrecision(y ?? 0, precision)
|
|
503
|
+
]
|
|
504
|
+
);
|
|
355
505
|
let minX = Infinity;
|
|
356
506
|
let minY = Infinity;
|
|
357
507
|
let maxX = -Infinity;
|
|
358
508
|
let maxY = -Infinity;
|
|
359
|
-
for (const point of
|
|
509
|
+
for (const point of roundedPoints) {
|
|
360
510
|
const [x, y] = point;
|
|
361
511
|
if (x !== void 0 && y !== void 0) {
|
|
362
512
|
minX = Math.min(minX, x);
|
|
@@ -383,7 +533,7 @@ var ppocrToMinLabelStudio = (data, imagePath, baseServerUrl, inputDir, labelName
|
|
|
383
533
|
],
|
|
384
534
|
label: [
|
|
385
535
|
{
|
|
386
|
-
points,
|
|
536
|
+
points: roundedPoints,
|
|
387
537
|
closed: true,
|
|
388
538
|
labels: [labelName],
|
|
389
539
|
original_width,
|
|
@@ -393,7 +543,7 @@ var ppocrToMinLabelStudio = (data, imagePath, baseServerUrl, inputDir, labelName
|
|
|
393
543
|
transcription: [item.transcription],
|
|
394
544
|
poly: [
|
|
395
545
|
{
|
|
396
|
-
points,
|
|
546
|
+
points: roundedPoints,
|
|
397
547
|
closed: true,
|
|
398
548
|
original_width,
|
|
399
549
|
original_height
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/index.ts","../src/lib/label-studio.ts","../src/lib/ppocr-label.ts","../src/constants.ts"],"sourcesContent":["export * from './label-studio';\nexport * from './ppocr-label';\n","import * as turf from '@turf/turf';\nimport {\n type FullOCRLabelStudio,\n type MinOCRLabelStudio,\n type PPOCRLabel,\n} from '@/lib/schema';\n\nexport const labelStudioToPPOCR = async (\n data: FullOCRLabelStudio,\n baseImageDir?: string,\n): Promise<Map<string, PPOCRLabel>> => {\n const resultMap = new Map<string, PPOCRLabel>();\n\n for (const task of data) {\n // Extract image path from data.ocr (full path with URL) or file_upload (just filename)\n let imagePath = task.file_upload || '';\n if (task.data.ocr) {\n // Extract path from URL: http://localhost:8081/ch/image.jpg -> ch/image.jpg\n const urlPath = task.data.ocr.replace(/^https?:\\/\\/[^/]+\\//, '');\n imagePath = decodeURIComponent(urlPath);\n }\n\n // Apply baseImageDir if provided\n if (baseImageDir) {\n imagePath = `${baseImageDir}/${task.file_upload || imagePath.split('/').pop() || imagePath}`;\n }\n\n const imageAnnotations: PPOCRLabel = [];\n\n // Process each annotation in the task\n for (const annotation of task.annotations) {\n // Group result items by their ID to avoid duplicates\n // (polygon, labels, and textarea share the same ID)\n const groupedById = new Map<string, typeof annotation.result>();\n\n for (const resultItem of annotation.result) {\n const { id } = resultItem;\n if (!groupedById.has(id)) {\n groupedById.set(id, []);\n }\n groupedById.get(id)!.push(resultItem);\n }\n\n // Process each group of result items (with same ID)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for (const [_, resultItems] of groupedById) {\n let points: number[][] | undefined;\n let transcription = '';\n\n // Process all result items in this group to extract points and transcription\n for (const resultItem of resultItems) {\n // Extract points from different value types\n if ('points' in resultItem.value && resultItem.value.points) {\n // Polygon/polyline with percentage points - convert to absolute\n const { points: valuePoints } = resultItem.value;\n const { original_width, original_height } = resultItem;\n\n // Convert percentage coordinates to absolute pixels\n points = valuePoints.map(([x, y]) => [\n ((x ?? 0) * original_width) / 100,\n ((y ?? 0) * original_height) / 100,\n ]);\n } else if (\n 'x' in resultItem.value &&\n 'y' in resultItem.value &&\n 'width' in resultItem.value &&\n 'height' in resultItem.value\n ) {\n // Rectangle - convert to 4 corner points\n const { x, y, width, height } = resultItem.value;\n const { original_width, original_height } = resultItem;\n\n // Convert normalized values to absolute coordinates\n const absX = (x * original_width) / 100;\n const absY = (y * original_height) / 100;\n const absWidth = (width * original_width) / 100;\n const absHeight = (height * original_height) / 100;\n\n points = [\n [absX, absY],\n [absX + absWidth, absY],\n [absX + absWidth, absY + absHeight],\n [absX, absY + absHeight],\n ];\n }\n\n // Extract transcription from text field\n if (\n 'text' in resultItem.value &&\n Array.isArray(resultItem.value.text)\n ) {\n transcription = resultItem.value.text[0] || '';\n }\n }\n\n // If we have points, create a PPOCRLabel entry\n if (points && points.length > 0) {\n // Calculate dt_score based on polygon area\n let dt_score = 1.0;\n try {\n const firstPoint = points[0];\n if (firstPoint) {\n const polygon = turf.polygon([points.concat([firstPoint])]);\n const area = turf.area(polygon);\n dt_score = Math.min(1.0, Math.max(0.5, area / 10000));\n }\n } catch {\n dt_score = 0.8;\n }\n\n imageAnnotations.push({\n transcription,\n points,\n dt_score,\n });\n }\n }\n }\n\n if (imageAnnotations.length > 0) {\n resultMap.set(imagePath, imageAnnotations);\n }\n }\n\n return resultMap;\n};\n\nexport const minLabelStudioToPPOCR = async (\n data: MinOCRLabelStudio,\n baseImageDir?: string,\n): Promise<Map<string, PPOCRLabel>> => {\n const resultMap = new Map<string, PPOCRLabel>();\n\n for (const item of data) {\n // Extract image path from ocr URL\n let imagePath = item.ocr || '';\n if (imagePath) {\n // Extract path from URL: http://localhost:8081/ch/image.jpg -> ch/image.jpg\n imagePath = decodeURIComponent(\n imagePath.replace(/^https?:\\/\\/[^/]+\\//, ''),\n );\n }\n\n // Apply baseImageDir if provided\n if (baseImageDir) {\n imagePath = `${baseImageDir}/${imagePath.split('/').pop() || imagePath}`;\n }\n\n // Use poly if available, otherwise convert from bbox\n let points: number[][];\n\n if (item.poly.length > 0 && item.poly[0]) {\n const { points: polyPoints } = item.poly[0];\n points = polyPoints;\n } else if (item.bbox.length > 0 && item.bbox[0]) {\n const bbox = item.bbox[0];\n const { x, y, width, height } = bbox;\n\n // Convert bbox to 4 corner points\n points = [\n [x, y],\n [x + width, y],\n [x + width, y + height],\n [x, y + height],\n ];\n } else {\n // Skip if no geometry data\n continue;\n }\n\n // Get transcription text (not the URL)\n const transcription =\n item.transcription.length > 0 ? item.transcription[0] : '';\n\n // Calculate dt_score based on polygon area\n let dt_score = 1.0;\n try {\n const firstPoint = points[0];\n if (firstPoint) {\n const polygon = turf.polygon([points.concat([firstPoint])]);\n const area = turf.area(polygon);\n dt_score = Math.min(1.0, Math.max(0.5, area / 10000));\n }\n } catch {\n dt_score = 0.8;\n }\n\n const annotation = {\n transcription: transcription ?? '',\n points,\n dt_score,\n };\n\n // Group by image path\n if (!resultMap.has(imagePath)) {\n resultMap.set(imagePath, []);\n }\n resultMap.get(imagePath)!.push(annotation);\n }\n\n return resultMap;\n};\n","import { randomUUID } from 'node:crypto';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport sizeOf from 'image-size';\nimport { DEFAULT_LABEL_NAME } from '@/constants';\nimport {\n type FullOCRLabelStudio,\n type MinOCRLabelStudio,\n type PPOCRLabel,\n} from '@/lib/schema';\n\nexport type ToLabelStudioOptions = {\n imagePath: string;\n baseServerUrl: string;\n inputDir?: string;\n toFullJson?: boolean;\n taskId?: number;\n labelName?: string;\n};\n\nexport const ppocrToLabelStudio = async (\n data: PPOCRLabel,\n options: ToLabelStudioOptions,\n): Promise<FullOCRLabelStudio | MinOCRLabelStudio> => {\n const {\n imagePath,\n baseServerUrl,\n inputDir,\n toFullJson = true,\n taskId = 1,\n labelName = DEFAULT_LABEL_NAME,\n } = options || {};\n\n if (toFullJson) {\n return ppocrToFullLabelStudio(\n data,\n imagePath,\n baseServerUrl,\n inputDir,\n taskId,\n labelName,\n );\n } else {\n return ppocrToMinLabelStudio(\n data,\n imagePath,\n baseServerUrl,\n inputDir,\n labelName,\n );\n }\n};\n\nexport const ppocrToFullLabelStudio = (\n data: PPOCRLabel,\n imagePath: string,\n baseServerUrl: string,\n inputDir?: string,\n taskId: number = 1,\n labelName: string = DEFAULT_LABEL_NAME,\n): FullOCRLabelStudio => {\n const newBaseServerUrl =\n baseServerUrl.replace(/\\/+$/, '') + (baseServerUrl === '' ? '' : '/');\n\n const now = new Date().toISOString();\n\n // Get actual image dimensions from the image file\n let original_width = 1920;\n let original_height = 1080;\n\n // Resolve absolute path to image file\n const resolvedImagePath = inputDir ? join(inputDir, imagePath) : imagePath;\n\n if (!existsSync(resolvedImagePath)) {\n throw new Error(`Image file not found: ${resolvedImagePath}`);\n }\n\n const buffer = readFileSync(resolvedImagePath);\n const dimensions = sizeOf(buffer);\n if (!dimensions.width || !dimensions.height) {\n throw new Error(\n `Failed to read image dimensions from: ${resolvedImagePath}`,\n );\n }\n original_width = dimensions.width;\n original_height = dimensions.height;\n\n // Extract filename from imagePath for file_upload (just the filename)\n const fileName = imagePath.split('/').pop() || imagePath;\n\n // Group all PPOCRLabel items into a single task with one annotation\n const result: FullOCRLabelStudio = [\n {\n id: taskId,\n annotations: [\n {\n id: taskId,\n completed_by: 1,\n result: data\n .map((item) => {\n const { points } = item;\n\n // Generate a single ID for all three related annotations\n const annotationId = randomUUID().slice(0, 10);\n const polygonPoints = points.map(([x, y]) => [\n ((x ?? 0) / original_width) * 100,\n ((y ?? 0) / original_height) * 100,\n ]);\n\n // Create result items: polygon, labels, and textarea\n return [\n // 1. Polygon geometry only\n {\n original_width,\n original_height,\n image_rotation: 0,\n value: {\n points: polygonPoints,\n closed: true,\n },\n id: annotationId,\n from_name: 'poly',\n to_name: 'image',\n type: 'polygon',\n origin: 'manual',\n },\n // 2. Labels with polygon geometry\n {\n original_width,\n original_height,\n image_rotation: 0,\n value: {\n points: polygonPoints,\n closed: true,\n labels: [labelName],\n },\n id: annotationId,\n from_name: 'label',\n to_name: 'image',\n type: 'labels',\n origin: 'manual',\n },\n // 3. Textarea with polygon geometry and text\n {\n original_width,\n original_height,\n image_rotation: 0,\n value: {\n points: polygonPoints,\n closed: true,\n text: [item.transcription],\n },\n id: annotationId,\n from_name: 'transcription',\n to_name: 'image',\n type: 'textarea',\n origin: 'manual',\n },\n ];\n })\n .flat(),\n was_cancelled: false,\n ground_truth: false,\n created_at: now,\n updated_at: now,\n draft_created_at: now,\n lead_time: 0,\n prediction: {},\n result_count: data.length * 3,\n unique_id: randomUUID(),\n import_id: null,\n last_action: null,\n bulk_created: false,\n task: taskId,\n project: 1,\n updated_by: 1,\n parent_prediction: null,\n parent_annotation: null,\n last_created_by: null,\n },\n ],\n file_upload: fileName,\n drafts: [],\n predictions: [],\n data: { ocr: `${newBaseServerUrl}${imagePath}` },\n meta: {},\n created_at: now,\n updated_at: now,\n allow_skip: false,\n inner_id: taskId,\n total_annotations: 1,\n cancelled_annotations: 0,\n total_predictions: 0,\n comment_count: 0,\n unresolved_comment_count: 0,\n last_comment_updated_at: null,\n project: 1,\n updated_by: 1,\n comment_authors: [],\n },\n ];\n\n return result;\n};\n\nexport const ppocrToMinLabelStudio = (\n data: PPOCRLabel,\n imagePath: string,\n baseServerUrl: string,\n inputDir?: string,\n labelName: string = 'text',\n): MinOCRLabelStudio => {\n const newBaseServerUrl =\n baseServerUrl.replace(/\\/+$/, '') + (baseServerUrl === '' ? '' : '/');\n\n const now = new Date().toISOString();\n\n // Get actual image dimensions from the image file\n let original_width = 1920;\n let original_height = 1080;\n\n // Resolve absolute path to image file\n const resolvedImagePath = inputDir ? join(inputDir, imagePath) : imagePath;\n\n if (!existsSync(resolvedImagePath)) {\n throw new Error(`Image file not found: ${resolvedImagePath}`);\n }\n\n const buffer = readFileSync(resolvedImagePath);\n const dimensions = sizeOf(buffer);\n if (!dimensions.width || !dimensions.height) {\n throw new Error(\n `Failed to read image dimensions from: ${resolvedImagePath}`,\n );\n }\n original_width = dimensions.width;\n original_height = dimensions.height;\n\n return data.map((item, index) => {\n const { points } = item;\n\n // Calculate bbox from points\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const point of points) {\n const [x, y] = point;\n if (x !== undefined && y !== undefined) {\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\n }\n\n const width = maxX - minX;\n const height = maxY - minY;\n\n return {\n ocr: encodeURI(`${newBaseServerUrl}${imagePath}`),\n id: index + 1,\n bbox: [\n {\n x: minX,\n y: minY,\n width,\n height,\n rotation: 0,\n original_width,\n original_height,\n },\n ],\n label: [\n {\n points: points,\n closed: true,\n labels: [labelName],\n original_width,\n original_height,\n },\n ],\n transcription: [item.transcription],\n poly: [\n {\n points: points,\n closed: true,\n original_width,\n original_height,\n },\n ],\n annotator: 1,\n annotation_id: index + 1,\n created_at: now,\n updated_at: now,\n lead_time: 0,\n };\n });\n};\n","export const OUTPUT_BASE_DIR = './output';\n\nexport const DEFAULT_LABEL_NAME = 'Text';\nexport const DEFAULT_LABEL_STUDIO_FULL_JSON = true;\nexport const DEFAULT_CREATE_FILE_PER_IMAGE = false;\nexport const DEFAULT_CREATE_FILE_LIST_FOR_SERVING = true;\nexport const DEFAULT_FILE_LIST_NAME = 'files.txt';\nexport const DEFAULT_BASE_SERVER_URL = 'http://localhost:8081';\n\nexport const DEFAULT_PPOCR_FILE_NAME = 'Label.txt';\n\n// Vertical sorting options\nexport const SORT_VERTICAL_NONE = 'none';\nexport const SORT_VERTICAL_TOP_BOTTOM = 'top-bottom';\nexport const SORT_VERTICAL_BOTTOM_TOP = 'bottom-top';\nexport const DEFAULT_SORT_VERTICAL = SORT_VERTICAL_NONE;\n\n// Horizontal sorting options\nexport const SORT_HORIZONTAL_NONE = 'none';\nexport const SORT_HORIZONTAL_LTR = 'ltr';\nexport const SORT_HORIZONTAL_RTL = 'rtl';\nexport const DEFAULT_SORT_HORIZONTAL = SORT_HORIZONTAL_NONE;\n\nexport type VerticalSortOrder =\n | typeof SORT_VERTICAL_NONE\n | typeof SORT_VERTICAL_TOP_BOTTOM\n | typeof SORT_VERTICAL_BOTTOM_TOP;\n\nexport type HorizontalSortOrder =\n | typeof SORT_HORIZONTAL_NONE\n | typeof SORT_HORIZONTAL_LTR\n | typeof SORT_HORIZONTAL_RTL;\n"],"mappings":"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","names":["polygon","area","sizeOf"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/index.ts","../src/lib/label-studio.ts","../src/lib/geometry.ts","../src/lib/ppocr-label.ts","../src/constants.ts"],"sourcesContent":["export * from './label-studio';\nexport * from './ppocr-label';\n","import * as turf from '@turf/turf';\nimport { type ShapeNormalizeOption } from '@/constants';\nimport { type Point, roundPoints, transformPoints } from '@/lib/geometry';\nimport {\n type FullOCRLabelStudio,\n type MinOCRLabelStudio,\n type PPOCRLabel,\n} from '@/lib/schema';\n\nexport interface ConversionOptions {\n baseImageDir?: string;\n normalizeShape?: ShapeNormalizeOption;\n widthIncrement?: number;\n heightIncrement?: number;\n precision?: number;\n}\n\nexport const labelStudioToPPOCR = async (\n data: FullOCRLabelStudio,\n options?: ConversionOptions,\n): Promise<Map<string, PPOCRLabel>> => {\n const {\n baseImageDir,\n normalizeShape,\n widthIncrement = 0,\n heightIncrement = 0,\n precision = 0,\n } = options || {};\n const resultMap = new Map<string, PPOCRLabel>();\n\n for (const task of data) {\n // Extract image path from data.ocr (full path with URL) or file_upload (just filename)\n let imagePath = task.file_upload || '';\n if (task.data.ocr) {\n // Extract path from URL: http://localhost:8081/ch/image.jpg -> ch/image.jpg\n const urlPath = task.data.ocr.replace(/^https?:\\/\\/[^/]+\\//, '');\n imagePath = decodeURIComponent(urlPath);\n }\n\n // Apply baseImageDir if provided\n if (baseImageDir) {\n imagePath = `${baseImageDir}/${task.file_upload || imagePath.split('/').pop() || imagePath}`;\n }\n\n const imageAnnotations: PPOCRLabel = [];\n\n // Process each annotation in the task\n for (const annotation of task.annotations) {\n // Group result items by their ID to avoid duplicates\n // (polygon, labels, and textarea share the same ID)\n const groupedById = new Map<string, typeof annotation.result>();\n\n for (const resultItem of annotation.result) {\n const { id } = resultItem;\n if (!groupedById.has(id)) {\n groupedById.set(id, []);\n }\n groupedById.get(id)!.push(resultItem);\n }\n\n // Process each group of result items (with same ID)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for (const [_, resultItems] of groupedById) {\n let points: number[][] | undefined;\n let transcription = '';\n\n // Process all result items in this group to extract points and transcription\n for (const resultItem of resultItems) {\n // Extract points from different value types\n if ('points' in resultItem.value && resultItem.value.points) {\n // Polygon/polyline with percentage points - convert to absolute\n const { points: valuePoints } = resultItem.value;\n const { original_width, original_height } = resultItem;\n\n // Convert percentage coordinates to absolute pixels\n points = valuePoints.map(([x, y]) => [\n ((x ?? 0) * original_width) / 100,\n ((y ?? 0) * original_height) / 100,\n ]);\n } else if (\n 'x' in resultItem.value &&\n 'y' in resultItem.value &&\n 'width' in resultItem.value &&\n 'height' in resultItem.value\n ) {\n // Rectangle - convert to 4 corner points\n const { x, y, width, height } = resultItem.value;\n const { original_width, original_height } = resultItem;\n\n // Convert normalized values to absolute coordinates\n const absX = (x * original_width) / 100;\n const absY = (y * original_height) / 100;\n const absWidth = (width * original_width) / 100;\n const absHeight = (height * original_height) / 100;\n\n points = [\n [absX, absY],\n [absX + absWidth, absY],\n [absX + absWidth, absY + absHeight],\n [absX, absY + absHeight],\n ];\n }\n\n // Extract transcription from text field\n if (\n 'text' in resultItem.value &&\n Array.isArray(resultItem.value.text)\n ) {\n transcription = resultItem.value.text[0] || '';\n }\n }\n\n // If we have points, create a PPOCRLabel entry\n if (points && points.length > 0) {\n // Apply geometry transformations\n points = transformPoints(points as Point[], {\n normalizeShape,\n widthIncrement,\n heightIncrement,\n });\n\n // Round points to specified precision\n points = roundPoints(points as Point[], precision);\n\n // Calculate dt_score based on polygon area\n let dt_score = 1.0;\n try {\n const firstPoint = points[0];\n if (firstPoint) {\n const polygon = turf.polygon([points.concat([firstPoint])]);\n const area = turf.area(polygon);\n dt_score = Math.min(1.0, Math.max(0.5, area / 10000));\n }\n } catch {\n dt_score = 0.8;\n }\n\n imageAnnotations.push({\n transcription,\n points,\n dt_score,\n });\n }\n }\n }\n\n if (imageAnnotations.length > 0) {\n resultMap.set(imagePath, imageAnnotations);\n }\n }\n\n return resultMap;\n};\n\nexport const minLabelStudioToPPOCR = async (\n data: MinOCRLabelStudio,\n options?: ConversionOptions,\n): Promise<Map<string, PPOCRLabel>> => {\n const {\n baseImageDir,\n normalizeShape,\n widthIncrement = 0,\n heightIncrement = 0,\n precision = 0,\n } = options || {};\n const resultMap = new Map<string, PPOCRLabel>();\n\n for (const item of data) {\n // Extract image path from ocr URL\n let imagePath = item.ocr || '';\n if (imagePath) {\n // Extract path from URL: http://localhost:8081/ch/image.jpg -> ch/image.jpg\n imagePath = decodeURIComponent(\n imagePath.replace(/^https?:\\/\\/[^/]+\\//, ''),\n );\n }\n\n // Apply baseImageDir if provided\n if (baseImageDir) {\n imagePath = `${baseImageDir}/${imagePath.split('/').pop() || imagePath}`;\n }\n\n // Process each bbox/poly with its corresponding transcription\n const numAnnotations = Math.max(\n item.poly?.length || 0,\n item.bbox?.length || 0,\n item.transcription?.length || 0,\n );\n\n for (let i = 0; i < numAnnotations; i++) {\n let points: number[][] | undefined;\n\n // Use poly if available, otherwise convert from bbox\n if (item.poly && item.poly.length > i && item.poly[i]) {\n const poly = item.poly[i];\n if (poly) {\n const { points: polyPoints } = poly;\n points = polyPoints;\n }\n } else if (item.bbox && item.bbox.length > i && item.bbox[i]) {\n const bbox = item.bbox[i];\n if (bbox) {\n const { x, y, width, height } = bbox;\n\n // Convert bbox to 4 corner points\n points = [\n [x, y],\n [x + width, y],\n [x + width, y + height],\n [x, y + height],\n ];\n }\n }\n\n // Skip if no geometry data for this annotation\n if (!points) {\n continue;\n }\n\n // Apply geometry transformations\n points = transformPoints(points as Point[], {\n normalizeShape,\n widthIncrement,\n heightIncrement,\n });\n\n // Round points to specified precision\n points = roundPoints(points as Point[], precision);\n\n // Get transcription text for this annotation\n const transcription =\n item.transcription && item.transcription.length > i\n ? item.transcription[i]\n : '';\n\n // Calculate dt_score based on polygon area\n let dt_score = 1.0;\n try {\n const firstPoint = points[0];\n if (firstPoint) {\n const polygon = turf.polygon([points.concat([firstPoint])]);\n const area = turf.area(polygon);\n dt_score = Math.min(1.0, Math.max(0.5, area / 10000));\n }\n } catch {\n dt_score = 0.8;\n }\n\n const annotation = {\n transcription: transcription ?? '',\n points,\n dt_score,\n };\n\n // Group by image path\n if (!resultMap.has(imagePath)) {\n resultMap.set(imagePath, []);\n }\n resultMap.get(imagePath)!.push(annotation);\n }\n }\n\n return resultMap;\n};\n","/**\n * Geometry utility functions for shape normalization and bounding box operations\n */\n\nimport type { ShapeNormalizeOption } from '@/constants';\n\nexport type Point = [number, number];\n\n/**\n * Round a number to a specified precision\n * @param value - The number to round\n * @param precision - Number of decimal places (-1 means no rounding)\n * @returns Rounded number\n */\nexport function roundToPrecision(value: number, precision: number): number {\n if (precision < 0) {\n return value; // No rounding\n }\n const multiplier = Math.pow(10, precision);\n return Math.round(value * multiplier) / multiplier;\n}\n\n/**\n * Round points array to a specified precision\n * @param points - Array of points to round\n * @param precision - Number of decimal places (-1 means no rounding)\n * @returns Rounded points\n */\nexport function roundPoints(points: Point[], precision: number): Point[] {\n if (precision < 0) {\n return points; // No rounding\n }\n return points.map(\n ([x, y]) =>\n [roundToPrecision(x, precision), roundToPrecision(y, precision)] as Point,\n );\n}\n\n/**\n * Calculate the center point of a polygon\n */\nexport function calculateCenter(points: Point[]): Point {\n const sum = points.reduce((acc, [x, y]) => [acc[0] + x, acc[1] + y], [\n 0, 0,\n ] as Point);\n return [sum[0] / points.length, sum[1] / points.length];\n}\n\n/**\n * Calculate the minimum bounding rectangle of a polygon\n */\nexport function getMinimumBoundingRect(points: Point[]): {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n width: number;\n height: number;\n} {\n const minX = Math.min(...points.map(([x]) => x));\n const maxX = Math.max(...points.map(([x]) => x));\n const minY = Math.min(...points.map(([, y]) => y));\n const maxY = Math.max(...points.map(([, y]) => y));\n\n return {\n minX,\n minY,\n maxX,\n maxY,\n width: maxX - minX,\n height: maxY - minY,\n };\n}\n\n/**\n * Convert diamond-like shapes to axis-aligned rectangles\n * @param points - Array of points representing the shape\n * @returns Normalized rectangle points\n */\nexport function normalizeShape(points: Point[]): Point[] {\n if (points.length < 3) {\n return points;\n }\n\n // Convert to axis-aligned bounding rectangle\n const { minX, minY, maxX, maxY } = getMinimumBoundingRect(points);\n\n return [\n [minX, minY],\n [maxX, minY],\n [maxX, maxY],\n [minX, maxY],\n ];\n}\n\n/**\n * Resize bounding box by a certain amount while keeping it centered\n * @param points - Array of points representing the bounding box\n * @param widthIncrement - Amount to increase width (can be negative to decrease)\n * @param heightIncrement - Amount to increase height (can be negative to decrease)\n * @returns Resized points\n */\nexport function resizeBoundingBox(\n points: Point[],\n widthIncrement: number,\n heightIncrement: number,\n): Point[] {\n if (points.length === 0) {\n return points;\n }\n\n // Calculate center\n const center = calculateCenter(points);\n\n // Calculate current bounding box\n const bbox = getMinimumBoundingRect(points);\n\n // Calculate new dimensions\n const newWidth = Math.max(1, bbox.width + widthIncrement);\n const newHeight = Math.max(1, bbox.height + heightIncrement);\n\n // Calculate scale factors\n const scaleX = newWidth / bbox.width;\n const scaleY = newHeight / bbox.height;\n\n // Transform each point: translate to origin, scale, translate back\n return points.map(([x, y]) => {\n const relX = x - center[0];\n const relY = y - center[1];\n\n return [center[0] + relX * scaleX, center[1] + relY * scaleY] as Point;\n });\n}\n\n/**\n * Apply geometry transformations to points\n * @param points - Original points\n * @param options - Transformation options\n * @returns Transformed points\n */\nexport function transformPoints(\n points: Point[],\n options: {\n normalizeShape?: ShapeNormalizeOption;\n widthIncrement?: number;\n heightIncrement?: number;\n },\n): Point[] {\n let result = points;\n\n // Apply shape normalization first\n if (options.normalizeShape && options.normalizeShape === 'rectangle') {\n result = normalizeShape(result);\n }\n\n // Then apply resizing\n if (\n options.widthIncrement !== undefined ||\n options.heightIncrement !== undefined\n ) {\n result = resizeBoundingBox(\n result,\n options.widthIncrement ?? 0,\n options.heightIncrement ?? 0,\n );\n }\n\n return result;\n}\n","import { randomUUID } from 'node:crypto';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport sizeOf from 'image-size';\nimport {\n DEFAULT_LABEL_NAME,\n DEFAULT_LABEL_STUDIO_PRECISION,\n type ShapeNormalizeOption,\n} from '@/constants';\nimport { type Point, roundToPrecision, transformPoints } from '@/lib/geometry';\nimport {\n type FullOCRLabelStudio,\n type MinOCRLabelStudio,\n type PPOCRLabel,\n} from '@/lib/schema';\n\nexport type ToLabelStudioOptions = {\n imagePath: string;\n baseServerUrl: string;\n inputDir?: string;\n toFullJson?: boolean;\n taskId?: number;\n labelName?: string;\n normalizeShape?: ShapeNormalizeOption;\n widthIncrement?: number;\n heightIncrement?: number;\n precision?: number;\n};\n\nexport const ppocrToLabelStudio = async (\n data: PPOCRLabel,\n options: ToLabelStudioOptions,\n): Promise<FullOCRLabelStudio | MinOCRLabelStudio> => {\n const {\n imagePath,\n baseServerUrl,\n inputDir,\n toFullJson = true,\n taskId = 1,\n labelName = DEFAULT_LABEL_NAME,\n normalizeShape,\n widthIncrement = 0,\n heightIncrement = 0,\n precision = DEFAULT_LABEL_STUDIO_PRECISION,\n } = options || {};\n\n if (toFullJson) {\n return ppocrToFullLabelStudio(\n data,\n imagePath,\n baseServerUrl,\n inputDir,\n taskId,\n labelName,\n normalizeShape,\n widthIncrement,\n heightIncrement,\n precision,\n );\n } else {\n return ppocrToMinLabelStudio(\n data,\n imagePath,\n baseServerUrl,\n inputDir,\n labelName,\n normalizeShape,\n widthIncrement,\n heightIncrement,\n precision,\n );\n }\n};\n\nexport const ppocrToFullLabelStudio = (\n data: PPOCRLabel,\n imagePath: string,\n baseServerUrl: string,\n inputDir?: string,\n taskId: number = 1,\n labelName: string = DEFAULT_LABEL_NAME,\n normalizeShape?: ShapeNormalizeOption,\n widthIncrement: number = 0,\n heightIncrement: number = 0,\n precision: number = DEFAULT_LABEL_STUDIO_PRECISION,\n): FullOCRLabelStudio => {\n const newBaseServerUrl =\n baseServerUrl.replace(/\\/+$/, '') + (baseServerUrl === '' ? '' : '/');\n\n const now = new Date().toISOString();\n\n // Get actual image dimensions from the image file\n let original_width = 1920;\n let original_height = 1080;\n\n // Resolve absolute path to image file\n const resolvedImagePath = inputDir ? join(inputDir, imagePath) : imagePath;\n\n if (!existsSync(resolvedImagePath)) {\n throw new Error(`Image file not found: ${resolvedImagePath}`);\n }\n\n const buffer = readFileSync(resolvedImagePath);\n const dimensions = sizeOf(buffer);\n if (!dimensions.width || !dimensions.height) {\n throw new Error(\n `Failed to read image dimensions from: ${resolvedImagePath}`,\n );\n }\n original_width = dimensions.width;\n original_height = dimensions.height;\n\n // Extract filename from imagePath for file_upload (just the filename)\n const fileName = imagePath.split('/').pop() || imagePath;\n\n // Group all PPOCRLabel items into a single task with one annotation\n const result: FullOCRLabelStudio = [\n {\n id: taskId,\n annotations: [\n {\n id: taskId,\n completed_by: 1,\n result: data\n .map((item) => {\n let { points } = item;\n\n // Apply geometry transformations\n points = transformPoints(points as Point[], {\n normalizeShape,\n widthIncrement,\n heightIncrement,\n });\n\n // Generate a single ID for all three related annotations\n const annotationId = randomUUID().slice(0, 10);\n const polygonPoints = points.map(([x, y]) => [\n roundToPrecision(((x ?? 0) / original_width) * 100, precision),\n roundToPrecision(((y ?? 0) / original_height) * 100, precision),\n ]);\n\n // Create result items: polygon, labels, and textarea\n return [\n // 1. Polygon geometry only\n {\n original_width,\n original_height,\n image_rotation: 0,\n value: {\n points: polygonPoints,\n closed: true,\n },\n id: annotationId,\n from_name: 'poly',\n to_name: 'image',\n type: 'polygon',\n origin: 'manual',\n },\n // 2. Labels with polygon geometry\n {\n original_width,\n original_height,\n image_rotation: 0,\n value: {\n points: polygonPoints,\n closed: true,\n labels: [labelName],\n },\n id: annotationId,\n from_name: 'label',\n to_name: 'image',\n type: 'labels',\n origin: 'manual',\n },\n // 3. Textarea with polygon geometry and text\n {\n original_width,\n original_height,\n image_rotation: 0,\n value: {\n points: polygonPoints,\n closed: true,\n text: [item.transcription],\n },\n id: annotationId,\n from_name: 'transcription',\n to_name: 'image',\n type: 'textarea',\n origin: 'manual',\n },\n ];\n })\n .flat(),\n was_cancelled: false,\n ground_truth: false,\n created_at: now,\n updated_at: now,\n draft_created_at: now,\n lead_time: 0,\n prediction: {},\n result_count: data.length * 3,\n unique_id: randomUUID(),\n import_id: null,\n last_action: null,\n bulk_created: false,\n task: taskId,\n project: 1,\n updated_by: 1,\n parent_prediction: null,\n parent_annotation: null,\n last_created_by: null,\n },\n ],\n file_upload: fileName,\n drafts: [],\n predictions: [],\n data: { ocr: `${newBaseServerUrl}${imagePath}` },\n meta: {},\n created_at: now,\n updated_at: now,\n allow_skip: false,\n inner_id: taskId,\n total_annotations: 1,\n cancelled_annotations: 0,\n total_predictions: 0,\n comment_count: 0,\n unresolved_comment_count: 0,\n last_comment_updated_at: null,\n project: 1,\n updated_by: 1,\n comment_authors: [],\n },\n ];\n\n return result;\n};\n\nexport const ppocrToMinLabelStudio = (\n data: PPOCRLabel,\n imagePath: string,\n baseServerUrl: string,\n inputDir?: string,\n labelName: string = 'text',\n normalizeShape?: ShapeNormalizeOption,\n widthIncrement: number = 0,\n heightIncrement: number = 0,\n precision: number = DEFAULT_LABEL_STUDIO_PRECISION,\n): MinOCRLabelStudio => {\n const newBaseServerUrl =\n baseServerUrl.replace(/\\/+$/, '') + (baseServerUrl === '' ? '' : '/');\n\n const now = new Date().toISOString();\n\n // Get actual image dimensions from the image file\n let original_width = 1920;\n let original_height = 1080;\n\n // Resolve absolute path to image file\n const resolvedImagePath = inputDir ? join(inputDir, imagePath) : imagePath;\n\n if (!existsSync(resolvedImagePath)) {\n throw new Error(`Image file not found: ${resolvedImagePath}`);\n }\n\n const buffer = readFileSync(resolvedImagePath);\n const dimensions = sizeOf(buffer);\n if (!dimensions.width || !dimensions.height) {\n throw new Error(\n `Failed to read image dimensions from: ${resolvedImagePath}`,\n );\n }\n original_width = dimensions.width;\n original_height = dimensions.height;\n\n return data.map((item, index) => {\n let { points } = item;\n\n // Apply geometry transformations\n points = transformPoints(points as Point[], {\n normalizeShape,\n widthIncrement,\n heightIncrement,\n });\n\n // Round coordinates based on precision first\n const roundedPoints = points.map(\n ([x, y]) =>\n [\n roundToPrecision(x ?? 0, precision),\n roundToPrecision(y ?? 0, precision),\n ] as [number, number],\n );\n\n // Calculate bbox from rounded points\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const point of roundedPoints) {\n const [x, y] = point;\n if (x !== undefined && y !== undefined) {\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\n }\n\n const width = maxX - minX;\n const height = maxY - minY;\n\n return {\n ocr: encodeURI(`${newBaseServerUrl}${imagePath}`),\n id: index + 1,\n bbox: [\n {\n x: minX,\n y: minY,\n width: width,\n height: height,\n rotation: 0,\n original_width,\n original_height,\n },\n ],\n label: [\n {\n points: roundedPoints,\n closed: true,\n labels: [labelName],\n original_width,\n original_height,\n },\n ],\n transcription: [item.transcription],\n poly: [\n {\n points: roundedPoints,\n closed: true,\n original_width,\n original_height,\n },\n ],\n annotator: 1,\n annotation_id: index + 1,\n created_at: now,\n updated_at: now,\n lead_time: 0,\n };\n });\n};\n","export const OUTPUT_BASE_DIR = './output';\n\nexport const DEFAULT_LABEL_NAME = 'Text';\nexport const DEFAULT_LABEL_STUDIO_FULL_JSON = true;\nexport const DEFAULT_CREATE_FILE_PER_IMAGE = false;\nexport const DEFAULT_CREATE_FILE_LIST_FOR_SERVING = true;\nexport const DEFAULT_FILE_LIST_NAME = 'files.txt';\nexport const DEFAULT_BASE_SERVER_URL = 'http://localhost:8081';\n\nexport const DEFAULT_PPOCR_FILE_NAME = 'Label.txt';\n\n// Vertical sorting options\nexport const SORT_VERTICAL_NONE = 'none';\nexport const SORT_VERTICAL_TOP_BOTTOM = 'top-bottom';\nexport const SORT_VERTICAL_BOTTOM_TOP = 'bottom-top';\nexport const DEFAULT_SORT_VERTICAL = SORT_VERTICAL_NONE;\n\n// Horizontal sorting options\nexport const SORT_HORIZONTAL_NONE = 'none';\nexport const SORT_HORIZONTAL_LTR = 'ltr';\nexport const SORT_HORIZONTAL_RTL = 'rtl';\nexport const DEFAULT_SORT_HORIZONTAL = SORT_HORIZONTAL_NONE;\n\nexport type VerticalSortOrder =\n | typeof SORT_VERTICAL_NONE\n | typeof SORT_VERTICAL_TOP_BOTTOM\n | typeof SORT_VERTICAL_BOTTOM_TOP;\n\nexport type HorizontalSortOrder =\n | typeof SORT_HORIZONTAL_NONE\n | typeof SORT_HORIZONTAL_LTR\n | typeof SORT_HORIZONTAL_RTL;\n\n// Shape normalization options\nexport const SHAPE_NORMALIZE_NONE = 'none';\nexport const SHAPE_NORMALIZE_RECTANGLE = 'rectangle';\nexport const DEFAULT_SHAPE_NORMALIZE = SHAPE_NORMALIZE_NONE;\n\nexport type ShapeNormalizeOption =\n | typeof SHAPE_NORMALIZE_NONE\n | typeof SHAPE_NORMALIZE_RECTANGLE;\n\n// Bounding box resize options\nexport const DEFAULT_WIDTH_INCREMENT = 0;\nexport const DEFAULT_HEIGHT_INCREMENT = 0;\n\n// Number precision options\n// For Label Studio: keep full precision (no rounding) by default\nexport const DEFAULT_LABEL_STUDIO_PRECISION = -1; // -1 means no rounding\n// For PPOCR: round to integers\nexport const DEFAULT_PPOCR_PRECISION = 0;\n"],"mappings":"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","names":["normalizeShape","polygon","area","normalizeShape","sizeOf"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
2
|
|
|
3
|
+
declare const SHAPE_NORMALIZE_NONE = "none";
|
|
4
|
+
declare const SHAPE_NORMALIZE_RECTANGLE = "rectangle";
|
|
5
|
+
type ShapeNormalizeOption = typeof SHAPE_NORMALIZE_NONE | typeof SHAPE_NORMALIZE_RECTANGLE;
|
|
6
|
+
|
|
3
7
|
declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
4
8
|
id: z.ZodNumber;
|
|
5
9
|
annotations: z.ZodArray<z.ZodObject<{
|
|
@@ -15,6 +19,7 @@ declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
15
19
|
width: z.ZodNumber;
|
|
16
20
|
height: z.ZodNumber;
|
|
17
21
|
rotation: z.ZodNumber;
|
|
22
|
+
text: z.ZodArray<z.ZodString>;
|
|
18
23
|
}, z.core.$strip>;
|
|
19
24
|
id: z.ZodString;
|
|
20
25
|
from_name: z.ZodString;
|
|
@@ -48,7 +53,6 @@ declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
48
53
|
width: z.ZodNumber;
|
|
49
54
|
height: z.ZodNumber;
|
|
50
55
|
rotation: z.ZodNumber;
|
|
51
|
-
text: z.ZodArray<z.ZodString>;
|
|
52
56
|
}, z.core.$strip>;
|
|
53
57
|
id: z.ZodString;
|
|
54
58
|
from_name: z.ZodString;
|
|
@@ -62,6 +66,7 @@ declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
62
66
|
value: z.ZodObject<{
|
|
63
67
|
points: z.ZodArray<z.ZodArray<z.ZodNumber>>;
|
|
64
68
|
closed: z.ZodBoolean;
|
|
69
|
+
text: z.ZodArray<z.ZodString>;
|
|
65
70
|
}, z.core.$strip>;
|
|
66
71
|
id: z.ZodString;
|
|
67
72
|
from_name: z.ZodString;
|
|
@@ -89,7 +94,6 @@ declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
89
94
|
value: z.ZodObject<{
|
|
90
95
|
points: z.ZodArray<z.ZodArray<z.ZodNumber>>;
|
|
91
96
|
closed: z.ZodBoolean;
|
|
92
|
-
text: z.ZodArray<z.ZodString>;
|
|
93
97
|
}, z.core.$strip>;
|
|
94
98
|
id: z.ZodString;
|
|
95
99
|
from_name: z.ZodString;
|
|
@@ -132,6 +136,7 @@ declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
132
136
|
width: z.ZodNumber;
|
|
133
137
|
height: z.ZodNumber;
|
|
134
138
|
rotation: z.ZodNumber;
|
|
139
|
+
text: z.ZodArray<z.ZodString>;
|
|
135
140
|
}, z.core.$strip>;
|
|
136
141
|
id: z.ZodString;
|
|
137
142
|
from_name: z.ZodString;
|
|
@@ -165,7 +170,6 @@ declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
165
170
|
width: z.ZodNumber;
|
|
166
171
|
height: z.ZodNumber;
|
|
167
172
|
rotation: z.ZodNumber;
|
|
168
|
-
text: z.ZodArray<z.ZodString>;
|
|
169
173
|
}, z.core.$strip>;
|
|
170
174
|
id: z.ZodString;
|
|
171
175
|
from_name: z.ZodString;
|
|
@@ -179,6 +183,7 @@ declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
179
183
|
value: z.ZodObject<{
|
|
180
184
|
points: z.ZodArray<z.ZodArray<z.ZodNumber>>;
|
|
181
185
|
closed: z.ZodBoolean;
|
|
186
|
+
text: z.ZodArray<z.ZodString>;
|
|
182
187
|
}, z.core.$strip>;
|
|
183
188
|
id: z.ZodString;
|
|
184
189
|
from_name: z.ZodString;
|
|
@@ -206,7 +211,6 @@ declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
206
211
|
value: z.ZodObject<{
|
|
207
212
|
points: z.ZodArray<z.ZodArray<z.ZodNumber>>;
|
|
208
213
|
closed: z.ZodBoolean;
|
|
209
|
-
text: z.ZodArray<z.ZodString>;
|
|
210
214
|
}, z.core.$strip>;
|
|
211
215
|
id: z.ZodString;
|
|
212
216
|
from_name: z.ZodString;
|
|
@@ -244,7 +248,7 @@ declare const FullOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
244
248
|
declare const MinOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
245
249
|
ocr: z.ZodString;
|
|
246
250
|
id: z.ZodNumber;
|
|
247
|
-
bbox: z.ZodArray<z.ZodObject<{
|
|
251
|
+
bbox: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
248
252
|
x: z.ZodNumber;
|
|
249
253
|
y: z.ZodNumber;
|
|
250
254
|
width: z.ZodNumber;
|
|
@@ -252,8 +256,8 @@ declare const MinOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
252
256
|
rotation: z.ZodNumber;
|
|
253
257
|
original_width: z.ZodNumber;
|
|
254
258
|
original_height: z.ZodNumber;
|
|
255
|
-
}, z.core.$strip
|
|
256
|
-
label: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
259
|
+
}, z.core.$strip>>>>;
|
|
260
|
+
label: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
257
261
|
x: z.ZodNumber;
|
|
258
262
|
y: z.ZodNumber;
|
|
259
263
|
width: z.ZodNumber;
|
|
@@ -268,14 +272,14 @@ declare const MinOCRLabelStudioSchema: z.ZodArray<z.ZodObject<{
|
|
|
268
272
|
labels: z.ZodArray<z.ZodString>;
|
|
269
273
|
original_width: z.ZodNumber;
|
|
270
274
|
original_height: z.ZodNumber;
|
|
271
|
-
}, z.core.$strip>]
|
|
272
|
-
transcription: z.ZodArray<z.ZodString
|
|
273
|
-
poly: z.ZodArray<z.ZodObject<{
|
|
275
|
+
}, z.core.$strip>]>>>>;
|
|
276
|
+
transcription: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>, z.ZodTransform<string[], string | string[] | undefined>>;
|
|
277
|
+
poly: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
274
278
|
points: z.ZodArray<z.ZodArray<z.ZodNumber>>;
|
|
275
279
|
closed: z.ZodBoolean;
|
|
276
280
|
original_width: z.ZodNumber;
|
|
277
281
|
original_height: z.ZodNumber;
|
|
278
|
-
}, z.core.$strip
|
|
282
|
+
}, z.core.$strip>>>>;
|
|
279
283
|
annotator: z.ZodNumber;
|
|
280
284
|
annotation_id: z.ZodNumber;
|
|
281
285
|
created_at: z.ZodString;
|
|
@@ -291,8 +295,15 @@ type FullOCRLabelStudio = z.infer<typeof FullOCRLabelStudioSchema>;
|
|
|
291
295
|
type MinOCRLabelStudio = z.infer<typeof MinOCRLabelStudioSchema>;
|
|
292
296
|
type PPOCRLabel = z.infer<typeof PPOCRLabelSchema>;
|
|
293
297
|
|
|
294
|
-
|
|
295
|
-
|
|
298
|
+
interface ConversionOptions {
|
|
299
|
+
baseImageDir?: string;
|
|
300
|
+
normalizeShape?: ShapeNormalizeOption;
|
|
301
|
+
widthIncrement?: number;
|
|
302
|
+
heightIncrement?: number;
|
|
303
|
+
precision?: number;
|
|
304
|
+
}
|
|
305
|
+
declare const labelStudioToPPOCR: (data: FullOCRLabelStudio, options?: ConversionOptions) => Promise<Map<string, PPOCRLabel>>;
|
|
306
|
+
declare const minLabelStudioToPPOCR: (data: MinOCRLabelStudio, options?: ConversionOptions) => Promise<Map<string, PPOCRLabel>>;
|
|
296
307
|
|
|
297
308
|
type ToLabelStudioOptions = {
|
|
298
309
|
imagePath: string;
|
|
@@ -301,9 +312,13 @@ type ToLabelStudioOptions = {
|
|
|
301
312
|
toFullJson?: boolean;
|
|
302
313
|
taskId?: number;
|
|
303
314
|
labelName?: string;
|
|
315
|
+
normalizeShape?: ShapeNormalizeOption;
|
|
316
|
+
widthIncrement?: number;
|
|
317
|
+
heightIncrement?: number;
|
|
318
|
+
precision?: number;
|
|
304
319
|
};
|
|
305
320
|
declare const ppocrToLabelStudio: (data: PPOCRLabel, options: ToLabelStudioOptions) => Promise<FullOCRLabelStudio | MinOCRLabelStudio>;
|
|
306
|
-
declare const ppocrToFullLabelStudio: (data: PPOCRLabel, imagePath: string, baseServerUrl: string, inputDir?: string, taskId?: number, labelName?: string) => FullOCRLabelStudio;
|
|
307
|
-
declare const ppocrToMinLabelStudio: (data: PPOCRLabel, imagePath: string, baseServerUrl: string, inputDir?: string, labelName?: string) => MinOCRLabelStudio;
|
|
321
|
+
declare const ppocrToFullLabelStudio: (data: PPOCRLabel, imagePath: string, baseServerUrl: string, inputDir?: string, taskId?: number, labelName?: string, normalizeShape?: ShapeNormalizeOption, widthIncrement?: number, heightIncrement?: number, precision?: number) => FullOCRLabelStudio;
|
|
322
|
+
declare const ppocrToMinLabelStudio: (data: PPOCRLabel, imagePath: string, baseServerUrl: string, inputDir?: string, labelName?: string, normalizeShape?: ShapeNormalizeOption, widthIncrement?: number, heightIncrement?: number, precision?: number) => MinOCRLabelStudio;
|
|
308
323
|
|
|
309
|
-
export { type ToLabelStudioOptions, labelStudioToPPOCR, minLabelStudioToPPOCR, ppocrToFullLabelStudio, ppocrToLabelStudio, ppocrToMinLabelStudio };
|
|
324
|
+
export { type ConversionOptions, type ToLabelStudioOptions, labelStudioToPPOCR, minLabelStudioToPPOCR, ppocrToFullLabelStudio, ppocrToLabelStudio, ppocrToMinLabelStudio };
|