carsales / pyheif

Python 3.6+ interface to libheif library
Apache License 2.0
165 stars 41 forks source link

Struct heif_decoding_options: wrong total size #92

Open hamzabidi opened 1 year ago

hamzabidi commented 1 year ago

In a fastapi project, i have this method:

   @staticmethod
    def ios_image_converter(file: UploadFile) -> Tuple[UploadFile, str]:
        # source
        source_extension = 'heic'
        source_content_type = 'image/heif'

       # target
        target_extension = 'jpg'
        target_format = 'JPEG'
        target_content_type = 'image/jpeg'

        # source type checking
        if file.content_type != source_content_type:
            raise Exception(f"expected file type 'image/heif', got {file.content_type}")

        # converting
        heif_file = pyheif.read(file.file.read())
        image = Image.frombytes(
            heif_file.mode,
            heif_file.size,
            heif_file.data,
            "raw",
            heif_file.mode,
            heif_file.stride
        )

        io = BytesIO()
        image.save(io, format=target_format)
        io.seek(0)

        # saving
        upload_file = UploadFile(io)
        upload_file.filename = file.filename.lower().replace(f'.{source_extension}', f'.{target_extension}')

        return upload_file, target_content_type

When I run it locally (ubuntu 22 LTS), I get no errors. But when I deploy it on a container based on the python:3.8-alpine image, I get this error:

File '/home/python/app/src/api/api_v1/endpoints/dossier.py', line 195, in dossier_piece_post file, content_type = FileService.ios_image_converter(file) File '/home/python/app/src/api/api_v1/services/FileService.py', line 57, in ios_image_converter heif_file = pyheif.read(file.file.read()) File '/usr/local/lib/python3.8/site-packages/pyheif/reader.py', line 103, in read return heif_file.load() File '/usr/local/lib/python3.8/site-packages/pyheif/reader.py', line 47, in load self.data, self.stride = _read_heif_image(self._heif_handle, self) File '/usr/local/lib/python3.8/site-packages/pyheif/reader.py', line 402, in _read_heif_image p_options.ignore_transformations = int(not heif_file.apply_transformations) ffi.error: struct heif_decoding_options: wrong total size (cdef says 48, but C compiler says 72). fix it or use '...;' as the last field in the cdef for struct heif_decoding_options to make it flexible

installed libs on my alpine pods:

libheif-1.16.2-r0
libheif-dev-1.16.2-r0

Any help please !

Cyberfit commented 11 months ago

I'm having the same issue running this on macOS py3.11.5

struct heif_decoding_options: wrong total size (cdef says 48, but C compiler says 72). fix it or use "...;" as the last field in the cdef for struct heif_decoding_options to make it flexible

peterlauri commented 11 months ago

I'm having same problem as CyberFit.

➜   brew info libffi
==> libffi: stable 3.4.4 (bottled), HEAD [keg-only]
Portable Foreign Function Interface library
https://sourceware.org/libffi/
/opt/homebrew/Cellar/libffi/3.4.4 (17 files, 724.8KB)
  Poured from bottle using the formulae.brew.sh API on 2023-08-15 at 08:48:22
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/lib/libffi.rb
License: MIT
==> Options
--HEAD
    Install HEAD version
==> Caveats
libffi is keg-only, which means it was not symlinked into /opt/homebrew,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

For compilers to find libffi you may need to set:
  export LDFLAGS="-L/opt/homebrew/opt/libffi/lib"
  export CPPFLAGS="-I/opt/homebrew/opt/libffi/include"

For pkg-config to find libffi you may need to set:
  export PKG_CONFIG_PATH="/opt/homebrew/opt/libffi/lib/pkgconfig"
==> Analytics
install: 27,321 (30 days), 71,475 (90 days), 188,609 (365 days)
install-on-request: 6,790 (30 days), 17,520 (90 days), 43,862 (365 days)
build-error: 1 (30 days)
==> libheif: stable 1.16.2 (bottled)
ISO/IEC 23008-12:2017 HEIF file format decoder and encoder
https://www.libde265.org/
/opt/homebrew/Cellar/libheif/1.16.2 (27 files, 3.2MB) *
  Poured from bottle using the formulae.brew.sh API on 2023-08-15 at 08:48:29
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/lib/libheif.rb
License: LGPL-3.0-only
==> Dependencies
Build: cmake ✔, pkg-config ✔
Required: aom ✔, jpeg-turbo ✔, libde265 ✔, libpng ✔, shared-mime-info ✔, x265 ✔
==> Analytics
install: 26,975 (30 days), 75,270 (90 days), 252,115 (365 days)
install-on-request: 13,098 (30 days), 37,676 (90 days), 136,666 (365 days)
build-error: 0 (30 days)
➜   python --version
Python 3.11.5
michaelrhanson commented 10 months ago

Same error on slightly older Python. The file in question is a recent HEIC from an iPhone running iOS 16.6.1.

ffi.error: struct heif_decoding_options: wrong total size (cdef says 48, but C compiler says 72). fix it or use "...;" as the last field in the cdef for struct heif_decoding_options to make it flexible
$ brew info libffi
==> libffi: stable 3.4.4 (bottled), HEAD [keg-only]
Portable Foreign Function Interface library
https://sourceware.org/libffi/
/opt/homebrew/Cellar/libffi/3.4.4 (17 files, 724.8KB)
  Poured from bottle using the formulae.brew.sh API on 2023-04-24 at 09:35:09
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/lib/libffi.rb
License: MIT
==> Options
--HEAD
    Install HEAD version
==> Caveats
libffi is keg-only, which means it was not symlinked into /opt/homebrew,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

For compilers to find libffi you may need to set:
  export LDFLAGS="-L/opt/homebrew/opt/libffi/lib"
  export CPPFLAGS="-I/opt/homebrew/opt/libffi/include"

For pkg-config to find libffi you may need to set:
  export PKG_CONFIG_PATH="/opt/homebrew/opt/libffi/lib/pkgconfig"
$ brew info libheif
==> libheif: stable 1.16.2 (bottled)
ISO/IEC 23008-12:2017 HEIF file format decoder and encoder
https://www.libde265.org/
/opt/homebrew/Cellar/libheif/1.16.2 (27 files, 3.2MB) *
  Poured from bottle using the formulae.brew.sh API on 2023-10-10 at 08:04:32
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/lib/libheif.rb
License: LGPL-3.0-only
==> Dependencies
Build: cmake ✘, pkg-config ✔
Required: aom ✔, jpeg-turbo ✔, libde265 ✔, libpng ✔, shared-mime-info ✔, x265 ✔
$ python --version
Python 3.10.12
michaelrhanson commented 10 months ago

This is probably a duplicate of #84 -- installing from master as directed in that issue resolves the problem.

davidcz95 commented 9 months ago

This is probably a duplicate of #84 -- installing from master as directed in that issue resolves the problem.

when installing from master on M1 old error has returned fatal error: 'libheif/heif.h' file not foun i can install it through pip install pyheif but then Struct heif_decoding_options: wrong total size occurs

derSoerrn95 commented 9 months ago

I have the same problem as @davidcz95

malekinho8 commented 8 months ago

For anyone still on this thread, I found at least a temporary workaround using the pillow_heif module.

from pillow_heif import register_heif_opener
from PIL import Image

register_heif_opener()

def load_heic_image(heic_file_path):
    # obtain the image data
    image = Image.open(heic_file_path)
    return image

# Replace with your HEIC file path
heic_file_path = 'foo.heic'
image = load_heic_image(heic_file_path)

Hope this helps.

lufte commented 7 months ago

Another workaround (installing from this repo didn't work for me because it would try to build against an incompatible version of libheif) is to downgrade to Python 3.11. I had upgraded to Python 3.12 but there is no pyheif wheel for it.

AbidiHamza84 commented 6 months ago

I finally found another way to do it !

` from io import BytesIO from typing import Final

from PIL import Image from fastapi import UploadFile, File from pillow_heif import register_heif_opener from starlette.datastructures import Headers

from src.utils.mimes_type_enum import MimeTypeEnum

SOURCE_EXTENSION: Final[str] = 'heic' SOURCE_CONTENT_TYPE: Final[MimeTypeEnum] = MimeTypeEnum.HEIC TARGET_EXTENSION: Final[str] = 'png' TARGET_FORMAT: Final[str] = 'PNG' TARGET_CONTENT_TYPE: Final[MimeTypeEnum] = MimeTypeEnum.PNG

async def convert_to_png(file: UploadFile) -> UploadFile:

source type checking

if file.content_type != SOURCE_CONTENT_TYPE.value:
    raise Exception(f"expected file type {SOURCE_CONTENT_TYPE.value}, got {file.content_type}")

register_heif_opener()

with Image.open(file.file) as image:
    io = BytesIO()
    image.save(io, format=TARGET_FORMAT)
    io.seek(0)

# saving
upload_file = UploadFile(
    io,
    filename=file.filename.lower().replace(f'.{SOURCE_EXTENSION}', f'.{TARGET_EXTENSION}'),
    headers=Headers({'Content-Type': TARGET_CONTENT_TYPE.value})
)

return upload_file

`

I use the register_heif_opener() function to registers a Pillow plugin for HEIF format. To get it, you will need to install the pillow-heif lib pip install pillow-heif.

Thank you @malekinho8 for the idea ;)

mzahidriaz commented 3 months ago

I finally found another way to do it !

` from io import BytesIO from typing import Final

from PIL import Image from fastapi import UploadFile, File from pillow_heif import register_heif_opener from starlette.datastructures import Headers

from src.utils.mimes_type_enum import MimeTypeEnum

SOURCE_EXTENSION: Final[str] = 'heic' SOURCE_CONTENT_TYPE: Final[MimeTypeEnum] = MimeTypeEnum.HEIC TARGET_EXTENSION: Final[str] = 'png' TARGET_FORMAT: Final[str] = 'PNG' TARGET_CONTENT_TYPE: Final[MimeTypeEnum] = MimeTypeEnum.PNG

async def convert_to_png(file: UploadFile) -> UploadFile: # source type checking if file.content_type != SOURCE_CONTENT_TYPE.value: raise Exception(f"expected file type {SOURCE_CONTENT_TYPE.value}, got {file.content_type}")

register_heif_opener()

with Image.open(file.file) as image:
    io = BytesIO()
    image.save(io, format=TARGET_FORMAT)
    io.seek(0)

# saving
upload_file = UploadFile(
    io,
    filename=file.filename.lower().replace(f'.{SOURCE_EXTENSION}', f'.{TARGET_EXTENSION}'),
    headers=Headers({'Content-Type': TARGET_CONTENT_TYPE.value})
)

return upload_file

`

I use the register_heif_opener() function to registers a Pillow plugin for HEIF format. To get it, you will need to install the pillow-heif lib pip install pillow-heif.

Thank you @malekinho8 for the idea ;)

This worked