Skip to content

v0.29.0

Latest

Choose a tag to compare

@xbmlz xbmlz released this 25 Aug 03:07
· 6 commits to main since this release
383f72d

Six platforms per codec instead of four, 32-bit support, and three real bugs that
were only visible once a 32-bit build existed.

The codecs cover more platforms

golibjpeg and goopenjpeg are now v1.3.0, adding prebuilt libraries for
darwin/amd64 and windows/arm64:

Platform JPEG / JPEG-LS / JPEG 2000 / HTJ2K
linux/amd64, linux/arm64
darwin/amd64 new
darwin/arm64
windows/amd64
windows/arm64 new

More importantly, both now build everywhere Go targets rather than only where
they ship a library, and return an error wrapping ErrUnsupportedPlatform from
every entry point instead of panicking. Importing godicom is therefore safe on
any platform: parsing, writing, the data dictionary, JSON, RLE and Deflated all
work, and only the four native-codec transfer syntaxes fail — with an error you
can test for.

if _, err := ds.PixelBytes(); errors.Is(err, golibjpeg.ErrUnsupportedPlatform) {
    // No JPEG library for this GOOS/GOARCH. The dataset itself is fine.
}

Three bugs

Checking that "importable anywhere" claim turned out to falsify it — godicom
itself did not compile for a 32-bit target. Fixing that surfaced two bugs with
nothing to do with cross-compilation.

The data dictionary answered US for nearly every tag on a 32-bit platform.
All 88 repeater masks were parsed with fmt.Sscanf into int fields with the
error discarded. A mask like 0xFF00FFFF does not fit in a 32-bit int, so all
88 came out zero — and (tag ^ value) & 0 == 0 is true for every tag.
Whichever repeater came first in map iteration order answered for every
non-private tag: LookupVR(PatientName) returned US rather than PN, group
lengths returned US rather than UL, IsRepeaterTag was true for everything,
and reading an ordinary file raised two dozen spurious VR-mismatch diagnostics.
64-bit platforms were unaffected.

ParseTag rejected every hex tag with a group of 0x8000 or above — on all
platforms.
It used strconv.ParseInt(v, 16, 32), and a signed 32-bit parse
rejects anything from 0x80000000 up:

ParseTag("FFFEE000")  // godicom: unknown tag keyword "FFFEE000"

Those are the item, item-delimiter and sequence-delimiter tags that godicom's own
sequence and encapsulation code is built from, and the ones a JSONKey
round-trip is most likely to hit. pydicom's int(arg, 16) has no width at all,
so ParseUint is the port. The parenthesised form (FFFE,E000) always worked.

encaps.Encapsulate did not compile on 32-bit. Its Basic Offset Table guard
read total > (1<<32)-1, exact in pydicom because Python integers are
arbitrary-precision, an int overflow at compile time in Go.

Lengths are uint32 now

The compile failures were one mistake repeated: a declared value length is
unsigned 32 bits, and elementHeader.Length was an int. 0xFFFFFFFF
undefined length — is -1 in an int on a 32-bit platform, so casting to make
it build would have shipped a binary that silently misread every
undefined-length sequence and every encapsulated Pixel Data element. A
merely-compiling build would have been worse than the compile error.

uint32 is carried through the header, deferred-read and sequence paths
instead. No exported signature changed, and it removed two existing
uint32(length) casts at call sites.

One platform's libraries per binary

Each binary embeds the libraries for its own platform and never all twelve. The
//go:embed directives sit behind per-platform build tags:

cmd/godicom, go build Size Embedded libraries
linux/amd64 11.0 MB 3.7 MB
linux/arm64 10.4 MB 3.4 MB
darwin/amd64 10.4 MB 2.7 MB
darwin/arm64 9.8 MB 2.3 MB
windows/amd64 10.5 MB 2.6 MB
windows/arm64 9.8 MB 2.4 MB
js/wasm 8.3 MB none
linux/386 6.4 MB none

All twelve libraries are 17.0 MB together, so embedding them unconditionally
would add about 13.3 MB to every binary — linux/amd64 would be 24.3 MB instead
of 11.0 MB. To check your own build:

go list -f '{{.EmbedFiles}}' github.com/godicom-dev/golibjpeg/native

There is no cgo and no toolchain to install; the libraries load through purego,
so a plain go build is all a cross-compile takes.

CI keeps it true

The new cross-build job vets windows/386, linux/386, linux/arm (including
GOARM=5), linux/riscv64, linux/ppc64le, js/wasm and wasip1/wasm, and
runs the full test suite on linux/386. The test run is the point: the
repeater-mask bug compiled cleanly and only failed when executed. linux/mips
and linux/mipsle are excluded because purego does not build for them yet.

Tests that genuinely need a native codec now skip rather than fail where no
library exists, so a real failure is visible among them.

Also

  • CompressPixelData's doc comment listed its supported targets without HTJ2K,
    which pixels.EncodeFrame has dispatched on for some time.
  • The README documents platform support and binary size, and its Go snippets are
    now Example functions that go test compiles and checks.

Full changelog: https://github.com/godicom-dev/godicom/blob/v0.29.0/CHANGELOG.md