Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
82df819
Add IRenderBackend
even1024 May 9, 2026
53a6188
Wire RenderContext
even1024 May 10, 2026
d9824c1
CMake skip graphics
even1024 May 10, 2026
558e927
Guard lunasvg
even1024 May 10, 2026
2121b0d
Remove graphics deps
even1024 May 10, 2026
8ea4346
Guard emf_utils
even1024 May 10, 2026
aff127c
Fix linker errors
even1024 May 10, 2026
f132177
JS render backend
even1024 May 10, 2026
3455af6
clang format fixes
even1024 May 10, 2026
61acc3b
Fix Win32 build errors
even1024 May 10, 2026
4fb4325
Skip visual regression render tests
even1024 May 11, 2026
cc1f014
Update Win rendering ref image
even1024 May 11, 2026
7e6c4c7
Update WASM render test ref PNGs for JS backend
even1024 May 11, 2026
2a99b89
Fix JS render backend: pre-transform paths through CTM
even1024 May 11, 2026
4694866
Add rendering regression tests: reactions, arrows, bonds
even1024 May 11, 2026
176d93e
Render SVG arcs and images
even1024 May 12, 2026
28c5828
Fix WASM text rendering baseline and line spacing to match Windows Cairo
even1024 May 12, 2026
8f4fa2b
Fix clang-format violation in js_render_backend.cpp
even1024 May 12, 2026
6bf8fa1
Bypass clang-format for js_rb_copyOutput EM_JS macro
even1024 May 12, 2026
4ef4ef8
Implement asynchronous SVG to PNG rendering via post.js
even1024 May 12, 2026
952a6a4
Restore sync sharp PNG for Node.js, keep renderAsync for browser
even1024 May 12, 2026
c819bb6
Move sharp to optionalDependencies
even1024 May 12, 2026
b0a5a52
Add Puppeteer browser test suite for renderAsync and fix IIFE
even1024 May 12, 2026
71c2693
Fix CI: Install Puppeteer dependencies in emscripten container
even1024 May 12, 2026
d689cef
Fix CI: use libasound2t64 instead of libasound2 for Ubuntu Noble (24.04)
even1024 May 12, 2026
312cd29
Fix relative paths to integration tests in wasm test.js so it works b…
even1024 May 12, 2026
65362f6
Fix integration test paths by dynamically searching upwards for api/t…
even1024 May 12, 2026
fba25f8
Fix CI: load missing untracked .ket test files from integration direc…
even1024 May 12, 2026
199684e
Fix CI: run tests with async/await properly, and relax looksSame tole…
even1024 May 13, 2026
58c2351
fonts management added
even1024 May 13, 2026
4a89933
Fix build: Add missing font_lang_detector.h
even1024 May 13, 2026
61b69c4
Fix signed/unsigned mismatch in font_lang_detector.h
even1024 May 13, 2026
77f2646
Fix: use Noto Sans only for WASM, keep Arial for native builds
even1024 May 13, 2026
72df072
Update CJK ref images from clean CI-matching build
even1024 May 13, 2026
313590a
CJK text measurement via node-canvas, fix font detection
even1024 May 14, 2026
276e7f5
clang format
even1024 May 14, 2026
023349a
Replace sharp/tmpfile with node-canvas for SVG-to-PNG rasterization
even1024 May 14, 2026
72026a4
Fix CI utils matrix
even1024 May 15, 2026
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
10 changes: 9 additions & 1 deletion .github/workflows/indigo-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,10 @@ jobs:
ver=$(git describe --abbrev=0 --tags --match "indigo-*")-$(git rev-list $(git describe --abbrev=0 --tags --match "indigo-*").. --count)
ver=$(echo $ver | sed 's/indigo-//g' | sed 's/-0//g')
npm version --allow-same-version ${ver}
- name: Install Puppeteer Dependencies
run: |
apt-get update
apt-get install -y libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2t64 libpango-1.0-0 libcairo2
- name: Build, Test, Pack
run: |
mkdir build
Expand Down Expand Up @@ -936,6 +940,10 @@ jobs:
ver=$(git describe --abbrev=0 --tags --match "indigo-*")-$(git rev-list $(git describe --abbrev=0 --tags --match "indigo-*").. --count)
ver=$(echo $ver | sed 's/indigo-//g' | sed 's/-0//g')
npm version --allow-same-version ${ver}
- name: Install Puppeteer Dependencies
run: |
apt-get update
apt-get install -y libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2t64 libpango-1.0-0 libcairo2 fonts-noto-cjk
- name: Build, Test, Pack
run: |
mkdir build
Expand All @@ -951,7 +959,7 @@ jobs:
build_indigo_utils_x86_64:
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.set_matrix.outputs.matrix) }}
matrix: ${{ fromJSON(needs.set_matrix.outputs.matrix || '{"os":["ubuntu-latest","windows-latest"]}') }}
runs-on: ${{ matrix.os }}
# needs: [build_bingo_postgres_linux_x86_64, build_bingo_postgres_windows_msvc_x86_64, build_bingo_postgres_macos_x86_64]
needs: [build_bingo_postgres_linux_x86_64, build_bingo_postgres_windows_msvc_x86_64, set_matrix ]
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ if (EMSCRIPTEN)
set(BUILD_BINGO_SQLSERVER OFF)
set(BUILD_BINGO_ORACLE OFF)
set(BUILD_BINGO_ELASTIC OFF)
set(USE_FONT_MANAGER ON)
set(USE_FONT_MANAGER OFF)
# Skip Array/Pool bounds-check throws in release WASM builds to allow inlining.
# emscripten's JS-based exception handling wraps every throw-containing function
# in invoke_* shims, preventing inlining and causing ~80x overhead in hot loops.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions api/wasm/indigo-ketcher/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@ set(EMCC_COMMON_FLAGS
-s INITIAL_MEMORY=32mb
-s ALLOW_MEMORY_GROWTH=1
-s DISABLE_EXCEPTION_CATCHING=0
-s DYNAMIC_EXECUTION=0
-s ENVIRONMENT=web,worker
-s MODULARIZE=1
-s FILESYSTEM=1
${EMCC_ASSERTIONS}
-s USE_SDL=0 -s USE_SDL_IMAGE=0 -s USE_SDL_TTF=0 -s USE_SDL_NET=0
--no-entry
--post-js ${CMAKE_CURRENT_SOURCE_DIR}/post.js
${EMCC_FLAGS}
)

Expand All @@ -52,15 +55,16 @@ set(EMCC_FLAGS_SEPARATE
set(EMCC_FLAGS
${EMCC_COMMON_FLAGS}
-s SINGLE_FILE=1
-s SINGLE_FILE_BINARY_ENCODE=0
)

set(TARGET_FILES
$<TARGET_OBJECTS:${PROJECT_NAME}-object>
$<TARGET_FILE:indigo-static> $<TARGET_FILE:indigo-inchi-static> $<TARGET_FILE:indigo-renderer-static> $<TARGET_FILE:render2d> $<TARGET_FILE:lunasvg> $<TARGET_FILE:plutovg> $<TARGET_FILE:cairo> $<TARGET_FILE:freetype> $<TARGET_FILE:png> $<TARGET_FILE:pixman> $<TARGET_FILE:indigo-core> $<TARGET_FILE:inchi> $<TARGET_FILE:tinyxml2> $<TARGET_FILE:z>
$<TARGET_FILE:indigo-static> $<TARGET_FILE:indigo-inchi-static> $<TARGET_FILE:indigo-renderer-static> $<TARGET_FILE:render2d> $<TARGET_FILE:indigo-core> $<TARGET_FILE:inchi> $<TARGET_FILE:tinyxml2> $<TARGET_FILE:z>
)

set(TARGET_FILES_NORENDER
$<TARGET_OBJECTS:${PROJECT_NAME}-object-norender> $<TARGET_FILE:indigo-static> $<TARGET_FILE:indigo-inchi-static> $<TARGET_FILE:indigo-core> $<TARGET_FILE:inchi> $<TARGET_FILE:tinyxml2> $<TARGET_FILE:png> $<TARGET_FILE:z>
$<TARGET_OBJECTS:${PROJECT_NAME}-object-norender> $<TARGET_FILE:indigo-static> $<TARGET_FILE:indigo-inchi-static> $<TARGET_FILE:indigo-core> $<TARGET_FILE:inchi> $<TARGET_FILE:tinyxml2> $<TARGET_FILE:z>
)

add_custom_target(${PROJECT_NAME}-separate
Expand Down Expand Up @@ -109,6 +113,7 @@ if (NOT RENDER_ENABLE_CJK)
WORKING_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/patch.cmake
COMMAND npm test
COMMAND npm run test_browser
COMMAND npm pack
COMMAND ${CMAKE_COMMAND} -E make_directory ${DIST_DIRECTORY}
COMMAND ${COPY_COMMAND} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}${SEP}${PROJECT_NAME}*.tgz ${NATIVE_DIST_DIRECTORY}${SEP}
Expand All @@ -125,6 +130,7 @@ else ()
WORKING_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/patch.cmake
COMMAND npm test
COMMAND npm run test_browser
COMMAND npm run test_cjk
COMMAND npm pack
COMMAND ${CMAKE_COMMAND} -E make_directory ${DIST_DIRECTORY}
Expand Down
14 changes: 13 additions & 1 deletion api/wasm/indigo-ketcher/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,21 @@
"homepage": "https://lifescience.opensource.epam.com/indigo/api/index.html",
"scripts": {
"test": "node test.js",
"test_browser": "node test_browser.js",
"test_cjk": "node test_cjk.js"
},
"devDependencies": {
"looks-same": "^8.2.4"
"looks-same": "^8.2.4",
"puppeteer": "^22.0.0"
},
"dependencies": {
"@fontsource/noto-sans": "^5.0.0",
"@fontsource/noto-sans-jp": "^5.0.0",
"@fontsource/noto-sans-kr": "^5.0.0",
"@fontsource/noto-sans-sc": "^5.0.0",
"@fontsource/noto-sans-tc": "^5.0.0"
},
"optionalDependencies": {
"canvas": "^3.1.0"
}
}
87 changes: 87 additions & 0 deletions api/wasm/indigo-ketcher/post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// post.js - appended to the end of the emscripten module
// Adds Module.renderAsync() for asynchronous SVG-to-PNG conversion

(function() {

// Convert SVG string to PNG base64 using browser Canvas API
function svgToPngBrowser(svgStr) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.onload = function() {
try {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
var dataUrl = canvas.toDataURL('image/png');
resolve(dataUrl.split(',')[1]);
} catch (e) {
reject(e);
}
};
img.onerror = function() {
reject(new Error('Failed to load SVG into Image for PNG conversion'));
};
img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgStr);
});
}

// Convert SVG string to PNG base64 using sharp (Node.js)
function svgToPngNode(svgStr) {
var sharp = require('sharp');
return sharp(Buffer.from(svgStr)).png().toBuffer().then(function(buf) {
return buf.toString('base64');
});
}

Module.renderAsync = async function(data, options) {
var requestedFormat = 'svg';

// Detect requested format and override to SVG for C++ engine
if (options && typeof options.get === 'function') {
try {
var fmt = options.get('render-output-format');
if (fmt) requestedFormat = fmt;
} catch(e) {}

if (requestedFormat === 'png') {
options.set('render-output-format', 'svg');
}
}

// Call synchronous C++ render — always returns base64-encoded SVG
var base64Out = Module.render(data, options);

// Restore original option so the caller's map isn't permanently mutated
if (requestedFormat === 'png' && options && typeof options.set === 'function') {
options.set('render-output-format', 'png');
}

if (requestedFormat !== 'png') {
return base64Out;
}

// Decode base64 SVG to string
var svgStr;
if (typeof Buffer !== 'undefined') {
svgStr = Buffer.from(base64Out, 'base64').toString('utf-8');
} else {
var binary = atob(base64Out);
var bytes = new Uint8Array(binary.length);
for (var i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
svgStr = new TextDecoder().decode(bytes);
}

// Convert SVG to PNG using the appropriate environment
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
return svgToPngBrowser(svgStr);
} else if (typeof require !== 'undefined') {
return svgToPngNode(svgStr);
} else {
throw new Error('No environment available for SVG to PNG conversion');
}
};
})();
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified api/wasm/indigo-ketcher/test-cjk/CJK_characters_ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 31 additions & 4 deletions api/wasm/indigo-ketcher/test-cjk/test_cjk.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,42 @@ function parseHrtimeToSeconds(hrtime) {
return (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
}

function run() {
async function run() {
let succeeded = 0;
let failed = 0;

// On Linux, configure FontConfig to use the @fontsource fonts so that `sharp` (librsvg)
// renders SVGs with the correct Noto Sans CJK fonts, avoiding looksSame failures in CI.
if (process.platform === 'linux') {
const { execSync } = require('child_process');
const os = require('os');
const path = require('path');
const fs = require('fs');
try {
console.log("Configuring FontConfig for Linux...");
const fontsDir = path.join(os.homedir(), '.fonts');
if (!fs.existsSync(fontsDir)) {
fs.mkdirSync(fontsDir, { recursive: true });
}
const sourceDir = path.join(__dirname, 'node_modules', '@fontsource');
if (fs.existsSync(sourceDir)) {
execSync(`find "${sourceDir}" -type f \\( -name "*.woff" -o -name "*.woff2" -o -name "*.ttf" \\) -exec cp {} "${fontsDir}" \\;`);
execSync('fc-cache -f -v');
console.log("FontConfig successfully updated with Noto Sans fonts.");
} else {
console.warn(`Fontsource directory not found at ${sourceDir}`);
}
} catch (e) {
console.error('Failed to configure FontConfig for Linux:', e.message);
}
}

console.log("Starting tests...\n")
var startTestsTime = process.hrtime();
tests.forEach(t => {
for (const t of tests) {
try {
var startTestTime = process.hrtime();
t.fn()
await t.fn()
const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTestTime));
console.log(`✅ ${t.group}.${t.name} [${elapsedSeconds}s]`);
succeeded++;
Expand All @@ -30,7 +57,7 @@ function run() {
console.log(e.stack)
failed++
}
})
}
const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTestsTime));
const total = succeeded + failed;
console.log(`\n${total} tests executed in ${elapsedSeconds} seconds. ${succeeded} succeeded, ${failed} failed.`)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions api/wasm/indigo-ketcher/test/bonds.mol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

Mrv0541 12021111492D

26 13 0 0 0 0 999 V2000
0.4125 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.4125 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3.4768 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
2.6518 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
6.4232 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
5.5982 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
9.4875 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
8.6625 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
0.4125 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.4125 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3.4768 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
2.6518 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
6.5411 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
5.7161 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
9.6054 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
8.7804 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
0.4125 -3.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.4125 -3.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3.2411 -3.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
2.4161 -3.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
6.0696 -3.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
5.2446 -3.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
8.8982 -3.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
8.0732 -3.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
0.4125 -4.9500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.4125 -4.9500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
3 4 2 0 0 0 0
5 6 3 0 0 0 0
7 8 4 0 0 0 0
9 10 1 1 0 0 0
11 12 1 6 0 0 0
13 14 1 4 0 0 0
15 16 2 3 0 0 0
17 18 2 3 0 0 0
19 20 5 0 0 0 0
21 22 6 0 0 0 0
23 24 7 0 0 0 0
25 26 8 0 0 0 0
M MRV CTU 1 9
M END
Binary file added api/wasm/indigo-ketcher/test/bonds_ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading