Skip to content

feat(presets): a size limit, and ready-made presets for email, Discord, WhatsApp and Instagram (#553) - #567

Open
cre8ive-marketing wants to merge 3 commits into
KnifeLemon:mainfrom
cre8ive-marketing:feat/553-fit
Open

cre8ive-marketing wants to merge 3 commits into
KnifeLemon:mainfrom
cre8ive-marketing:feat/553-fit

Conversation

@cre8ive-marketing

Copy link
Copy Markdown
Collaborator

Part 1 of #553, as approved: the ready-made presets are only in the Add list, with no migration, no schema change and nothing on the default donut.

What it does

Size limit (MB) on a preset, one field for pictures (next to Quality) and one for videos (with the other video options). 0 = no limit.

  • Pictures: a result over the limit is saved again at a lower quality, 10 at a time down to 50, then with fewer pixels, aiming just under the limit, until it fits (ImageEncoder.FitToSize).
  • Videos: a result over the limit is encoded again from the source at the bitrate its length allows, less the sound (96 kbit/s at most) and a 5 % margin for the container. Two tries at most, since a bitrate is an average. It uses software encoding, since every encoder takes -b:v. An MP4 that Balanced would have copied as it is gets encoded too.
  • When it can't fit (a one-hour film in 10 MB, a noise picture in 100 bytes), the file fails with "It can't be made small enough for the size limit" and the sizes, rather than handing over a file that breaks the limit.
  • Only the result has to fit: like the playback speed, only the step that writes the result sees the limit, not a picture passed from one engine to the next.

Settings → Presets → New is now a menu: Empty preset, or a copy of a ready-made one:

The New menu

Preset Target Limit
Video for email MP4 18 MB
Video for Discord MP4 10 MB
Video for WhatsApp MP4, 720p 16 MB
Photo for Instagram JPG, 1080 px wide —

Two choices that differ from the plan, for you to check:

  • Email is 18 MB, not 20. An attachment grows by about a third on the way (base64), and Gmail and most providers stop at 25 MB, so a 20 MB file would bounce.
  • Instagram is 1080 px wide rather than a 1080 px long edge. Instagram's sizes are 1080 wide (1080 × 1350 for 4:5); a long edge of 1080 would make a 4:5 photo 864 wide, and Instagram scales it up.

Each Add makes a new preset with its own id, so it can be added twice and changed freely. The names are translated (NameKey). New strings are in all 16 languages.

Tests

  • SizeLimitTests (Engines):
    • a noisy picture is fitted under 200 KB, first by quality, then smaller, keeping its shape;
    • a picture already under the limit is left as written;
    • an impossible limit is refused;
    • the bitrate arithmetic, and CRF / -b:v 0 turned into a bitrate;
    • real FFmpeg: an 8 s noisy 720p video is fitted under 1 MB, and one too long for 50 KB is refused.
  • SizeLimitTests (Core): only the last step of a two-engine route gets the limit; the ready-made presets are offered but not in the library.
  • RenderTests.Add_offers_presets_for_where_a_file_goes_and_the_editor_keeps_their_size_limit (en, ru): Add makes two separate copies; the editor shows and saves the limit, and drops it for a target where it isn't shown. It also saves the screenshot above.
  • dotnet format --verify-no-changes is clean.
  • Full dotnet test: Platform 81, Core 604, CLI 27, Setup 176, Engines 1828 and App 1346 pass, none fail.

Part of #553 (Undo is #564).

…nifeLemon#553)

Pictures and videos get a "Size limit (MB)". A picture over it is saved
again at a lower quality (down to 50), then smaller, until it fits. A video
over it is encoded again from the source at the bitrate its length allows,
twice at most. When it can't fit, the file is refused with a reason rather
than handed over too large. Only the step that writes the result sees the
limit.

Settings → Presets → New now offers an empty preset or a copy of a
ready-made one: video for email (18 MB), Discord (10 MB), WhatsApp (720p,
16 MB) and a photo for Instagram (JPG, 1080 px wide). They aren't in the
library or on a donut: no settings migration.
@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

@KnifeLemon, CI is green on every check here. When you have reviewed it, could you merge it into main?

@KnifeLemon KnifeLemon left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @cre8ive-marketing, this follows the #553 decision exactly: the ready-made presets are only in the New menu, there's no migration and nothing goes on the donut. Stripping the limit from every step but the last in JobQueue is the right call. Both of your choices are right: 18 MB for email (once a megabyte is 1,000,000 bytes, point 3), and 1080 px wide for Instagram, since that's what Instagram uses for square, 4:5 and landscape, and ResizeMode.Width never upscales.

  1. The limit is silently ignored on several routes where the field is shown. It's only applied in ImageEncoder.Write (single frames) and the plain FfmpegConverter path. It does nothing for HEIC (shows the field but is written by HeicWriter, FfmpegConverter.cs:129); CAD and 3D renders to JPG/WebP (CadConverter.cs:127, ModelConverter.cs:168); animated WebP and multi-page files (ImageEncoder.cs:399); "Remove metadata" MP4 → MP4 (FfmpegConverter.cs:154, which returns before fitting); Merge videos and Video from images (JobQueue.cs:462); VOB and DV (a fixed -b:v or no rate argument for AtBitrate to replace). The PR promises a failure rather than handing over a file that breaks the limit, so please add one check after the last step in JobQueue: if an output is over MaxSizeMb, fail it with error.over_size_limit. Also hide the field where nothing can fit it (joins, vob/dv), or fit those routes as well.
  2. Video: one encode, not up to three, and keep the progress bar moving. Today a file over the limit is encoded in full at CRF, then once or twice more at a bitrate (FfmpegConverter.cs:196, :230), and those runs pass progress: null, so the bar sits at the end for minutes. When MaxSizeMb > 0 and the duration is known, add -maxrate {kbps}k -bufsize {2×kbps}k to the first pass next to the CRF: one encode, never larger than the plain CRF result, and usually within the limit. Keep the bitrate re-encode only as the fallback, with progress. When FitBitrateKbps returns 0, refuse before encoding anything ("an hour in 10 MB" currently encodes the whole film first).
  3. MB should be 1,000,000 bytes. ImageEncoder.cs:420 and FfmpegConverter.cs:217 use MaxSizeMb * 1024 * 1024. Filee shows sizes in decimal MB, and so do the services: with MiB, "18 MB" is 18.87 MB, about 25.8 MB after base64, so it bounces at 25 MB. The same goes for WhatsApp 16 and Discord 10. The error detail (/ 1048576.0) should use the same unit.
  4. Pictures have no pixel floor. After quality 50, FitToSize shrinks up to 8 more times, so a large photo with a tight limit can come back as a thumbnail and count as fitted. Please stop shrinking below a sensible size (for example a long edge of 640 px, or a quarter of the original) and refuse there.
  5. Small fixes: Preset.cs:613 still says "email 20"; PresetsPage.axaml:26-29 hard-codes the four menu items to PlacePresets[0..3], so generating them from PlacePresets would keep the menu in step if the list changes.

…cimal MB

From the review of KnifeLemon#567:
- The queue checks every result against the preset's limit after the last step, and after a join, and refuses one that's over (HEIC, CAD and 3D renders, animations, pages, Remove metadata). The video field is hidden for joins, slideshows, VOB and DV.
- Video: one encode, its bitrate capped (-maxrate / -bufsize) at what the length allows next to the CRF. The video is never copied as-is with a limit, and a second encode at a lower bitrate runs only if the first missed, on the last tenth of the progress bar. When nothing fits, it's refused before anything is encoded.
- MB is 1,000,000 bytes (SizeLimit.Bytes), in the error detail too.
- Pictures stop shrinking at a long edge of 640 px (or their own) and are refused there, never made a thumbnail.
- The New menu is filled from PlacePresets; the "email 20" comment says 18. German strings for the new keys (KnifeLemon#541).
@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

@KnifeLemon, thanks for the review. All five points are in, pushed as 87cfb1e, with main merged in:

  1. Routes that didn't fit: SizeLimit.Check runs after the last step (and after a join) in JobQueue. A picture or video over its limit is refused with error.over_size_limit, and the file is discarded, never handed over. That covers HEIC, CAD and 3D renders, animations and pages, joins, and Remove metadata. The video field is hidden for joins, slideshows, VOB and DV.
  2. One video encode: with a limit, the first encode gets -maxrate {kbps}k -bufsize {2×kbps}k next to its CRF; VP9's and libaom's -b:v 0 becomes the cap.
    • With a limit, the video is never copied as it is, the sound is at most 96 kbit/s a track, and no graphics chip encodes (MediaEncoding.ForSizeLimit).
    • When nothing fits ("an hour in 10 MB"), it is refused before anything is encoded.
    • The bitrate re-encode runs only if the capped one missed, on the last tenth of the progress bar.
  3. Decimal MB: SizeLimit.Bytes uses 1,000,000 bytes, and so does the error detail (SizeLimit.Describe).
  4. Pixel floor: pictures stop shrinking at a long edge of 640 px, or their own if smaller, and are refused there (ImageEncoder.MinFittedLongEdge).
  5. Small fixes: the comment says 18 MB, and the New menu is filled from PlacePresets in code-behind.

German strings for the new keys are included, since #541 came in on main.

New tests:

  • the queue refuses a result no engine fitted and leaves nothing behind;
  • a video limit says nothing about a picture;
  • the capped arguments for x264 and VP9;
  • with a limit, a video is never copied and no graphics chip encodes;
  • decimal MB;
  • the 640 px floor;
  • "8 s in 50 KB" is refused before encoding;
  • the editor hides the field for VOB and joins.

Full dotnet test: Platform 81, Core 606, CLI 30, Setup 181, Engines 1833 and App 1371 pass, none fail.

@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

@KnifeLemon, CI is green on every check after the review fixes. Could you take another look and merge it into main if it is good?

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

Labels

feature New features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants