💾 Archived View for rawtext.club › ~jmq › recycled › mvi-jpg-crop.gmi captured on 2023-04-26 at 13:48:16. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

➡️ Next capture (2024-06-16)

-=-=-=-=-=-=-

plugin for cropping JPEG files in mpv

December 2021

Motivation

Sometime within the past five years, gripped by the urge to clean out some of the clutter in my house, I removed all the photographs from a shelf full of photo albums and donated the empty binders to a nearby thrift store. The photographs themselves I stuffed into a couple of shoeboxes. My long-term plan was to scan the photographs and keep only the digital copies, appropriately tagged and sorted into folders. This plan would take on various shapes in the subsequent years, as I migrated from OS X to FreeBSD and later a CRUX Linux desktop.

The photo app that came with OS X did have the nifty feature of automatically detecting the boundaries of each picture (when five or six such pictures were placed on my flatbed scanner), but manual correction was required so often that I ended up looking for a better solution. In total, I only digitized about a hundred pictures using Apple's software.

While running FreeBSD, I came up with a pretty decent workflow for digitizing pictures, thanks to the informative status bar in mtPaint. After selecting a region with the mouse, I could find in the status bar the offset of the upper-left corner and the size of the selected region. This information remained visible if I moused over a terminal emulator, where I could run a command like

jpegtran -crop 800x600+150+2189 ~bruder/Scan_7145.jpg > new-mexico-vacation-12.jpg

to save the selected region with a more informative filename. Selecting a region by hand, copying the coordinates into the terminal emulator, and coming up with a good filename, were the slowest parts of the process, but after dozens of photos in a row I could easily get into a rhythm and speed through dozens more.

Lately the luxury of multi-hour gaps in my schedule has been harder to come by, so the manual integration of mtPaint and jpegtran would proceed at the slow starting pace every time, never having the chance to achieve a state of "flow" and move more quickly. I began to look for a solution that eliminated as much friction as possible.

Wayland Narrows the Solution Space

This past summer I made the leap to a Wayland-only desktop, installing only the bare minimum of X11 libraries and eschewing any software that required an X server. As a result, I could no longer consider mtPaint (with its informative status bar) a viable solution to the photo cropping problem. Thankfully the road to a Wayland-only desktop had been mapped out by more adventurous users, and they wrote up some helpful lists of replacements for X11-only programs. I pursued two of the recommended photo viewing apps: imv by Harry Jeffries, and mpv-image-viewer (mvi for short).

imv did expose a neat method for launching a script from within the program, but it did not export enough environment variables for accurate calculation of the correct jpegtran arguments. I did manage to get "close-enough" crops with a script launched from imv, but it required aligning the upper-left corner of the scanned image with the upper-left corner of the viewing window.

Lua scripting with mpv

The next possibility I explored was mvi, a suite of config files and scripts that turns mpv into a viewer for still photos. Thanks to the thorough documentation of mpv's Lua scripting interface, I was able to identify the methods that could construct the necessary jpegtran command automatically, upon releasing the mouse from a "select region" operation. Two new blocks of code are enough to do the job, one inside the refresh() function:


    draw_ass(a.text)
    if opts.save_crop then
    mp.set_property("file-local-options/osd-msg2", string.format("%ix%i+%i+%i",
            line_end.image[1] - line_start.image[1], line_end.image[2] - line_start.image[2],
            line_start.image[1], line_start.image[2]))
    end

and another inside the next_step() function:

    elseif state == 2 then
        local dim = mp.get_property_native("osd-dimensions")
        if not dim then return end
        state = 3
        second_point = cursor_video_space_normalized(dim)
        if opts.save_crop then
             cropdims = mp.get_property("file-local-options/osd-msg2")
             filehandle = mp.get_property("path")
             mp.command_native({
                 name="subprocess",
                 playback_only=true,
                 args={"jpegtran","-crop",cropdims,"-outfile","newcrop.jpg",filehandle}
             })
        end
        if opts.clear_on_second_point_set then
            next_step()
        end

I inserted these two blocks into the mvi script "ruler". To enable them, I just need to ensure that ${MVI_CONFIG_DIR}/script-opts/ruler.conf has a line that reads save_crop=yes. Then I can obtain a crop of the current image with just one keystroke and two mouse clicks. A follow-up bash script called "ncrop" takes one argument and uses that argument to rename the newly-created jpeg file.

External links (WWW)

mtPaint

imv

mvi

Conclusion

During a four-month stint of being separated from my flatbed scanner, I still found it useful to have this cropping functionality in mvi. Pictures uploaded from a smart phone, or screenshots taken inside a compositor that does not implement the layer-shell protocol, all usually include more pixels than I want to use. Being able to crop them with a keystroke and two mouse clicks is an immense productivity booster.

Back to Recycle Bin