Repository: beetbox/beets

Issue:
Fetch art is pixelated
### Setup

* OS: Docker image (`linuxserver/docker-beets:nightly`)
* Python version: `3.8.5`
* beets version: `HEAD`
* Turning off plugins made problem go away (yes/no): N/A

### Problem

Seems like `fetchart` is pixelating the images when resizing. Not sure if this is a `Pillow` problem or something beets is doing.

Running this command in verbose (`-vv`) mode:

```sh
beet -vv fetchart -f 53 thieves after hours
user configuration: /config/config.yaml
data directory: /config
plugin paths: 
Sending event: pluginload
library database: /config/musiclibrary.blb
library directory: /data/media/music
Sending event: library_opened
fetchart: trying source filesystem for album 53 Thieves - after hours
fetchart: trying source coverart for album 53 Thieves - after hours
fetchart: trying source coverart for album 53 Thieves - after hours
fetchart: trying source itunes for album 53 Thieves - after hours
fetchart: getting URL: https://itunes.apple.com/search?term=53+Thieves+after+hours&entity=album&media=music&limit=200
ImageMagick version check failed: [Errno 2] No such file or directory: 'magick'
ImageMagick version check failed: [Errno 2] No such file or directory: 'convert'
artresizer: method is (1, (0,))
fetchart: downloading image: https://is4-ssl.mzstatic.com/image/thumb/Music124/v4/02/24/59/02245915-fb50-26d7-6a10-b976526d3af1/source/1200x1200bb.jpg
fetchart: downloaded art to: /tmp/tmp3a64362y.jpg
fetchart: image size: (1200, 1200)
fetchart: image needs resizing (1200 > 1000)
fetchart: using remote image /tmp/tmp3a64362y.jpg
artresizer: PIL resizing /tmp/tmp3a64362y.jpg to /tmp/tmpbo33o8x7.jpg
Sending event: art_set
Sending event: database_change
fetchart: 53 Thieves - after hours: found album art
Sending event: cli_exit
```

Output looks good, no errors there.

---

Led to this problem:

<details>
<summary>Original Image</summary>

![image](https://user-images.githubusercontent.com/12074633/92248560-e43e1380-ee96-11ea-8967-cece04e5e8c6.png)

</details>

<details>
<summary>Resized Image</summary>

![cover](https://user-images.githubusercontent.com/12074633/92248372-90cbc580-ee96-11ea-972a-ddd3b325b58f.jpg)

</details>

My configuration (output of `beet config`) is:

```yaml
fetchart:
    auto: yes
    maxwidth: 1000
    enforce_ratio: yes
    cautious: yes
```

If I use:

```yaml
fetchart:
    auto: yes
    # maxwidth: 1000
    enforce_ratio: yes
    # cautious: yes
```

Comes out just fine.

---

### Suggested solution

Installing the `ImageMagick` library worked for resizing. So it seems that we do need `ImageMagick` to use fetchart to it's fullest extent.

`readthedocs` state that:

> Note: maxwidth and enforce_ratio options require either ImageMagick or Pillow.

Not sure where to go from here, but either:

1. Update doc to include both (or perhaps maybe just `ImageMagick` here works
2. Figure out why Pillow is destroying these images


Discussion:
Oh no! That image is ridiculously bad. 😆

I'm pretty stumped about why PIL would do such a bad job. Maybe it's worth isolating the call to the PIL API to see if anything's going obviously wrong, like a missing parameter that says "make the image look not terrible"? But otherwise, yeah, I concur with your suggestion to at least warn about this in the docs. And maybe we should even remove the PIL option…
Would be nice if the Pillow command was printed in -v or -vv mode.

edit: Relevant file / function:
https://github.com/beetbox/beets/blob/00c6d1439ee29b3b4592d6f65cfa57b1d1f96575/beets/util/artresizer.py#L67
I believe it is

> `artresizer: method is (1, (0,))`
> `artresizer: PIL resizing /tmp/tmp3a64362y.jpg to /tmp/tmpbo33o8x7.jpg`

What other information would you like to see?
My mistake. I have the command at the link I posted (the try/except block). I thought it was a 1-line call to Pillow but the code block has a few steps.

https://github.com/beetbox/beets/blob/00c6d1439ee29b3b4592d6f65cfa57b1d1f96575/beets/util/artresizer.py#L76
Gotcha. Maybe this upcoming weekend I'll do some more debugging and see what types of outputs I get for PIL resizing... Could be the library API has changed or needs updating.

edit: Will also throw in some more `debug` logs there :)

Resolving patch:
diff --git a/beets/util/artresizer.py b/beets/util/artresizer.py
--- a/beets/util/artresizer.py
+++ b/beets/util/artresizer.py
@@ -77,6 +77,11 @@ def pil_resize(maxwidth, path_in, path_out=None, quality=0):
         im = Image.open(util.syspath(path_in))
         size = maxwidth, maxwidth
         im.thumbnail(size, Image.ANTIALIAS)
+
+        if quality == 0:
+            # Use PIL's default quality.
+            quality = -1
+
         im.save(util.py3_path(path_out), quality=quality)
         return path_out
     except IOError:


Test patch: