Skip to content

Latest commit

 

History

History
114 lines (92 loc) · 4.73 KB

File metadata and controls

114 lines (92 loc) · 4.73 KB

GetImage Error 380 — Root Cause & Workaround

Symptom

On Linux / macOS (Mono 6.8, libgdiplus 6.1), ncode-cli generate fails with:

GetImage failed (380): 380 : Error occurred while making image.

even though:

  • GetTickets (REST) succeeds and returns tickets for the given appSecretKey
  • GenerateNcode (REST) succeeds and returns a NcodePage whose data field holds the expected ~118 KB hex-encoded dot stream
  • libgdiplus itself passes a smoke test (Format8bppIndexed Bitmap + LockBits + Save round-trips cleanly)

Root cause

The C# CNcodeSDK.GetImage(NcodePage, int dpi, string filename, bool isBold) public wrapper delegates to a private overload whose IL 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

Key facts:

  1. The separator is a literal backslash, not Path.Combine and not Path.DirectorySeparatorChar.
  2. On Linux the backslash is not a directory separator, so Image::Save("/tmp/ncode-cli-cache" + "\" + "out.png") tries to write a file whose name literally contains a backslash, under whatever the first component resolves to.
  3. Whether the write succeeds or not depends on what the caller passes as filename:
    • "/tmp/out.png" — concat yields /tmp/ncode-cli-cache\/tmp/out.png, which Linux parses as a request to place \/tmp/out.png under ncode-cli-cache. That inner slash means "create intermediate directories", which System.Drawing.Image::Save does not, so the call throws and the SDK swallows it into error 380.
    • "out.png" — concat yields /tmp/ncode-cli-cache\out.png, which Linux accepts as a single filename (the \ is just another char). Image::Save succeeds, but the file lands at literally /tmp/ncode-cli-cache\out.png (backslash in the name), not /tmp/ncode-cli-cache/out.png.

In short: the SDK was compiled against Windows path semantics. The catch (Exception) block erases every diagnostic and returns a single opaque code (380), which makes the failure look like a rendering problem when it is actually a path construction bug.

Verification

ncode-cli generate … --out-png /tmp/t.png on Linux, before the workaround, produced no file at /tmp/t.png but did produce

/tmp/ncode-cli-cache\test_out.png   (literal backslash in basename)
PNG image data, 4962 x 7014, 1-bit colormap, non-interlaced
103,272 bytes

when the CLI was invoked with --out-png test_out.png. The PNG content is byte-valid and contains the dot pattern for page 3.27.524.0 at 8.27 × 11.69 in @ 600 dpi, matching the reference sample at cpp/sampleApp(Ncode_cpp)/3_27_524_0_8.270000_11.700000.png in the upstream NeoSmartpen/Ncode-SDK2.0 repository in both dimensions and encoding class.

Workaround (applied to Program.cs)

  1. Pass only the basename (Path.GetFileName(--out-png)) to sdk.GetImage, so the concatenation stays within the workingFolder directory regardless of platform.
  2. After GetImage returns zero, locate the produced file:
    • Path.Combine(workingFolder, basename) — the Windows / Mono path
    • workingFolder + "\\" + basename — the Linux literal-backslash path
  3. File.Move the located file to the caller-supplied --out-png.

Net effect:

Platform Before After
Windows works works
Linux (Mono) returns 380, no file returns 0, file at --out-png
macOS (Mono) expected same as Linux expected same as Linux

MONO_IOMAP=all was evaluated and rejected: Mono's IOMAP only translates DOS-style drive letters, not mid-string backslashes emitted by managed code, so it does not help here.

Caveats / follow-up

  • Windows behaviour is unchanged. No regression risk.
  • The workaround relies on GetImage writing atomically once. If a future SDK version starts producing side files (e.g. a sidecar JSON) we will need to extend the "locate produced file" loop.
  • MONO_IOMAP=all is no longer needed and should not be set — it remains a no-op here and has unrelated side effects on other Mono apps in the process tree.
  • Reported to NeoLAB is unnecessary for the PoC since the workaround is one-line and runs on every platform; however if they ship a non-Windows SDK in the future they should use Path.DirectorySeparatorChar instead of the literal "\\".