| #!/bin/bash | |
| # Copyright 2026 Google LLC | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| # ------------------------------------------------------------------------------ | |
| # | |
| # tests for command lines using image transforms (clap/irot/imir...) | |
| source $(dirname "$0")/cmd_test_common.sh || exit | |
| # Input file paths. | |
| INPUT_PNG="${TESTDATA_DIR}/paris_exif_xmp_icc.jpg" | |
| # Output file names. | |
| ENCODED_FILE="encoded.avif" | |
| # Cleanup | |
| cleanup() { | |
| rm -f -r "${TMP_DIR}" | |
| } | |
| trap cleanup EXIT | |
| pushd ${TMP_DIR} | |
| # Encode/decode uncropped image | |
| # Some image magick versions may drop EXIF. Remove it preemptively to avoid | |
| # ARE_IMAGES_EQUAL failing because of EXIF mismatch. | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" -o "${ENCODED_FILE}" | |
| "${AVIFDEC}" "${ENCODED_FILE}" "${ENCODED_FILE}.png" | |
| # Crop | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" --crop 10,50,100,25 -o "encoded_clap.avif" | |
| "${AVIFDEC}" "encoded_clap.avif" "encoded_clap.png" | |
| "${AVIFDEC}" "encoded_clap.avif" -q 100 "encoded_clap.jpg" | |
| # Rotation (0 degrees) | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" --irot 0 -o "encoded_irot0.avif" | |
| "${AVIFDEC}" "encoded_irot0.avif" "encoded_irot0.png" | |
| "${AVIFDEC}" "encoded_irot0.avif" -q 100 "encoded_irot0.jpg" | |
| # Rotation (90 degrees anti-clockwise) | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" --irot 1 -o "encoded_irot1.avif" | |
| "${AVIFDEC}" "encoded_irot1.avif" "encoded_irot1.png" | |
| "${AVIFDEC}" "encoded_irot1.avif" -q 100 "encoded_irot1.jpg" | |
| # Rotation (180 degrees) | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" --irot 2 -o "encoded_irot2.avif" | |
| "${AVIFDEC}" "encoded_irot2.avif" "encoded_irot2.png" | |
| "${AVIFDEC}" "encoded_irot2.avif" -q 100 "encoded_irot2.jpg" | |
| # Rotation (90 clockwise) | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" --irot 3 -o "encoded_irot3.avif" | |
| "${AVIFDEC}" "encoded_irot3.avif" "encoded_irot3.png" | |
| "${AVIFDEC}" "encoded_irot3.avif" -q 100 "encoded_irot3.jpg" | |
| # Mirror (top-to-bottom) | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" --imir 0 -o "encoded_imir0.avif" | |
| "${AVIFDEC}" "encoded_imir0.avif" "encoded_imir0.png" | |
| "${AVIFDEC}" "encoded_imir0.avif" -q 100 "encoded_imir0.jpg" | |
| # Mirror (left-to-right) | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" --imir 1 -o "encoded_imir1.avif" | |
| "${AVIFDEC}" "encoded_imir1.avif" "encoded_imir1.png" | |
| "${AVIFDEC}" "encoded_imir1.avif" -q 100 "encoded_imir1.jpg" | |
| # Combined transforms: crop + mirror (no rotation) | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" --crop 10,50,100,25 --imir 0 -o "encoded_crop_imir0.avif" | |
| "${AVIFDEC}" "encoded_crop_imir0.avif" "encoded_crop_imir0.png" | |
| "${AVIFDEC}" "encoded_crop_imir0.avif" -q 100 "encoded_crop_imir0.jpg" | |
| # Combined transforms: crop + rotation + mirror | |
| # MIAF (ISO/IEC 23000-22) specifies the application order: 1. clap, 2. irot, 3. imir. | |
| "${AVIFENC}" --ignore-exif -s 10 "${INPUT_PNG}" --crop 10,50,100,25 --irot 1 --imir 1 -o "encoded_combined.avif" | |
| "${AVIFDEC}" "encoded_combined.avif" "encoded_combined.png" | |
| "${AVIFDEC}" "encoded_combined.avif" -q 100 "encoded_combined.jpg" | |
| if command -v magick &> /dev/null | |
| then | |
| IMAGEMAGICK="magick" | |
| elif command -v convert &> /dev/null | |
| then | |
| IMAGEMAGICK="convert" | |
| else | |
| echo Missing ImageMagick, test skipped | |
| popd | |
| exit 0 | |
| fi | |
| "${IMAGEMAGICK}" --version | |
| JPEG_PSNR_THRESHOLD=48 | |
| # Crop | |
| "${IMAGEMAGICK}" "${ENCODED_FILE}.png" -crop 100x25+10+50 "encoded_clap_ref.png" | |
| "${ARE_IMAGES_EQUAL}" "encoded_clap_ref.png" "encoded_clap.png" 0 | |
| "${ARE_IMAGES_EQUAL}" "encoded_clap_ref.png" "encoded_clap.jpg" 0 ${JPEG_PSNR_THRESHOLD} | |
| # Rotation (0 degrees) | |
| "${IMAGEMAGICK}" "${ENCODED_FILE}.png" -rotate 0 "encoded_irot0_ref.png" | |
| "${ARE_IMAGES_EQUAL}" "encoded_irot0_ref.png" "encoded_irot0.png" 0 | |
| "${ARE_IMAGES_EQUAL}" "encoded_irot0_ref.png" "encoded_irot0.jpg" 0 ${JPEG_PSNR_THRESHOLD} | |
| # Rotation (90 degrees anti-clockwise) | |
| "${IMAGEMAGICK}" "${ENCODED_FILE}.png" -rotate -90 "encoded_irot1_ref.png" | |
| "${ARE_IMAGES_EQUAL}" "encoded_irot1_ref.png" "encoded_irot1.png" 0 | |
| "${ARE_IMAGES_EQUAL}" "encoded_irot1_ref.png" "encoded_irot1.jpg" 0 ${JPEG_PSNR_THRESHOLD} | |
| # Rotation (180 degrees) | |
| "${IMAGEMAGICK}" "${ENCODED_FILE}.png" -rotate 180 "encoded_irot2_ref.png" | |
| "${ARE_IMAGES_EQUAL}" "encoded_irot2_ref.png" "encoded_irot2.png" 0 | |
| "${ARE_IMAGES_EQUAL}" "encoded_irot2_ref.png" "encoded_irot2.jpg" 0 ${JPEG_PSNR_THRESHOLD} | |
| # Rotation (90 clockwise) | |
| "${IMAGEMAGICK}" "${ENCODED_FILE}.png" -rotate 90 "encoded_irot3_ref.png" | |
| "${ARE_IMAGES_EQUAL}" "encoded_irot3_ref.png" "encoded_irot3.png" 0 | |
| "${ARE_IMAGES_EQUAL}" "encoded_irot3_ref.png" "encoded_irot3.jpg" 0 ${JPEG_PSNR_THRESHOLD} | |
| # Mirror (top-to-bottom) | |
| "${IMAGEMAGICK}" "${ENCODED_FILE}.png" -flip "encoded_imir0_ref.png" | |
| "${ARE_IMAGES_EQUAL}" "encoded_imir0_ref.png" "encoded_imir0.png" 0 | |
| "${ARE_IMAGES_EQUAL}" "encoded_imir0_ref.png" "encoded_imir0.jpg" 0 ${JPEG_PSNR_THRESHOLD} | |
| # Mirror (left-to-right) | |
| "${IMAGEMAGICK}" "${ENCODED_FILE}.png" -flop "encoded_imir1_ref.png" | |
| "${ARE_IMAGES_EQUAL}" "encoded_imir1_ref.png" "encoded_imir1.png" 0 | |
| "${ARE_IMAGES_EQUAL}" "encoded_imir1_ref.png" "encoded_imir1.jpg" 0 ${JPEG_PSNR_THRESHOLD} | |
| # Combined transforms: crop + mirror (no rotation) | |
| "${IMAGEMAGICK}" "${ENCODED_FILE}.png" -crop 100x25+10+50 -flip "encoded_crop_imir0_ref.png" | |
| "${ARE_IMAGES_EQUAL}" "encoded_crop_imir0_ref.png" "encoded_crop_imir0.png" 0 | |
| "${ARE_IMAGES_EQUAL}" "encoded_crop_imir0_ref.png" "encoded_crop_imir0.jpg" 0 ${JPEG_PSNR_THRESHOLD} | |
| # Combined transforms: crop + rotation + mirror | |
| # MIAF (ISO/IEC 23000-22) specifies the application order: 1. clap, 2. irot, 3. imir. | |
| "${IMAGEMAGICK}" "${ENCODED_FILE}.png" -crop 100x25+10+50 -rotate -90 -flop "encoded_combined_ref.png" | |
| "${ARE_IMAGES_EQUAL}" "encoded_combined_ref.png" "encoded_combined.png" 0 | |
| "${ARE_IMAGES_EQUAL}" "encoded_combined_ref.png" "encoded_combined.jpg" 0 ${JPEG_PSNR_THRESHOLD} | |
| popd | |
| exit 0 |