calibreapp / image-actions

A Github Action that automatically compresses JPEGs, PNGs and WebPs in Pull Requests.
https://calibreapp.com/blog/compress-images-in-prs
GNU General Public License v3.0
1.42k stars 67 forks source link

[Bug] image-actions rotates image unexpectedly #218

Closed octref closed 1 year ago

octref commented 1 year ago

Describe the bug

Calibre rotates image unexpectedly.

image

How To Reproduce

  1. Have a portrait image
  2. Use the calibre GitHub Action

Screenshots

image image

Relevant Log Output

Images automagically compressed by [Calibre](https://calibreapp.com)'s [image-actions](https://github.com/marketplace/actions/image-actions) ✨

Compression reduced images by <strong>50.5%</strong>, saving <strong>11.42 MB</strong>.

| Filename | Before | After | Improvement |
| -------- | ------ | ----- | ----------- |
| <code>notes/agua-de-tuna-roja-sorbet.jpg</code> | 2.22 MB | 1.26 MB | -43.0% |
| <code>notes/ants-on-bread.jpg</code> | 2.79 MB | 1.58 MB | -43.5% |
| <code>notes/el-pan-como.jpg</code> | 1.70 MB | 704.16 KB | -59.6% |
| <code>notes/geisha.jpg</code> | 3.64 MB | 1.48 MB | -59.4% |
| <code>notes/huitlacoche-soup.jpg</code> | 2.54 MB | 1.58 MB | -38.0% |
| <code>notes/san-pablo1.jpg</code> | 4.10 MB | 1.91 MB | -53.4% |
| <code>notes/san-pablo2.jpg</code> | 5.62 MB | 2.70 MB | -52.0% |

Code of Conduct

octref commented 1 year ago

The project is internal and I'm not ready to share it publicly, sorry.

Here's the output from the step Compress Image

/usr/bin/docker run --name ghcriocalibreappimageactionsimageactionsmain_7db1bc --label ef7d85 --workdir /github/workspace --rm -e "INPUT_GITHUBTOKEN" -e "INPUT_COMPRESSONLY" -e "INPUT_JPEGQUALITY" -e "INPUT_JPEGPROGRESSIVE" -e "INPUT_PNGQUALITY" -e "INPUT_WEBPQUALITY" -e "INPUT_IGNOREPATHS" -e "HOME" -e "GITHUB_JOB" -e "GITHUB_REF" -e "GITHUB_SHA" -e "GITHUB_REPOSITORY" -e "GITHUB_REPOSITORY_OWNER" -e "GITHUB_REPOSITORY_OWNER_ID" -e "GITHUB_RUN_ID" -e "GITHUB_RUN_NUMBER" -e "GITHUB_RETENTION_DAYS" -e "GITHUB_RUN_ATTEMPT" -e "GITHUB_REPOSITORY_ID" -e "GITHUB_ACTOR_ID" -e "GITHUB_ACTOR" -e "GITHUB_TRIGGERING_ACTOR" -e "GITHUB_WORKFLOW" -e "GITHUB_HEAD_REF" -e "GITHUB_BASE_REF" -e "GITHUB_EVENT_NAME" -e "GITHUB_SERVER_URL" -e "GITHUB_API_URL" -e "GITHUB_GRAPHQL_URL" -e "GITHUB_REF_NAME" -e "GITHUB_REF_PROTECTED" -e "GITHUB_REF_TYPE" -e "GITHUB_WORKFLOW_REF" -e "GITHUB_WORKFLOW_SHA" -e "GITHUB_WORKSPACE" -e "GITHUB_ACTION" -e "GITHUB_EVENT_PATH" -e "GITHUB_ACTION_REPOSITORY" -e "GITHUB_ACTION_REF" -e "GITHUB_PATH" -e "GITHUB_ENV" -e "GITHUB_STEP_SUMMARY" -e "GITHUB_STATE" -e "GITHUB_OUTPUT" -e "RUNNER_OS" -e "RUNNER_ARCH" -e "RUNNER_NAME" -e "RUNNER_ENVIRONMENT" -e "RUNNER_TOOL_CACHE" -e "RUNNER_TEMP" -e "RUNNER_WORKSPACE" -e "ACTIONS_RUNTIME_URL" -e "ACTIONS_RUNTIME_TOKEN" -e "ACTIONS_CACHE_URL" -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" -v "/home/runner/work/soc/soc":"/github/workspace" ghcr.io/calibreapp/image-actions/image-actions:main
->> Using config: {"jpeg":{"quality":80,"progressive":false},"png":{"quality":80},"webp":{"quality":80},"ignorePaths":["node_modules/**"],"compressOnly":true}
->> Locating images…
To turn on DEBUG level logging for image-actions, see this reference: https://docs.github.com/en/actions/managing-workflow-runs/enabling-debug-logging
  jpeg: {
    id: 'jpeg',
    input: { file: true, buffer: true, stream: true },
    output: { file: true, buffer: true, stream: true }
  },
  png: {
    id: 'png',
    input: { file: true, buffer: true, stream: true },
    output: { file: true, buffer: true, stream: true }
  },
  webp: {
    id: 'webp',
    input: { file: true, buffer: true, stream: true },
    output: { file: true, buffer: true, stream: true }
  },
  tiff: {
    id: 'tiff',
    input: { file: true, buffer: true, stream: true },
    output: { file: true, buffer: true, stream: true }
  },
  magick: {
    id: 'magick',
    input: { file: true, buffer: true, stream: true },
    output: { file: true, buffer: true, stream: true }
  },
  openslide: {
    id: 'openslide',
    input: { file: false, buffer: false, stream: false },
    output: { file: false, buffer: false, stream: false }
  },
  dz: {
    id: 'dz',
    input: { file: false, buffer: false, stream: false },
    output: { file: true, buffer: true, stream: true }
  },
  ppm: {
    id: 'ppm',
    input: { file: true, buffer: false, stream: false },
    output: { file: true, buffer: false, stream: false }
  },
  fits: {
    id: 'fits',
    input: { file: false, buffer: false, stream: false },
    output: { file: false, buffer: false, stream: false }
  },
  gif: {
    id: 'gif',
    input: { file: true, buffer: true, stream: true },
    output: { file: false, buffer: false, stream: false }
  },
  svg: {
    id: 'svg',
    input: { file: true, buffer: true, stream: true },
    output: { file: false, buffer: false, stream: false }
  },
  heif: {
    id: 'heif',
    input: { file: true, buffer: true, stream: true },
    output: { file: true, buffer: true, stream: true }
  },
  pdf: {
    id: 'pdf',
    input: { file: false, buffer: false, stream: false },
    output: { file: false, buffer: false, stream: false }
  },
  vips: {
    id: 'vips',
    input: { file: true, buffer: false, stream: false },
    output: { file: true, buffer: false, stream: false }
  },
  raw: {
    id: 'raw',
    input: { file: false, buffer: true, stream: true },
    output: { file: false, buffer: true, stream: true }
  }
}
->> Using config: {"jpeg":{"quality":80,"progressive":false},"png":{"quality":80},"webp":{"quality":80},"ignorePaths":["node_modules/**"],"compressOnly":true}
    - Processing: /github/workspace/notes/agua-de-tuna-roja-sorbet.jpg config={"quality":80,"progressive":false} output={"format":"jpeg","width":4032,"height":3024,"channels":3,"premultiplied":false,"size":1324877}
    - Processing: /github/workspace/notes/ants-on-bread.jpg config={"quality":80,"progressive":false} output={"format":"jpeg","width":4032,"height":3024,"channels":3,"premultiplied":false,"size":1652007}
    - Processing: /github/workspace/notes/el-pan-como.jpg config={"quality":80,"progressive":false} output={"format":"jpeg","width":1840,"height":2453,"channels":3,"premultiplied":false,"size":721057}
    - Processing: /github/workspace/notes/geisha.jpg config={"quality":80,"progressive":false} output={"format":"jpeg","width":4032,"height":3024,"channels":3,"premultiplied":false,"size":1548591}
    - Processing: /github/workspace/notes/huitlacoche-soup.jpg config={"quality":80,"progressive":false} output={"format":"jpeg","width":4032,"height":3024,"channels":3,"premultiplied":false,"size":1652156}
    - Processing: /github/workspace/notes/san-pablo1.jpg config={"quality":80,"progressive":false} output={"format":"jpeg","width":4032,"height":3024,"channels":3,"premultiplied":false,"size":2003600}
    - Processing: /github/workspace/notes/san-pablo2.jpg config={"quality":80,"progressive":false} output={"format":"jpeg","width":4032,"height":3024,"channels":3,"premultiplied":false,"size":2829650}
->> Generating markdown…
->> Using config: {"jpeg":{"quality":80,"progressive":false},"png":{"quality":80},"webp":{"quality":80},"ignorePaths":["node_modules/**"],"compressOnly":true}
Warning: The `set-output` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-[11](https://github.com/octref/soc/actions/runs/5993355890/job/16253711123#step:4:12)-github-actions-deprecating-save-state-and-set-output-commands/
benschwarz commented 1 year ago

@octref I have no doubt that the issue you've reported is happening on your repo and to your image

image-actions has been run on tens of thousands (probably more?) of images without any reports of rotation of images, so I find it difficult to believe that there's a bug in image-actions code that causes it.

Have you been able to replicate the issue on all images that you've tested?

octref commented 1 year ago

Let me go back in commit, get the old image, setup a new open repo for repro case so you can take a look.

octref commented 1 year ago

It repros!

Repo: https://github.com/octref/calibre-rotate-bug Action: https://github.com/octref/calibre-rotate-bug/actions/runs/6001844959/job/16276919435 Commit the action created: https://github.com/octref/calibre-rotate-bug/commit/00311ff1eb4df33d1b5b12c13668b4fb0ec5d2fe

benschwarz commented 1 year ago

@octref The image displays sideways in GitHub, but that looks like it's because the commit has already occurred.

image

Can you repro with a different image?

octref commented 1 year ago

The commit was created by the Action. You can see the diff: https://github.com/octref/calibre-rotate-bug/commit/00311ff1eb4df33d1b5b12c13668b4fb0ec5d2fe

If you check the log of this Action run: https://github.com/octref/calibre-rotate-bug/actions/runs/6001844959/job/16276919435

It shows the modification by the Calibre action

On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   agua-de-tuna-roja-sorbet.jpg

no changes added to commit (use "git add" and/or "git commit -a")
[main 00311ff] *
 1 file changed, 0 insertions(+), 0 deletions(-)
To https://github.com/octref/calibre-rotate-bug
   5fb7697..00311ff  main -> main
benschwarz commented 1 year ago

Thanks for the confirmation @octref. Can you repro with a different image?

As I said, image-actions has run on easily tens to hundreds of thousands of images and this is the first time image rotation has been a reported issue.

octref commented 1 year ago

Yes, here you go: https://github.com/octref/calibre-rotate-bug/actions/runs/6065968865/job/16456039262 which made this commit https://github.com/octref/calibre-rotate-bug/commit/69435608b121004dbd25d75189b015e2ef170d11

image

Can you fork the repo and try it out yourself?

benschwarz commented 1 year ago

Thanks for the additional testing @octref, appreciated.

From what I am able to tell, your test images contain EXIF metadata that includes the original orientation of the image (e.g.: portrait or landscape).

By default, Sharp (the library that performs the image compression) removes all EXIF metadata:

By default all metadata will be removed, which includes EXIF-based orientation.

There is a sharp function to retain EXIF metadata (withMetadata) that we could opt to use, however removing EXIF is an intentional feature of image-actions, as EXIF can greatly increase the size of an image (maximum 64 kB), and can also contain private information (such as geolocation of photos).

At present sharp does not have a passable configuration option to retain EXIF (outside of directly calling the function), so it's not a change we're likely to make to image-actions directly.

If you'd like to use image-actions, I'd recommend creating your own fork and including withMetadata() where sharp is called.

Hope that helps.