Skip to content

fix(deps): update module github.com/go-gfx/gfx to v0.19.0 - #25

Open
tannevaled wants to merge 1 commit into
mainfrom
renovate/deps
Open

fix(deps): update module github.com/go-gfx/gfx to v0.19.0#25
tannevaled wants to merge 1 commit into
mainfrom
renovate/deps

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
github.com/go-gfx/gfx v0.1.0v0.19.0 age confidence

Release Notes

go-gfx/gfx (github.com/go-gfx/gfx)

v0.19.0

Compare Source

v0.18.0

Compare Source

v0.17.0: — a TIFF that is not eighteen times too big

Compare Source

tiff.Encode was passed nil options, which reads like "no options" and means "no compression". On a page-sized picture that is 7 755 458 bytes against 415 493 with Deflate — eighteen times.

It was found downstream. go-pdfkit/app added a format chooser for handing a drawn page over and measured what each costs over 40 real documents: GIF 105 kB, JPEG 129 kB, PNG 209 kB — against BMP 4.9 MB and TIFF 6.6 MB. The ratio between those two is exactly four bytes a pixel against three, the alpha channel TIFF carries: both were the raw raster.

Deflate is compression 8, which every reader written this century takes. LZW would be the other candidate and this library cannot write it — tiff.Encode refuses it.

BMP stays large, and now says so. BMP has no compression to ask for; the documentation says it rather than leaving somebody to find out on a document of two hundred pages, and a test asserts it, so a BMP encoder that one day learns to compress makes what is written here fail rather than merely become untrue.

The compressed file is read back and compared pixel for pixel. A smaller file nothing opens is worse than a large one.

100% statement coverage, go vet and -race clean, nine cross-compile targets, CGO-free.

v0.16.0: — the registry writes too

Compare Source

codec.Encode writes PNG, JPEG, GIF, TIFF and BMP, each through the same reference library that reads it. Nothing here encodes anything itself.

The registry could read eleven formats and write none, so every consumer that had a picture and needed a file wrote its own encoder call — and a PDF toolkit that can draw a page could not offer "PDF to PNG".

Reading and writing are not symmetric, and the gap is not an oversight: a reference decoder exists in pure Go for every format Sniff names, a reference encoder for five of them. WEBP, ICO, ICNS, PNM, QOI, JP2 and JBIG2 return ErrCannotEncode rather than something in another format under the asked-for name. CanEncode says which way a format goes without having to fail to find out.

Alpha survives into PNG and TIFF. The other three do not, and what they are given is the image composited onto white — chosen here rather than left to the encoder, because an encoder that simply drops the channel puts the colour that was under the transparency into the file, and for a page drawn on transparent ground that is black.

100% statement coverage, go vet and -race clean, nine cross-compile targets, CGO-free.

v0.15.0: — a JBIG2 decoder that reads real scans

Compare Source

The JBIG2 decoder now comes from a fork carrying one fix, offered upstream as dkrisman/gobig2#2.

Upstream's per-symbol pixel cap defaults to 4 megapixels, on the reasoning that a real glyph is "tens of pixels per side". Real scanned documents disagree: some encoders emit a page-sized region as one symbol. Of 403 JBIG2 streams taken from the /Mask and /SMask entries of public Internet Archive scans, 7 are refused at that default — they need between 7 and 8 MP for a single symbol, and poppler reads all of them at its own defaults.

A consumer could not simply raise it: the limits are process-global variables, so a library that raised them would raise them for everything else in the binary.

The fix defaults the per-symbol cap to the aggregate cap, which is charged for every symbol three statements later and so already bounds the work — a per-symbol cap below the aggregate forbids a shape, not an amount of work.

With it the same 403 streams decode 403 of 403, every one bit-exact with poppler's own decoder, compared by extracting the image rather than rendering the page.

The fork also ends this module's dependency on an untagged one. It is meant to end: the day upstream tags a release carrying the fix, this goes back.

100% statement coverage, go vet and -race clean, nine cross-compile targets, CGO-free.

v0.14.0: — the JBIG2 a container embeds

Compare Source

codec.DecodeEmbeddedJBIG2 reads the headerless form of JBIG2 — segments and nothing else, with the shared ones handed in separately — which is what a PDF stores in a /JBIG2Decode stream.

v0.13.0 added JBIG2 as a file. The embedded form carries no signature and its globals cannot be guessed from the stream, so it cannot be sniffed and sits outside Decode's contract on purpose.

It is here so that one package names the JBIG2 decoder. That matters more than usual for this format: the reference decoder's resource limits are process-global rather than per-decode, so a library cannot raise them without changing them for everything else in the binary, and it publishes no tagged version.

Globals that make no sense do not stop a stream that does not read them — which is nearly all of them. Of 403 JBIG2 streams in a corpus of scanned documents, none named a globals stream.

100% statement coverage, go vet and -race clean, nine cross-compile targets, CGO-free.

v0.13.0: — JBIG2, the ink layer of a scanned page

Compare Source

codec reads JBIG2, the format a scanned page's ink is stored in. A modern scan is two images — a low-resolution colour background as JPEG 2000, and a high-resolution bitonal ink layer over it as JBIG2. v0.12.0 could read the background; this reads the ink.

No decoder is reimplemented, as for every other format in the package. Choosing the reference was the work: four pure-Go candidates exist and all four advertise full segment coverage. 403 JBIG2 masks were extracted from real scanned documents and every pixel compared against poppler's own decoder.

decoder decoded identical to poppler
dkrisman/gobig2 396/403 396 — 100%
jdeng/gojbig2 399/403 37 — 9%
dobbo-ca/byblos 157/403 157 — 100% (generic region only)
xiaoqidun/jbig2 0/403

The candidate that decodes the most is wrong nearly everywhere. Counting successes would have picked it; comparing pixels is what did not.

The headerless form a PDF embeds carries no signature and is deliberately not sniffed — a PDF consumer learns the format from the image dictionary. TestTheEmbeddedFormCarriesNoSignature holds that line.

100% statement coverage, go vet and -race clean, nine cross-compile targets including big-endian s390x, CGO_ENABLED=0.

v0.12.0: — JPEG 2000, which is what a scanned page is stored in

Compare Source

JPEG 2000 — which is what a scanned page is stored in

This package reimplements no decoder. It sniffs a container and hands it to a pure-Go reference. JPEG 2000 was the one shape it did not know, and that mattered more than anyone had measured.

Extending the corpus to where a scanned page actually lives says so plainly. Per population, the share of documents carrying a JPEG 2000 image, and the pages that have nothing else on them at all:

population documents pages blank without it
biodiversity scans 250 of 250 (100.0%) 310
medical heritage 248 of 250 (99.2%) 278
scanned books 144 of 222 (64.9%) 67
court filings 2 of 250 (0.8%) 0
government forms 4 of 450 (0.9%) 0

The last two rows are why this was nearly not done. Measured over forms alone, JPEG 2000 looks like eleven files in sixteen hundred and not worth a decoder. That figure was about the corpus, not about the world.

Not written here, and not written at all

github.com/ajroetker/go-jpeg2000 is 20 050 lines of pure Go — EBCOT, the wavelet transforms, the MQ coder, tag trees, packets, both the JP2 container and the bare codestream, decoder and encoder, with its own conformance suite and no cgo. Writing a second one would be the reference-library rule broken in its plainest case.

Checked rather than assumed:

  • it builds for all nine targets this fleet ships, js/wasm and s390x included, despite carrying a SIMD dependency;
  • it decodes 1 610 of 1 610 real JPEG 2000 images taken out of eighty scanned books, with no refusals.

Two shapes, one picture

A JP2 file opens with the twelve-byte signature box. A PDF's /JPXDecode stream is usually the bare codestream, which opens with SOC immediately followed by SIZ. Sniff knows both, because in the wild almost every scanned page is one of them.

A test that was wrong about the format

It asserted that half a codestream is refused. It is not, and should not be: JPEG 2000 is progressive by construction, so a codestream cut short is a coarser picture of the same size — the opposite of a Flate stream cut short. A decoder that refused it would throw away a page every other reader shows. The test now says that, and a separate one says that something which merely opens like a codestream and continues into nonsense is still refused.

100% statement coverage, go vet and -race clean, nine cross-compile targets.

v0.11.0

Compare Source

v0.10.0: — a stroke is one shape

Compare Source

A stroke was rasterised a piece at a time and the pieces combined by keeping the greater coverage of each pixel. That is not a union: where two pieces meet along a shared edge each covers part of the pixel that edge cuts, and the greater of two halves is a half. A curve cut into thousands of short segments — how every plotting program writes one — came out at about half the colour it was asked for, combed through with a lighter notch at every vertex.

Every piece now goes into one edge list, wound the same way round, filled once under the nonzero rule. Round ends and corners are stepped polygons within a hundredth of a pixel of the circle; a round join draws only the outside of the turn, a round cap only the half past the end.

Filling now sweeps an index of the edges instead of asking every edge about every scanline:

before after
fill, 2000-sided polygon 9.29 ms 3.30 ms
stroke, 3000-segment curve, miter 2.82 ms 3.30 ms
stroke, 3000-segment curve, round 2.23 ms 3.27 ms

The stroke parity test compared against a reimplementation of the code being replaced, so it asserted the defect; it now compares against a definition — every point within half a width of the line — over 604 shape/width/clamp combinations.

Full details in #​18.

v0.9.0

Compare Source

v0.8.0

Compare Source

v0.7.0

Compare Source

v0.6.0

Compare Source

v0.5.1

Compare Source

color: inlinable, allocation-light HSV/HSL/HWB conversions (#​9). Bit-identical fast paths (minMax3/absf, dropped no-op hue wrap, arithmetic Mod); inverse ~16% faster, zero-alloc unchanged. No API change.

v0.5.0

Compare Source

v0.4.0

Compare Source

v0.3.0

Compare Source

v0.2.1

Compare Source

v0.2.0

Compare Source


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Enabled.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate CLI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant