The reference SDK ships only as a Windows-targeted x64 .NET Framework 4.5
DLL (NeoLABNcodeSDK.dll). Its IL is platform-neutral and runs under
Mono 6.8+ on Linux / macOS, but one path-handling bug inside
GetImage() and GetPostscript() makes the DLL unusable on non-Windows
hosts out of the box. This SDK works around that bug in
tools/ncode-cli so the same DLL can power
production runs on Linux.
On Linux / macOS, GetImage(NcodePage, dpi, filename, isBold) fails with:
GetImage failed (380): 380 : Error occurred while making image.
even when:
Init()accepts the appSecretKey,GetTickets()returns the expected ticket list (REST → 200 OK),GenerateNcode()returns aNcodePagewhosedatafield holds ~118 KB of dot bitmap, andlibgdiplusitself passes a smoke test (Format8bppIndexedBitmap+LockBits+Saveround-trips cleanly).
MONO_IOMAP=all does not help — Mono's IOMAP only translates
DOS-style drive letters, not mid-string backslashes emitted by managed
code.
The IL of CNcodeSDK.GetImage ends with:
IL_0305: ldfld string NeoLABNcodeSDK.CNcodeSDK::workingFolder
IL_030a: ldstr "\\" ← HARDCODED BACKSLASH
IL_030f: ldarg.s filename
IL_0311: call string System.String::Concat(string, string, string)
IL_0316: callvirt instance void System.Drawing.Image::Save(string)
IL_031b: leave.s IL_0332
IL_031d: catch [mscorlib]System.Exception
IL_0324: stfld string NeoLABNcodeSDK::lastErrorMsg
IL_0329: ldc.i4 0x17c ← returns 380
The path separator is a literal "\\", not Path.Combine or
Path.DirectorySeparatorChar. On Linux, that backslash is just another
character in the file name, so Image.Save either:
- creates a file at
workingFolder\filename(literal backslash in the name), or - throws if the caller's
filenamecontained a forward slash, since the resulting path implies "create intermediate directories" — whichSystem.Drawing.Image.Savedoes not.
Either way the catch-all swallows the diagnostic and returns 380.
GetPostscript() has the same bug.
The ncode-cli wrapper in this repo:
-
Passes only
Path.GetFileName(--out-png)tosdk.GetImage, so the concatenation always stays insideworkingFolderregardless of platform. -
After
GetImagereturns 0, it locates the produced file at one of:Path.Combine(workingFolder, basename)— Windows / Mono happy pathworkingFolder + "\\" + basename— Linux literal-backslash path
-
File.Moves the located file to the caller-supplied--out-png.
| Platform | Before | After |
|---|---|---|
| Windows | works | works |
| Linux (Mono) | error 380, no file | returns 0, file at --out-png |
| macOS (Mono) | expected same as Linux | expected same as Linux |
The same fix is applied around GetPostscript() for the PostScript output
path.
- Mono 6.8+
libgdiplus 6.1+(System.Drawing.Bitmap inside the SDK depends on it)- Outbound HTTPS to
api.neolab.net - A NeoLAB-issued
appSecretKey(the SDK'sInitvalidates against the REST endpoint)
Decompiling, patching, and re-signing a third-party closed-source binary is a redistribution headache; a 30-line C# shim around the public API is a one-line fix that survives every future SDK release without requiring re-patching.
If NeoLAB ever publishes a non-Windows-targeted SDK build, the workaround
becomes a no-op — GetImage returns 0, --out-png is found at the first
candidate location, the wrapper still works, and we can retire the
literal-backslash branch.