Skip to content

Releases: mdws-org/squint

0.9.0

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 30 Sep 04:31
91f79f0

Shrink and Shrink to a Quality Target now keep an iPhone photograph's HDR gain map when they replace the file. Until now they dropped it and said so: the photograph still opened and looked right on an ordinary display, but it looked flat on the display it was taken for. macOS will only decode a gain map beside a picture its own encoder wrote, so for a photograph that has one, the system encoder writes the file and the map is copied across from the original. That costs about 30% more bytes than Squint's usual encoder at the same score, and it is used only when there is a map to keep. Measured on an iPhone 12 portrait: 3,995 KB to 1,505 KB with Shrink, the HDR headroom 4.00 before and after, and no location, camera or date left in the file.

Shrink for Email and Shrink for Social still drop the map. They make a smaller copy to send, and the original beside them keeps its range.

The window's picker now offers all six treatments the Finder entries do: Shrink, Email, Social, Quality, AVIF and Strip. A photo can be dropped on the window and sent through any of them, which matters in folders where Finder shows no Services entries.

Changes: #88.

Apple silicon, macOS 14 or later. Signed and notarized.

SHA-256

e10de19f9563127c7ab0220bd6fbccdd096dde16b54d4ed12e8f72fd18e983e6  Squint-0.9.0.dmg
b549a99d7e773bf84d563bee9ed084995de1d73271bc8281a02b38339493c7a3  Squint-0.9.0.zip

0.8.3

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 27 Sep 21:50
401579e

The icon loses the dark rim around its tile, which read as a drawn border in the Dock. The slate tile now runs to the edge; the eye is unchanged.

The HEIF and AVIF walker no longer panics on a malformed item table. An iloc box of exactly eight bytes that declared version 2 made the walk read its four-byte item count past the end of the box. The engine caught the panic and failed that one file with an error, so the application did not crash and no file was changed, but a panic reachable from a file is a defect. The box is now refused before it is read. Found by the fuzzing added in 0.8.2.

Changes: #86.

Apple silicon, macOS 14 or later. Signed and notarized.

SHA-256

84c934bd336933da55af4d48bc8f7ea9e7363338951f900cae862f56221d28be  Squint-0.8.3.dmg
01130e0d7a85e4978c8b21b4b450947a8318e48c91cfefb086daa63f15f92664  Squint-0.8.3.zip

0.8.2

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 27 Sep 14:58
fa8ce48

The application has its own icon: an almost-closed eye, replacing the placeholder.

Remove Location Data could stall on a hostile TIFF. A forty-byte file declaring an entry count in the billions made the directory walk run once per declared entry, which took tens of seconds, although every read past the end of the file failed. The count is now bounded by what the file holds. A second defect, in the same walker, let the engine's internal count of bytes destroyed exceed the size of the file when a directory chain looped back on itself; the application only uses that count to decide whether anything was removed, so nothing visible changed. Neither defect read or wrote outside the file. Both were found by fuzzing.

The repository now has a SECURITY.md, with a private way to report a defect, and docs/VERIFY.md, which shows how to check with ExifTool what each mode removes and keeps. Every parser in the engine is fuzzed on each change and weekly.

Changes: #82, #83, #84.

Apple silicon, macOS 14 or later. Signed and notarized.

SHA-256

c96ce52785f09c8e3db887fb906bdc2ae4adb458b05daeb55e97d85f5d1800d5  Squint-0.8.2.dmg
d7daf9547f936d2cd32a3d43007894cfb7087aefc10f7bb8d1aa0e28437021e6  Squint-0.8.2.zip

0.8.1

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 26 Sep 23:28
a2c65f5

A row in the window now moves to its result the moment the work finishes.

Through 0.8.0 a row showed "working" after its file was done, and kept showing it until another file was added. The list drew each row from a plain reference to its job, so it redrew when a job was added or cleared but not when a job's own state changed. Each row now observes its job. Verified through the Finder path: one JPEG through Shrink, nothing else added, and the row read its result as soon as the file was written.

The drop prompt names PDF, which the in-place modes have accepted since 0.8.0.

Changes: #79.

Apple silicon, macOS 14 or later. Signed and notarized.

SHA-256

570cd6478fa86f4a49cf7d383cf6fd986f38e04b7b2493a3afbf2fc30cf8beb4  Squint-0.8.1.dmg
f2860003d5e588bb732ff1c4089e806571d13341b56af7899812b0f47658ebd1  Squint-0.8.1.zip

0.8.0

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 26 Sep 22:26
9bfd01b

Two things the command line could do reach the Finder menu.

A PDF goes through Shrink and Shrink to a Quality Target. The pictures inside it are re-encoded, any above 150 dpi on the page are downscaled to it, the document's own record of who wrote it and with what is dropped, and the file is rewritten in place. A fax-coded page, a JPEG 2000 image or a CMYK image inside it is left exactly as it was. Measured on a 665 KB PDF wrapping one photograph: 124 KB through Shrink, 165 KB through the quality target.

Squint: Convert to AVIF is a new entry. It takes a JPEG, PNG, HEIC, WebP or SVG and writes name.avif beside it, at the picture's own size, searched to the quality target the way the Quality entry is; the original is not touched. Measured: a 662 KB JPEG became a 262 KB AVIF, a 7.8 MB PNG a 506 KB one, a 340 KB HEIC a 108 KB one, all at their source dimensions. An AVIF handed to it is refused rather than written over.

The C interface gains squint_optimize_as, which names the output format; a code it does not know is refused rather than read as JPEG. The application now decides from the bytes of a result, not from what was asked for, whether it may replace the original: only a file of the same kind ever does.

Changes: #77.

Apple silicon, macOS 14 or later. Signed and notarized.

SHA-256

53431584b7b4460858d8a3789112bd05d64d20c2307b084280c8287247b818af  Squint-0.8.0.dmg
50c57f0e5e80ee70c1af82600910d7aec0afa358a811883f7e2f156cae085fb6  Squint-0.8.0.zip

0.7.1

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 26 Sep 16:49
0285f4a

The same Squint as 0.7.0, signed with a Developer ID and notarized by Apple. It opens on first launch like any other application: no Privacy & Security detour, no Open Anyway.

Nothing in the engine or the application changed. The version exists because a signed and notarized build is a different set of bytes from the one already published as 0.7.0, whose archives, hashes and update signature stay exactly as they were.

What the signature covers: the application, the Sparkle framework, and each of the five pieces nested inside it — the two XPC services, Autoupdate, Updater.app and the framework binary — every one signed individually with the hardened runtime and a timestamp, then verified as a whole before submission. The notary ticket is stapled to the bundle, so Gatekeeper's answer does not depend on reaching Apple.

This is also the first update Sparkle delivers across a change of signing identity. Every earlier build was ad-hoc signed; this one carries a team. Sparkle permits that transition when the update's EdDSA signature is intact, which it is — the same key has signed every archive since 0.4.0. The build stays marked pre-release until an installed 0.6.0 or 0.7.0 has taken this update through Squint → Check for Updates and come up running; then the flag comes off.

Changes: #73.

Requires macOS 14.

SHA-256

750126a5736992e1e95aefdc4e02fa9e4e6d6598d68cc52759401fd406cbe3f7  Squint-0.7.1.dmg
58d5a6c32c874af412f92e0e59851bca5345fd97352dfd7b04d256f0502acf52  Squint-0.7.1.zip

Squint 0.7.0

Squint 0.7.0 Pre-release
Pre-release

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 25 Sep 23:21
7cbb1fa

A PDF is a wrapper around pictures, and Squint now shrinks the pictures. From the command line in this release; the application follows (#70).

A PDF is rewritten as itself. A scanned document is a handful of JPEGs with a page around each: measured across real files, a 14 MB scan is thirty 300 dpi JPEGs, an 11 MB product sheet is one image stored with no compression at all, and the text and vectors together are a rounding error against either. Each picture is lifted out, put through the same encode a standalone JPEG gets, and put back where it was. The page tree, the content streams and the fonts are not touched, so the document stays selectable and searchable. The scan came out at 3.0 MB (21%), the sheet at 183 KB (1.6%), and an 88-page study guide from Word at 49%.

Resolution is capped at 150 dpi against the page. A picture is placed on a page by a transformation matrix, not by its own pixel count, so a smaller picture drawn by the same matrix covers the same area at a lower resolution, and no content stream is rewritten. The cap is where most of the saving is: re-encoding alone takes an eighth off a 300 dpi scan, the cap halves it. 120 dpi is visibly soft on scanned text and costs OCR, so 150 is the cap and it is not a control.

Strip works on a PDF. The info dictionary (author, application, dates) and every XMP packet in the document go, from the catalog and from any page, picture or font that carries one, and no pixel is touched.

What is left alone. Fax-coded pages, JPEG 2000 (#69), CMYK, indexed palettes, stencil masks, and the soft masks that carry another picture's transparency each keep the bytes they arrived with. A picture whose colours are defined by an ICC profile keeps the profile, as it does in every other format here. A document that would not come out smaller is refused, as everything else is.

A PDF does not become a picture. --format avif on one is refused with a sentence that says so, rather than quietly writing a PDF.

Changes: #65.

Not notarized. macOS will refuse to open it on first launch: System Settings, Privacy & Security, scroll down, Open Anyway. Control-click and Open no longer bypasses Gatekeeper on Sequoia and later. Requires macOS 14.

SHA-256

a9da9b553d55d56f713082c0b066ed1488cbe21f62d8fc345fe73bfd73421972  Squint-0.7.0.dmg
8bd7ab5f41ca3cf05d5025ad168b49063a0a52154f02010b9aaccf36a0b1534c  Squint-0.7.0.zip

Squint 0.6.0

Squint 0.6.0 Pre-release
Pre-release

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 14 Sep 20:47
dbe81b6

Two things Squint was getting quietly wrong, and the other half of format support.

A WebP shot in portrait no longer converts on its side. A WebP has no orientation field of its own; the only place a turn can be recorded is the TIFF block inside its EXIF chunk, and nothing here read one. A picture that carried its rotation there was converted the way its pixels were stored rather than the way it was meant to be seen. The tag is now read by the same walk that reads a JPEG's, and Strip still removes the chunk — by then the turn is in the pixels and what is left of the block names a camera.

An image sequence is refused rather than flattened to one frame. avis was already refused; msf1, hevc and hevx were not. Those are the HEIF and HEVC-coded sequences that sit beside the heic and heix single images, one letter apart, and macOS decodes any of them to a primary frame — so a sequence became a single still with nothing said about the frames that went missing. All four brands are now refused for re-encoding, and stripping one still works and leaves the frames alone.

AVIF and lossless WebP can be written, from the command line only: --format avif and --format webp. Both are conversions, written beside the original and never over it.

AVIF goes through the system encoder rather than a crate, because no pure-Rust AVIF encoder can embed a colour profile — ravif has no colour handling at all, and the container writer beneath it emits only an nclx box. An untagged AVIF is read as sRGB, and a Display P3 photograph comes out flat, which is the failure this project exists to avoid. Worth stating plainly: measured against JPEG at the same perceptual score on two 12 megapixel photographs, AVIF was 2 to 4% smaller, which is within noise. What it reliably buys is time — about 7 seconds where the JPEG search takes 11.7, and three probes rather than five. It is written only on macOS.

WebP is lossless, because the pure-Rust encoder has no other kind and adding one would mean a C dependency. It suits what a PNG suits: a flat-colour 800x600 PNG went from 6,926 to 514 bytes. A photograph encoded this way comes out several times larger and is refused — not by recognising a photograph, but because a result larger than its source is refused on principle.

That rule needed saying properly, and one case had it backwards. A conversion has no size to beat, since a raster of a drawing is legitimately larger than the drawing. A format asked for by name is the exception: asking for AVIF is asking for a smaller file of the same picture, and one that came out larger did not do what was asked.

Changes: #60, #61.

Not notarized. macOS will refuse to open it on first launch: System Settings, Privacy & Security, scroll down, Open Anyway. Control-click and Open no longer bypasses Gatekeeper on Sequoia and later. Requires macOS 14.

SHA-256

e6255a7d24c1a17fb1e04c6ed1db26650c945baf8e41cbd40e21e554293dfc6f  Squint-0.6.0.dmg
d13ec292e90c082be2bb2bf044e862ca62df29ec0f312a0bcc765d4d5f438749  Squint-0.6.0.zip

Squint 0.5.0

Squint 0.5.0 Pre-release
Pre-release

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 14 Sep 04:26
8a9da01

WebP and AVIF are read. Neither could be opened at all before this, so a picture from a browser or a newer phone was a file Squint had nothing to say about. Both now go through the same door HEIC does: decoded, and written as a JPEG beside the original by Shrink for Email and Shrink for Social. Remove Location Data accepts both and rewrites them as themselves, so a WebP stays a WebP with its EXIF and XMP gone and its colour profile kept.

An animated WebP is refused rather than converted. Every decoder hands back the first frame and Squint has no animated encoder to put the rest back, so a conversion would quietly throw away everything after frame one. The same now holds for an AVIF image sequence, which macOS would otherwise decode to a single still. Stripping either still works and leaves the frames alone.

SVG, WebP and AVIF appear in the Finder menu. SVG was readable in 0.4.0 from the command line only, because no menu entry ever declared the type; the same was true of WebP and AVIF the moment they were added. Two lists in two files decide whether an entry appears and whether the work is then done, and both were missing these formats. AVIF had to be named in its own right: it does not conform to public.heif, and neither does public.heic — both conform to public.heif-standard, so the entries already there covered nothing else.

A colour profile stored in a WebP's ICCP chunk is carried into the JPEG. Without that a Display P3 picture arrives untagged, is read as sRGB, and comes out visibly flat.

Two crashes are gone. A file of twelve to fifteen bytes beginning with ftyp — a truncated download, or anything at all that a right-click reaches — could panic the engine while its container was being identified. And a HEIC or AVIF declaring a box size near the top of the address space sent the structure walk backwards instead of forwards, consuming memory until the machine gave up; that one has been reachable since HEIC support arrived.

Four defects came out of an outside review of this work, each reproduced as a failing test before the code was changed. The record, including where the reviewers were wrong, is in review/webp-avif/.

One limitation worth stating: a WebP has no orientation field of its own, and the only place a turn can be recorded is inside its EXIF chunk, which nothing here reads yet. Such a picture converts the way its pixels are stored rather than the way it is meant to be seen.

Changes: #56, #57.

Not notarized. macOS will refuse to open it on first launch: System Settings, Privacy & Security, scroll down, Open Anyway. Control-click and Open no longer bypasses Gatekeeper on Sequoia and later. Requires macOS 14.

SHA-256

10d1e1d08525099479bd1d6415c3bebb4eaa0147f5f397a44aee70c746b1a321  Squint-0.5.0.dmg
710205beefc0da990d77b067f881d414e631471993fd64d1ff8ad48eae275ee3  Squint-0.5.0.zip

Squint 0.4.0

Squint 0.4.0 Pre-release
Pre-release

Choose a tag to compare

@TheBenMeadows TheBenMeadows released this 13 Sep 20:18
9c21c98

The release that can deliver the next one. Squint carries an updater from here: Squint menu → Check for Updates. It asks once whether to check on a schedule rather than deciding for you, and every update it installs is verified against a key compiled into the build. This is the last version anyone installs by hand.

Squint: Shrink for Social is the fifth Finder entry: 1440 pixels on the long edge, written beside the original as name-social.jpg, accepting HEIC like the email entry. Smaller than the email copy because the destinations differ — Instagram shows a feed picture 1080 wide, X recompresses whatever it is given, and a Nostr client recompresses nothing at all, so what you post is what every reader downloads. Measured on a 5712x4284 photograph: 331 KB, against 667 KB at the email cap.

GIF can have what it discloses removed. Squint: Remove Location Data accepts one now, alongside HEIC and TIFF. Out goes the comment and every application block the stripper was not told to keep, which is how XMP and anything a future encoder invents leave without being named; the frame timing, the animation loop count, drawn text and the colour profile stay. The pixels are copied untouched.

SVG is read from the command line and drawn to a JPEG beside the original. A drawing has no pixels of its own, so it is rendered at whatever size was asked for. Two deliberate choices: the renderer ignores any file a document names, so a drawing cannot make Squint read your disk, and the picture is composited onto white before the alpha is dropped, because JPEG has none.

Under all of it, a rule that was inconsistent is now stated once. Never growing a file is about replacing one; it says nothing about a conversion, whose result goes beside the original and is a different kind of thing. Fast and Quality used to answer differently on the same file.

Changes: #49, #50, #51, #52, #53, #54. Review records in review/.

Not notarized. macOS will refuse to open it on first launch: System Settings, Privacy & Security, scroll down, Open Anyway. Control-click and Open no longer bypasses Gatekeeper on Sequoia and later. Requires macOS 14.

SHA-256

5f099ddedcb7900450a461e0def02a161910f570deff71f720c59397e3056d9c  Squint-0.4.0.dmg
cf10d8d29c7e289a5090bcbdafbb27001eb0c5c02cf494f1ef3055099c31eebd  Squint-0.4.0.zip