getnikola / nikola

A static website and blog generator
https://getnikola.com/
MIT License
2.62k stars 450 forks source link

Thumbnail images are with the same size like the source images #3332

Closed marcuskammer closed 4 years ago

marcuskammer commented 4 years ago

Environment

Python Version: Python 3.7.3 Nikola Version: Nikola v8.0.3 Operating System: openSuse Tumbleweed / Windows 10

Description:

After i run nikola build it creates new thumbnail images, but with the same size like the source images. If you want, you can check it by yourself with the images from my photo blog repository [1].

-rw-r--r-- 1 marcus users 21771945 Dec 22 14:04 _63_1020.JPG -rw-r--r-- 1 marcus users 21771945 Dec 22 14:04 _63_1020.thumbnail.JPG -rw-r--r-- 1 marcus users 21936578 Dec 22 14:04 _63_1021.JPG -rw-r--r-- 1 marcus users 21936578 Dec 22 14:04 _63_1021.thumbnail.JPG -rw-r--r-- 1 marcus users 10862571 Dec 22 13:59 _DSC0849.JPG -rw-r--r-- 1 marcus users 10862571 Dec 22 13:59 _DSC0849.thumbnail.JPG -rw-r--r-- 1 marcus users 9256726 Dec 22 13:59 _DSC0850.JPG -rw-r--r-- 1 marcus users 9256726 Dec 22 13:59 _DSC0850.thumbnail.JPG -rw-r--r-- 1 marcus users 10139398 Dec 22 13:59 _DSC0851.JPG -rw-r--r-- 1 marcus users 10139398 Dec 22 13:59 _DSC0851.thumbnail.JPG -rw-r--r-- 1 marcus users 10533825 Dec 22 13:59 _DSC0852.JPG -rw-r--r-- 1 marcus users 10533825 Dec 22 13:59 _DSC0852.thumbnail.JPG -rw-r--r-- 1 marcus users 105627 Dec 22 14:03 IMG_0204.jpg -rw-r--r-- 1 marcus users 3781 Dec 22 14:03 IMG_0204.thumbnail.jpg -rw-r--r-- 1 marcus users 120466 Dec 22 14:03 IMG_0205.jpg -rw-r--r-- 1 marcus users 3541 Dec 22 14:03 IMG_0205.thumbnail.jpg -rw-r--r-- 1 marcus users 129014 Dec 22 14:03 IMG_0206.jpg -rw-r--r-- 1 marcus users 4713 Dec 22 14:03 IMG_0206.thumbnail.jpg -rw-r--r-- 1 marcus users 129206 Dec 22 14:03 IMG_0207.jpg -rw-r--r-- 1 marcus users 4826 Dec 22 14:03 IMG_0207.thumbnail.jpg -rw-r--r-- 1 marcus users 6481 Dec 22 14:04 index.html -rw-r--r-- 1 marcus users 4129 Dec 22 14:04 rss.xml

[1] My personal photo blog https://gitlab.com/marcuskammer/photoblog/tree/nikola/photoblog/galleries/travel

Kwpolska commented 4 years ago

This was discussed on IRC last month, and it was determined to be caused by EXIF metadata in the photos: (not really, see post below)

Log: https://irclogs.getnikola.com/logs/2019-11-13/

Kwpolska commented 4 years ago

I did some debugging. The images that fail to be processed are detected as<class 'PIL.MpoImagePlugin.MpoImageFile'> with is_animated = True, n_frames = 2. Nikola refuses to resize animated images.

I’m not sure where to go from there and what we should do to those files.

marcuskammer commented 4 years ago

Wow, thank you for your debugging. How can these images be classified as animated? Their are just regular jpegs, straight copied from my camera?! I did check the exif metadata with exiv2 and could not find any information about animation. Maybe it is a bug in the Python Lib Pillow? I will play around with Pillow.

marcuskammer commented 4 years ago

I did check the jpeg standard. https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format It is allowed to embed a thumbnail image into the Exif metadata of a jpeg image. Many camera producers do this to allow a preview of the image. The related exif metadata are Exif.Thumbnail.*. Because of this, PILLOW identifies these images as Multi Picture Object and not as JpegImageFile.

I also did check image_processing.py:

def resize_image(self, src, dst, max_size, bigger_panoramas=True, preserve_exif_data=False, exif_whitelist={}, preserve_icc_profiles=False):
        """Make a copy of the image in the requested size."""
        if not Image or os.path.splitext(src)[1] in ['.svg', '.svgz']:
            self.resize_svg(src, dst, max_size, bigger_panoramas)
            return
        im = Image.open(src)

        if hasattr(im, 'n_frames') and im.n_frames > 1:
            # Animated gif, leave as-is
            utils.copy_file(src, dst)
            return

It checks if the image has more than one frame. And of course it has 2 frames, the original image and the embedded thumbnail image. But it is wrong to suggest a image is of type GIF if the frame count is greater than 1?!

Kwpolska commented 4 years ago

Pillow also says that this image is_animated, although we don’t check that attribute. I think we could override this check for MPO/JPEG-with-thumbnail files, but you should perhaps report this issue with is_animated/n_frames directly to Pillow (https://github.com/python-pillow/Pillow/issues).

marcuskammer commented 4 years ago

I do not know the intention of if hasattr(im, 'n_frames') and im.n_frames > 1: but as the comment line suggests, it should check if the image is of type Gif. I would suggest the use of isinstance instead of hasattr. e.g.:

from PIL.GifImagePlugin import GifImageFile
if isinstance(im, GifImageFile):
    ...
Kwpolska commented 4 years ago

The current implementation has an issue with your images, but handles two other cases correctly: (a) non-animated GIFs can be scaled, and (b) animated images don’t have to be GIFs.

marcuskammer commented 4 years ago

It is getting more clear to me, thank you!. I guess, pillow should not handle these jpeg images, which includes a thumbnail, as MPO.

ralsina commented 4 years ago

Since there is no such thing as an animated JPEG, I will special-case that.