Repository navigation
A BMP, a TIFF or a WebP cut short loses the share of its picture asked for #244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
8dd2c01
A BMP, a TIFF or a WebP cut short loses the share of its picture aske…
donislawdev 6ef384e
A TIFF of an odd size starts its directory on a word boundary
donislawdev d289fc4
The text of a cut says a small file can lose less, and the checkers r…
donislawdev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package bmp | ||
|
|
||
| import "github.com/donislawdev/TestingFilesGenerator/internal/format" | ||
|
|
||
| // splitForACut splits the padding of a BMP around its pixels for a cut after | ||
| // its first cutAt bytes (format.Request.CutAt), so that the cut keeps the | ||
| // share of the pixels it keeps of the whole file: in front of them, in the gap | ||
| // bfOffBits points past, as much as the share wants, and the rest behind them, | ||
| // where no field points. It is raw bytes on either side, so every length | ||
| // lands. Ten decoders give the pixels of a BMP nothing cuts from the gap split | ||
| // and from all of it behind, Go's x/image/bmp only with no gap in front - it | ||
| // refuses every BMP with one (docs/TRUNCATE-2026-11-11.md section 15.3). | ||
| // | ||
| // A BMP nothing cuts keeps all of its padding in front, byte for byte what it | ||
| // was (D11). | ||
| func splitForACut(m *memo, total, cutAt int64) { | ||
| pad := m.gap | ||
| m.gap = format.SplitFront(pad, headers, pixelBytes(m.width, m.height), cutAt, total, 1) | ||
| m.back = pad - m.gap | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| package tiff | ||
|
|
||
| import ( | ||
| "context" | ||
| "io" | ||
|
|
||
| "github.com/donislawdev/TestingFilesGenerator/internal/format" | ||
| ) | ||
|
|
||
| // layOut says where a TIFF's directory and padding go. A TIFF a damage will cut | ||
| // is laid out for the cut (splitForACut). One of an odd size puts its directory | ||
| // right behind the header, with all of its padding still in front of the | ||
| // pixels: TIFF 6.0 starts a directory on a word boundary, and last, where the | ||
| // 172 B of the directory and its values end the file, it would start on an odd | ||
| // byte (O342). Nine decoders give the same pixels from that layout | ||
| // (docs/TRUNCATE-2026-11-11.md section 15.3). The rest keep the directory last. | ||
| func layOut(m *memo, total, cutAt int64) { | ||
| switch { | ||
| case cutAt > 0: | ||
| splitForACut(m, total, cutAt) | ||
| case total%2 == 1: | ||
| m.directoryFirst = true | ||
| } | ||
| } | ||
|
|
||
| // splitForACut lays a TIFF out for a cut after its first cutAt bytes | ||
| // (format.Request.CutAt), so that the cut keeps the share of the pixels it | ||
| // keeps of the whole file. | ||
| // | ||
| // The directory and the values it points at move up to right behind the | ||
| // header. TIFF 6.0 lets the directory stand anywhere after the header on a | ||
| // word boundary, and byte 8 is one. Left last, it is the end of the file: 172 | ||
| // B that a cut of 1% of a file of a few kilobytes falls in. The padding then | ||
| // goes around the pixels - in front of them as much as the share wants, the | ||
| // rest behind them, where no field points. It is raw bytes on either side, so | ||
| // every length lands. Nine decoders give the pixels of a TIFF nothing cuts | ||
| // from the directory first with the padding in front, split and behind, and | ||
| // exiftool reads it (docs/TRUNCATE-2026-11-11.md section 15.3). | ||
| // | ||
| // A TIFF nothing cuts keeps its directory last and its padding in front, byte | ||
| // for byte what it was (D11). | ||
| func splitForACut(m *memo, total, cutAt int64) { | ||
| pad := m.gap | ||
| m.directoryFirst = true | ||
| m.gap = format.SplitFront(pad, header+directory+heap, pixelBytes(m.width, m.height), cutAt, total, 1) | ||
| m.back = pad - m.gap | ||
| } | ||
|
|
||
| // writeDirectoryFirst writes a TIFF whose directory follows its header - one | ||
| // laid out for a cut, or one of an odd size: the header, the directory and its | ||
| // values, the padding in front, the pixels and the padding behind. | ||
| func writeDirectoryFirst(ctx context.Context, w io.Writer, m memo) error { | ||
| head := int64(header + directory + heap) | ||
| pixels := pixelBytes(m.width, m.height) | ||
| format.Mark(w, format.RoleStructure, 0, head) | ||
| format.Mark(w, format.RolePadding, head, m.gap) | ||
| format.Mark(w, format.RoleContent, head+m.gap, pixels) | ||
| format.Mark(w, format.RolePadding, head+m.gap+pixels, m.back) | ||
|
|
||
| if err := writeHeader(w, m); err != nil { | ||
| return err | ||
| } | ||
| if err := writeDirectory(w, m); err != nil { | ||
| return err | ||
| } | ||
| if err := writeGap(ctx, w, m.seed, m.gap); err != nil { | ||
| return err | ||
| } | ||
| if err := writePixels(ctx, w, m); err != nil { | ||
| return err | ||
| } | ||
| return writeGap(ctx, w, m.seed+1, m.back) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| package tiff | ||
|
|
||
| import ( | ||
| "context" | ||
| "image" | ||
| "image/color" | ||
| "io" | ||
|
|
||
| "github.com/donislawdev/TestingFilesGenerator/internal/format/imagelabel" | ||
| ) | ||
|
|
||
| // writePixels streams the picture a row at a time. | ||
| // | ||
| // Only the label band is ever built as an image, and it is at most 24 rows | ||
| // tall whatever the picture is. Everything else comes from the formula | ||
| // straight into one reused row buffer, so a 64 MiB picture costs a row rather | ||
| // than 64 MiB. | ||
| // | ||
| // A TIFF stores its rows top down, so the label band is written first - the | ||
| // one place this is simpler than BMP, which stores them the other way up. | ||
| func writePixels(ctx context.Context, w io.Writer, m memo) error { | ||
| row := make([]byte, m.width*samplesPerPixel) | ||
| off := int(m.seed % 256) | ||
|
|
||
| band := labelBand(m, off) | ||
| bandH := 0 | ||
| if band != nil { | ||
| bandH = band.Bounds().Dy() | ||
| } | ||
|
|
||
| for y := 0; y < m.height; y++ { | ||
| if y%64 == 0 { | ||
| select { | ||
| case <-ctx.Done(): | ||
| return ctx.Err() | ||
| default: | ||
| } | ||
| } | ||
| if y < bandH { | ||
| copyBandRow(row, band, y, m.width) | ||
| } else { | ||
| fillRow(row, y, m.width, off) | ||
| } | ||
| if _, err := w.Write(row); err != nil { | ||
| return err | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // fillRow writes one row of the gradient in the order a TIFF wants it: red, | ||
| // green, blue. | ||
| func fillRow(row []byte, y, width, off int) { | ||
| for x := 0; x < width; x++ { | ||
| row[x*3] = uint8((x + off) % 256) | ||
| row[x*3+1] = uint8((y + off) % 256) | ||
| row[x*3+2] = uint8((x + y + off) % 256) | ||
| } | ||
| } | ||
|
|
||
| func copyBandRow(row []byte, band *image.RGBA, y, width int) { | ||
| for x := 0; x < width; x++ { | ||
| i := band.PixOffset(x, y) | ||
| row[x*3] = band.Pix[i] | ||
| row[x*3+1] = band.Pix[i+1] | ||
| row[x*3+2] = band.Pix[i+2] | ||
| } | ||
| } | ||
|
|
||
| // labelBand rasterises the top strip of the picture, label included, or | ||
| // returns nil when there is no label to draw. | ||
| func labelBand(m memo, off int) *image.RGBA { | ||
| if m.label == "" || !imagelabel.Fits(m.width, len(m.label)) { | ||
| return nil | ||
| } | ||
| h := maxBandHeight | ||
| if m.height < h { | ||
| h = m.height | ||
| } | ||
| img := image.NewRGBA(image.Rect(0, 0, m.width, h)) | ||
| for y := 0; y < h; y++ { | ||
| for x := 0; x < m.width; x++ { | ||
| img.SetRGBA(x, y, color.RGBA{ | ||
| R: uint8((x + off) % 256), | ||
| G: uint8((y + off) % 256), | ||
| B: uint8((x + y + off) % 256), | ||
| A: 255, | ||
| }) | ||
| } | ||
| } | ||
| imagelabel.Draw(img, m.label) | ||
| return img | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: donislawdev/TestingFilesGenerator
Length of output: 48698
Script executed:
Repository: donislawdev/TestingFilesGenerator
Length of output: 1477
Script executed:
Repository: donislawdev/TestingFilesGenerator
Length of output: 3465
The setting text does not mention the small-WebP cut deviation.
The text says the cut removes the same percentage of the content. A WebP that is too small for the extended layout keeps the simple format. Its cut can then keep up to 26 bytes more of the picture than the requested share, as noted in
internal/format/webp/cut.go:33-38. In a very small file this moves the removed share by more than one point. Theall or nonewording from the README does not apply to WebP, so the setting text should not add it. Add a short qualifier to the English and Polish sentences instead, stating that a small WebP can keep slightly more than the requested share. The inspected excerpt does not include the full string, so replace the sentence in place rather than inserting a diff.Source: Path instructions