Skip to content

Instantly share code, notes, and snippets.

@Davr1
Forked from marcan/gamma_trick.sh
Last active November 12, 2023 18:42
Show Gist options
  • Save Davr1/1c76979ef9e9c75d49b429b40e060afc to your computer and use it in GitHub Desktop.
Save Davr1/1c76979ef9e9c75d49b429b40e060afc to your computer and use it in GitHub Desktop.
Two images in one using the PNG gamma header trick.
@echo off
rem PNG Gamma trick (by @marcan42 / marcan@marcan.st)
rem
rem This script implements an improved version of the gamma trick used to make
rem thumbnail images on reddit/4chan look different from the full-size image.
rem
rem Sample output (SFW; images by @Miluda):
rem https://mrcn.st/t/homura_gamma_trick.png
rem https://www.reddit.com/r/test/comments/6edthw/ (click for fullsize)
rem https://twitter.com/marcan42/status/869855956842143744
rem
rem Some backstory, explanation and example (slightly NSFW):
rem https://www.reddit.com/r/touhou/comments/6e6lga/a/di83t02/
rem
rem No idea who came up with the concept; this is an old trick, but past
rem implementations I've seen were less correct than this one :-)
rem
rem This trick works on at least Reddit, 4chan and similar imageboards, Google
rem Drive, Slack, and probably many others. It does not work on Twitter, as
rem Twitter always preprocesses PNG images and strips the gAMA chunk. It does,
rem however, work with e.g. imgur embed previews on Twitter.
rem
rem *Different* one-liner trick that works on Twitter (for grayscale images):
rem https://twitter.com/marcan42/status/869858577116086272
rem
rem License: public domain
set high="%~1" &rem High image (full-size original view)
set low="%~2" &rem Low image (thumbnail) (should be the same size)
set output="output.png"
if not "%~3"=="" (
set output="%~3" &rem Output image
)
for /f "tokens=*" %%a in ('convert %high% -format "%%wx%%h" info:') do (set size=%%a)
rem Give a slight brightness boost to the high source, then apply the gamma.
rem This ensures that the pixels look mostly white.
convert %high% -alpha off +level 3.5%%,100%% -gamma 20 high_gamma.png
rem Since the low image will be washed out, use gamma to darken it a bit, then
rem reduce its brightness to ensure that its pixels become black after PNG gamma.
rem 77% brightness gets crushed down to 0x00 or 0x01, enough for our purposes.
set low_gamma=-alpha off -gamma 0.8 +level 0%%,77%%
rem To get rid of the slight "halo" of the high image, we're going to cancel it
rem out from the low image. The equation that we need is:
rem output = ¾low + ¼ (what we want, for high = white)
rem output = ¾output_low + ¼high (what we get)
rem Solve for output_low:
rem ¾output_low + ¼high = ¾low + ¼
rem ¾output_low = ¾low + ¼ - ¼high
rem output_low = low + ⅓ - ⅓high
rem This assumes "dumb" resizing (not gamma-correct). For gamma-correct resizing,
rem or for viewing at 1:1 (which is equivalent to gamma-correct resizing, because
rem physics, assuming your monitor isn't mangling things), this operation would
rem have to be done in a linear colorspace. In practice, the vast majority of
rem resizing implementations are not gamma-correct, so this works.
convert ^( %low% %low_gamma% ^) high_gamma.png ^
-compose Mathematics -define compose:args="0,-0.33,1,0.33" ^
-composite low_adjusted.png
rem Now compose both images together using the mask, then set the gamma metadata.
rem note that the typical display gamma is 2.2 and image gamma is the reciprocal
rem 1/2.2. Since we're adding a gamma of 20, we need 1/2.2/20 = 0.022727.
rem We also force the PNG encoder to include the gAMA chunk (and no other
rem spurious metadata).
convert low_adjusted.png high_gamma.png -size %size% pattern:gray25 -composite ^
-set gamma 0.022727 -define png:include-chunk=none,gAMA %output%
rem Remove leftover files
del low_adjusted.png high_gamma.png
Copy link

ghost commented Jul 19, 2023

How do I use this? I'm dumb.

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