Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/npm-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
version:
description: Lockstep version for all release packages
required: true
default: 0.3.3
default: 0.3.4
type: string
publish_to_registry:
description: Publish the fully gated candidate to npm after preflight
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

This file records user-visible changes to `light-ocr`. Published artifact details and immutable hashes remain in [`docs/releases/`](docs/releases/).

## [0.3.4] - 2026-07-22

### Fixed

- Fixed the native Node-API option contract so the documented `region` option reaches the existing ROI implementation for both `recognize` and `detect`, including valid zero-based `x` and `y` coordinates.
- Extended the existing package smoke to execute a real `light-ocr recognize --region` command, covering CLI argument parsing, encoded-image decoding, native option admission, model inference, and text output in one focused check.

## [0.3.3] - 2026-07-22

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ if(APPLE AND (NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET OR
"Minimum macOS deployment target" FORCE)
endif()

project(light_ocr VERSION 0.3.3 LANGUAGES CXX)
project(light_ocr VERSION 0.3.4 LANGUAGES CXX)

if(APPLE)
enable_language(OBJCXX)
Expand Down
2 changes: 1 addition & 1 deletion bindings/node/bin/light-ocr.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const { createEngine, OcrError } = require('../js/index.cjs');
const { parseExifOrientation } = require('../js/exif.cjs');

const PKG_VERSION = require('../package.json').version;
const CORE_VERSION = '0.3.3';
const CORE_VERSION = '0.3.4';

const SUBCOMMANDS = new Set(['recognize', 'detect', 'info']);
const EXIT = {
Expand Down
2 changes: 1 addition & 1 deletion bindings/node/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@arcships/light-ocr",
"version": "0.3.3",
"version": "0.3.4",
"private": true,
"description": "Node-API adapter for the light-ocr C++ core",
"license": "Apache-2.0",
Expand Down
6 changes: 3 additions & 3 deletions bindings/node/src/addon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ RecognizeOptions parse_recognize_options(napi_env env, napi_value value,
require_object(env, value, "recognize options");
const std::unordered_set<std::string> allowed{
"recognitionScoreThreshold", "recognitionBatchSize", "includeDiagnostics",
"useTextlineOrientation", "detectionMaxSide", "applyExif"};
"useTextlineOrientation", "detectionMaxSide", "applyExif", "region"};
reject_unknown_properties(env, value, allowed, "recognize options");
if (const auto option = optional_named(env, value, "recognitionScoreThreshold")) {
const double score = get_number(env, *option, "recognitionScoreThreshold");
Expand Down Expand Up @@ -804,8 +804,8 @@ RecognizeOptions parse_recognize_options(napi_env env, napi_value value,
const std::unordered_set<std::string> region_allowed{"x", "y", "width", "height"};
reject_unknown_properties(env, *option, region_allowed, "region");
Rect rect;
rect.x = get_u32(env, *optional_named(env, *option, "x"), "region.x", 1);
rect.y = get_u32(env, *optional_named(env, *option, "y"), "region.y", 1);
rect.x = get_u32(env, *optional_named(env, *option, "x"), "region.x", 0);
rect.y = get_u32(env, *optional_named(env, *option, "y"), "region.y", 0);
rect.width = get_u32(env, *optional_named(env, *option, "width"), "region.width", 1);
rect.height = get_u32(env, *optional_named(env, *option, "height"), "region.height", 1);
if (rect.width == 0 || rect.height == 0) {
Expand Down
23 changes: 23 additions & 0 deletions tools/npm/smoke.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ const { spawnSync } = require('node:child_process');
const fs = require('node:fs');
const path = require('node:path');

const encodedBlankPng = Buffer.from(
'iVBORw0KGgoAAAANSUhEUgAAAAIAAAADCAIAAAA2iEnWAAAAFUlEQVR4nGP8//8/AwMDEwMDA4ICADkbAwP+wj6MAAAAAElFTkSuQmCC',
'base64',
);

async function main() {
const fixtureDirectory = process.env.LIGHT_OCR_SMOKE_FIXTURE;
assert.ok(fixtureDirectory, 'LIGHT_OCR_SMOKE_FIXTURE is required');
Expand Down Expand Up @@ -35,6 +40,24 @@ async function main() {
assert.equal(versionTriple.npm, packageMetadata.version);
assert.equal(versionTriple.core, packageMetadata.version);
assert.equal(versionTriple.model, 'ppocrv6-small-native-20260719.1');
const cliRecognition = spawnSync(
cli,
[
'recognize', '--stdin', '--type', 'image/png', '--format', 'text',
'--region', '0,0,2,3',
],
{
input: encodedBlankPng,
encoding: 'utf8',
shell: process.platform === 'win32',
},
);
assert.equal(
cliRecognition.status,
0,
cliRecognition.stderr || cliRecognition.error?.message,
);
assert.equal(cliRecognition.stdout, '');
const appleSupported = process.platform === 'darwin' && process.arch === 'arm64';
assert.strictEqual(esm.createEngine, cjs.createEngine);
assert.strictEqual(esm.OcrError, cjs.OcrError);
Expand Down
Loading