SHARE
TWEET

4-way JPEG

a guest Apr 18th, 2019 111 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/bin/bash
  2. # This creates an JPEG file with four different appearances depending on how the image is decoded.
  3. # The dct* tools are available at https://gitgud.io/dcttransform/dcttransform
  4.  
  5. if (($# != 5)); then
  6.   echo "Usage: $0 input1 input2 input3 input4 output"
  7.   exit
  8. fi
  9. for i in {1..4}; do
  10.   if [ ! -f "${!i}" ]; then
  11.     echo "input file does not exist: $1"
  12.     exit
  13.   fi
  14. done
  15. set -x -e
  16.  
  17. # Working directory.
  18. work=$(mktemp -d)
  19. for i in {1..4}; do
  20.   cp -- "${!i}" "$work/input$i"
  21. done
  22. pushd "$work" || exit
  23.  
  24. # The quantization table used in the files created.
  25. # All values are set to 32.
  26. yes 32 | head -n 64 > qtable.txt
  27.  
  28. # Create two color palettes.
  29. # 8colors.jpg contains the colors obtained when pushing Y, Cb, Cr outside the valid ranges.
  30. #   These are the intended colors for the final image.
  31. # 8legal.jpg contains the colors obtained by setting Y, Cb, Cr to 128 +/- 32.
  32. #   Images are mapped to this palette before JPEG compression;
  33. #   then the DCT coefficients are upscaled to send them out of the valid range.
  34. convert -size 64x8 xc: ppm:- \
  35.   | cjpeg -qtables qtable.txt -qslots 0 -sample 1x1 > 8blank.jpg
  36. dcttransform '
  37.    a = new Uint16Array(3*8*64);
  38.    i = 0;
  39.    for (c=0;c<3;c++) for(z=-1;z<=1;z+=2) for(y=-1;y<=1;y+=2) for(x=-1;x<=1;x+=2) {
  40.      a[64*i] = 64*[x,y,z][c];
  41.      i++;
  42.    }
  43.    a
  44.  ' 8blank.jpg > 8colors.jpg
  45. dcttransform 'dct.map(x => x/8)' 8colors.jpg > 8legal.jpg
  46.  
  47. # Create two more color palettes.
  48. # These are similar to the above except that an additional value for Y, Cb, Cr has been added in the middle.
  49. # This middle color will be created in the final image by using one of the AC components for dithering.
  50. convert -size 216x8 xc: ppm:- \
  51.   | cjpeg -qtables qtable.txt -qslots 0 -sample 1x1 > 27blank.jpg
  52. dcttransform '
  53.    a = new Uint16Array(3*27*64);
  54.    i = 0;
  55.    for(c=0;c<3;c++) for(z=-1;z<=1;z++) for(y=-1;y<=1;y++) for(x=-1;x<=1;x++) {
  56.      a[64*i] = 64*[x,y,z][c];
  57.      a[64*i+4] = 64*([x,y,z][c]==0);
  58.      i++;
  59.    }
  60.    a
  61.  ' 27blank.jpg > 27colors.jpg
  62. convert 27colors.jpg -colorspace LAB -resize 12.5% -scale 800% 27colors.png
  63. dcttransform 'dct.map((x, i) => (i%64==0) ? x/8 : 0)' 27colors.jpg > 27legal.jpg
  64. composite -blend 85% 27colors.png 27legal.jpg 27intermediate1.png
  65. composite -blend 35% 27colors.png 27legal.jpg 27intermediate2.png
  66.  
  67. # Quantize all images to the colors in the palette.
  68. # Pixelate into 8x8 blocks.
  69. # The images are desaturated a bit before dithering as it seems to improve results.
  70. for i in 1 3 4; do
  71.   convert "input$i" -colorspace sRGB -resize 12.5% +level 20% -remap 27colors.png +dither -remap 27intermediate1.png -remap 27intermediate2.png -remap 27legal.jpg -scale 800% "quant$i-27.ppm"
  72. done
  73. for i in 2 4; do
  74.   convert "input$i" -colorspace sRGB -resize 12.5% +level 20% -remap 8colors.jpg +dither -remap 8legal.jpg -scale 800% "quant$i-8.ppm"
  75. done
  76.  
  77. # JPEG compress the images using our quantization table.
  78. for f in *.ppm; do
  79.   convert "$f" ppm:- \
  80.     | cjpeg -qtables qtable.txt -qslots 0 -sample 1x1 "$f" > "${f%.*}.jpg"
  81.   dctextract < "${f%.*}.jpg" > "${f%.*}.dct"
  82. done
  83.  
  84. # Combine the images.
  85. cat quant{1-27,2-8,3-27,4-27,4-8}.dct \
  86.   | dcteval '
  87.      n = dct.length/5;
  88.      a = new Uint16Array(n);
  89.      for (i = 0; i < n; i += 64) {
  90.        // DC component
  91.        a[i] = (
  92.            512*Math.sign(dct[i]) +
  93.          + 128*Math.sign(dct[i]) * (dct[i+2*n]==0) +
  94.          + 256*Math.sign(dct[i+n]) * (dct[i]==0 ? +1 : -1)
  95.          - 128*Math.sign(dct[i+n]) * (dct[i]==0 && dct[i+2*n]==0)
  96.          - 128*Math.sign(dct[i+2*n])
  97.          - 64*Math.sign(dct[i+3*n])
  98.          - 32*Math.sign(dct[i+4*n])
  99.        );
  100.        // AC component 4 in x direction
  101.        a[i+4] = (
  102.            512*(dct[i]==0 && dct[i+2*n]!=0)
  103.          + 128*(dct[i+2*n]==0)
  104.          + 64*(dct[i+3*n]==0)
  105.        );
  106.        // AC component 4 in y direction
  107.        a[i+32] = (
  108.            128*(dct[i+2*n]==0)
  109.          + 512*(dct[i]==0 && dct[i+2*n]==0)
  110.        );
  111.      }
  112.      a
  113.    ' > output.dct
  114. dctreplace output.dct < quant1-27.jpg > output.jpg
  115.  
  116. # Clean up.
  117. popd
  118. cp -- "$work/output.jpg" "$5"
  119. rm -r -- "$work"
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top