diff --git a/docs/encoding.rst b/docs/encoding.rst deleted file mode 100644 index 755bbefd..00000000 --- a/docs/encoding.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. _encoding: - -Encoding of images -================== - -Current limitations of encoder -"""""""""""""""""""""""""""""" - -* ``Libheif`` does not support editing files in place(it is not possible just to change metadata) -* ``HEIF`` format does not provide information in what quality image was encoded - - -.. _save-parameters: - -Save parameters -""""""""""""""" - -Method ``save`` in both ``HeifFile`` and ``Pillow`` supports the **same** parameters. -There is only two differences between them: - -* Pillow's ``save`` by default has ``save_all=False`` and ``HeifFile`` has ``save_all=True`` -* When saving to memory for ``HeifFile`` you do not need to specify ``format`` parameter. - -Here is description of it: :py:meth:`~pillow_heif.HeifFile.save` - -.. _saving-16bit: - -Saving 16 bit images -"""""""""""""""""""" - -All 16 bit images that was created with: - -* :py:meth:`~pillow_heif.HeifImage.convert_to` -* :py:meth:`~pillow_heif.HeifFile.add_from_pillow` -* :py:meth:`~pillow_heif.HeifFile.add_frombytes` -* or images opened in ``I`` Pillow modes when using as a Pillow plugin - -Will be saved by default in 10 bit mode. - -To ``save`` 16 bit image in 12 bit for you can convert it to 12 bit before saving or set ``options().save_to_12bit`` to ``True``. diff --git a/docs/heif-file.rst b/docs/heif-file.rst index 45d38826..add3ef2a 100644 --- a/docs/heif-file.rst +++ b/docs/heif-file.rst @@ -9,6 +9,10 @@ Opening if pillow_heif.is_supported("image.heif"): heif_file = pillow_heif.open_heif("image.heif") +``open_heif`` is preferred over ``read_heif``, it does not decode images immediatly. +All image data supports `lazy loading` and will be automatically decoded when you request it, +e.g. when access to ``data`` or ``stride`` properties occurs. + Creating from Pillow -------------------- @@ -16,6 +20,8 @@ Creating from Pillow heif_file = pillow_heif.from_pillow(Image.open("image.gif")): +You can specify ``load_one=True`` if you need to add only one frame from a multi-frame image. + Creating from bytes ------------------- @@ -39,6 +45,8 @@ Enumerating images for img in heif_file: print(img) +.. note:: ``HeifFile`` itself points to the primary image in the container. + Adding images ------------- @@ -90,10 +98,10 @@ Starting from version `0.3.1` all images are in public list, and you can swap th heif_file.images[0], heif_file.images[1] = heif_file.images[1], heif_file.images[0] -Saving images -------------- +Saving +------ -Refer to :py:meth:`~pillow_heif.HeifFile.save` to see what additional parameters is supported and to :ref:`encoding`. +Refer to :py:meth:`~pillow_heif.HeifFile.save` to see what additional parameters is supported and to :ref:`saving-images`. .. code-block:: python @@ -107,6 +115,8 @@ Accessing image data Decoded image data from ``libheif`` available throw :py:attr:`~pillow_heif.HeifImage.data` property with the help of :py:attr:`~pillow_heif.HeifImage.stride` property. +Accessing `Primary` image in a file: + .. code-block:: python print(len(heif_file.data), heif_file.stride) @@ -123,12 +133,19 @@ Or you can access each image by index: Numpy array interface --------------------- -Next code gets decoded image data as a numpy array(in the same format as ``Pillow`` does): +Next code gets decoded primary image data as a numpy array(in the same format as ``Pillow`` does): + +.. code-block:: python + + heif_file = pillow_heif.open_heif("file.heif") + np_array = np.asarray(heif_file) + +Accessing image by index(for multi-frame images): .. code-block:: python heif_file = pillow_heif.open_heif("file.heif") - np_array = np.asarray(heif_file[0]) + np_array = np.asarray(heif_file[0]) # accessing image by index. After that you can load it at any library that supports numpy arrays. diff --git a/docs/index.rst b/docs/index.rst index 22f4bdeb..3c2b6d32 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,10 +18,9 @@ Pillow-Heif documentation heif-file.rst image-modes.rst options.rst - encoding.rst + saving-images.rst thumbnails.rst reference/index.rst - v0.3-order-of-images.rst workaround-orientation.rst benchmarks.rst diff --git a/docs/pillow-plugin.rst b/docs/pillow-plugin.rst index d1b0c897..72a4e9e0 100644 --- a/docs/pillow-plugin.rst +++ b/docs/pillow-plugin.rst @@ -46,7 +46,7 @@ Image Modes Currently all images are opened in ``RGB`` or ``RGBA`` 8 bit modes. There is a restriction in ``libheif`` that we cant check before decoding if an image is ``monochrome`` or not. -See here :ref:`image-modes` for a list of supported modes for saving. +See :ref:`image-modes` for a list of supported modes for saving. Metadata ******** @@ -120,7 +120,7 @@ Also images can be saved to memory, using ``format`` parameter: See here :ref:`save-parameters` for additional information. Changing order of images -"""""""""""""""""""""""" +************************ There is no such easy way to change order as for `HeifFile` usage, but the standard Pillow way to do so looks fine. Let's create image where second image will be primary: diff --git a/docs/reference/API.rst b/docs/reference/API.rst index e8a163a0..bb99d429 100644 --- a/docs/reference/API.rst +++ b/docs/reference/API.rst @@ -11,7 +11,12 @@ Opening HEIF file .. autofunction:: read_heif .. autofunction:: from_pillow .. autofunction:: from_bytes + +Thumbnails +---------- + .. autofunction:: thumbnail +.. autofunction:: add_thumbnails Low Level API ------------- diff --git a/docs/reference/HeifImage.rst b/docs/reference/HeifImage.rst index 38cfb7a9..305457ef 100644 --- a/docs/reference/HeifImage.rst +++ b/docs/reference/HeifImage.rst @@ -50,3 +50,8 @@ HeifImage object A boolean value that specifies whether the image is the main image when the file contains more than one image. + + .. py:attribute:: thumbnails + :type: list + + List of thumbnails(:class:`HeifThumbnail`) present for this image. Can be empty. diff --git a/docs/saving-images.rst b/docs/saving-images.rst new file mode 100644 index 00000000..ad0563f6 --- /dev/null +++ b/docs/saving-images.rst @@ -0,0 +1,103 @@ +.. _saving-images: + +Saving images +============= + +Current limitations of encoder +"""""""""""""""""""""""""""""" + +* ``Libheif`` does not support editing files in place(it is not possible just to change metadata) +* ``HEIF`` format does not provide information in what quality image was encoded + + +.. _save-parameters: + +Save parameters +""""""""""""""" + +Method ``save`` in both ``HeifFile`` and ``Pillow`` supports the **same** parameters. +There is only two differences between them: + +* Pillow's ``save`` by default has ``save_all=False`` and ``HeifFile`` has ``save_all=True`` +* When saving to memory for ``HeifFile`` you do not need to specify ``format`` parameter. + +Here is description of it: :py:meth:`~pillow_heif.HeifFile.save` + +.. _saving-16bit: + +Saving 16 bit images +"""""""""""""""""""" + +All 16 bit images that was created with: + +* :py:meth:`~pillow_heif.HeifImage.convert_to` +* :py:meth:`~pillow_heif.HeifFile.add_from_pillow` +* :py:meth:`~pillow_heif.HeifFile.add_frombytes` +* or images opened in ``I`` Pillow modes when using as a Pillow plugin + +Will be saved by default in 10 bit mode. + +To ``save`` 16 bit image in 12 bit for you can convert it to 12 bit before saving or set ``options().save_to_12bit`` to ``True``. + +.. _order-of-images: + +Order Of Images +""""""""""""""" + +All information here is only for files that has multiply images and when first image in file is not a `PrimaryImage` + +There was a slightly different behaviour in 0.2.x versions and 0.3.0 - 0.4.0 versions. +Starting from version `0.5.0` ``pillow-heif`` in both ``Pillow`` and ``stand alone`` mode works the same way. + +Lets imagine that we have file with 3 images and second image in file is a primary image. + +.. code-block:: python + + im = open_heif("image.heif") + im_pil = Image.open("image.heif") + +Both ``im`` and ``im_pil`` points to the second image in file, that is a primary image. + +This asserts will pass: + +.. code-block:: python + + assert im.info["primary"] == True + assert im[0].info["primary"] == False + assert im[1].info["primary"] == True + assert im[2].info["primary"] == False + + assert im_pil.info["primary"] == True + im_pil.seek(0) + assert im_pil.info["primary"] == False + im_pil.seek(1) + assert im_pil.info["primary"] == True + im_pil.seek(2) + assert im_pil.info["primary"] == False + +And next code will produce the same behavior results(during enumerating all frames): + +.. code-block:: python + + for frame in im: + print(frame.mode, frame.size) + + for frame in ImageSequence.Iterator(im_pil): + print(frame.mode, frame.size) + +Primary image when saving image sequences +""""""""""""""""""""""""""""""""""""""""" + +First image will be `primary`, unless after first image there is no images with `info["primary"]` set to ``True``. +So, last image with `info["primary"]` == ``True`` will be the primary image. + +In most cases you do not need to bother yourself with this, as other image formats are much simpler and has no such abilities. + +When you need to change `primary` image for some reason, just set `info["primary"]` of image to ``True`` +and all images after that should not have `info["primary"]` == ``True``. + +Method ``save`` supports ``primary_index`` parameter, that accepts ``index of image`` or ``-1`` to set last image as `PrimaryImage`. + +Specifying ``primary_index`` during ``save`` has highest priority. + +That's all. diff --git a/docs/thumbnails.rst b/docs/thumbnails.rst index de343e44..32d32926 100644 --- a/docs/thumbnails.rst +++ b/docs/thumbnails.rst @@ -31,3 +31,34 @@ Or as a Pillow plugin: Function :py:func:`~pillow_heif.thumbnail` has an optional parameter ``min_box``, so you can specify minimal size of thumbnail you interested in. Images that come from iPhone usual has thumbnails with 512 box size. + +Adding thumbnails +""""""""""""""""" + +For adding thumbnails use :py:func:`~pillow_heif.add_thumbnails`. + +It accepts both ``HeifImage`` or ``PIL.Image.Image`` and also can accept ``HeifFile`` + +When input is a ``HeifFile`` it will add thumbnails to all images in that file. + +When you adding thumbnails, if image has already such thumbnails sizes they wil be skipped. + +There is two examples for adding thumbnails in `examples` folder. + +Removing thumbnails +""""""""""""""""""" + +For Pillow you can clear list with thumbnails: + +.. code-block:: python + + im.info["thumbnails"].clear() + +For ``HeifFile`` or ``HeifImage``: + +.. code-block:: python + + im.thumbnails.clear() + +Or use ``del im.info["thumbnails"][index]`` for ``Pillow`` +and ``del im.thumbnails[index]`` for ``HeifImage`` to remove only one thumbnail. diff --git a/docs/v0.3-order-of-images.rst b/docs/v0.3-order-of-images.rst deleted file mode 100644 index b37565af..00000000 --- a/docs/v0.3-order-of-images.rst +++ /dev/null @@ -1,79 +0,0 @@ -.. _order-of-images: - -Order Of Images -=============== - -All information here is only for files that has multiply images and when first image in file is not a `PrimaryImage` - -Versions <0.3.0 -*************** - -Old behaviour was that the primary image was always first, no matter in which position it was in file. -And during saving, first image was always primary. -You can take a look at these two files: - -This is the original `nokia:alpha.heic `_ - -This file was created from it with thumbnails added: -`nokia:alpha_with_thumbs.heic `_ - -As you can see, third image that is `primary` in that container switched from pos 3, to pos 1 after saving. -Not a big deal, but it can be considered as a small little bug in some cases. - -Here is the code from versions till `0.3.0`: - -.. code-block:: python - - main_image_id = heif_ctx.get_main_img_id() - top_img_ids = heif_ctx.get_top_images_ids() - top_img_list = [main_image_id] + [i for i in top_img_ids if i != main_image_id] - -Reworked image order handling -***************************** - -Reading -""""""" - -Easiest way to handle this for usage **not** as a Pillow plugin is to change :py:class:`~pillow_heif.HeifFile` -that it will point as in old versions to `primary` image, but not to place that image as first in `top_img_list`. - -So this code will be equal in both old and new versions: - -.. code-block:: python - - heif_file = open_heif("input.hec") - print(heif_file.mode, heif_file.size) - -And this will have different behaviour: - -.. code-block:: python - - heif_file = open_heif("input.hec") - print(heif_file[0].mode, heif_file[0].size) - -For Pillow plugin this will be a bit break change when you use it to work with image containers, -cause from this change if you need to find a primary image you need to iterate throw all images and find image with -``info["primary"]=True``. - -Writing -""""""" - -In `0.2.x` versions when encoder was introduced, there was no way to create a file with primary image that is not in a first place. - -From now, first image will be `primary`, unless after first image there is no images with `info["primary"]` set to ``True``. -So, last image with `info["primary"]` == ``True`` will be the primary image. - -In most cases you do not need to bother yourself with this, as other image formats are much simpler and has no such abilities -and when converting to `HEIF` it will just worked as before. - -Converting from `HEIF` to `HEIF` will work as before, no any changes for both `HeifFile` or `Pillow plugin` usage part, -it will just place primary image position as it was in original image and do it right. - -When you need to change `primary` image for some reason, just set `info["primary"]` of image to ``True`` -and all images after that should not have `info["primary"]` == ``True``. - -Method ``save`` supports ``primary_index`` parameter, that accepts index of image or ``-1`` to set last image as `PrimaryImage`. - -Specifying ``primary_index`` during ``save`` has highest priority. - -That's all. diff --git a/pillow_heif/heif.py b/pillow_heif/heif.py index 4930bfbf..a57196ee 100644 --- a/pillow_heif/heif.py +++ b/pillow_heif/heif.py @@ -808,7 +808,7 @@ def open_heif(fp, convert_hdr_to_8bit=True) -> HeifFile: def read_heif(fp, convert_hdr_to_8bit=True) -> HeifFile: """Opens the given HEIF image file and decodes all images. - .. note:: In most cases it better to call :py:meth:`~pillow_heif.open_heif`, and + .. note:: In most cases it is better to call :py:meth:`~pillow_heif.open_heif`, and let images decoded automatically only when needed. :param fp: See parameter ``fp`` in :func:`is_supported` diff --git a/pillow_heif/misc.py b/pillow_heif/misc.py index e3a72cbc..14ef36a3 100644 --- a/pillow_heif/misc.py +++ b/pillow_heif/misc.py @@ -22,8 +22,8 @@ def set_orientation(info: dict, orientation: int = 1) -> Union[int, None]: """Sets orientation in ``EXIF`` to ``1`` by default if any orientation present. Removes ``XMP`` orientation tag if it is present. - In Pillow plugin mode it called automatically for main image. - When ``pillow_heif`` used as a reader, if you wish you can call it manually. + In Pillow plugin mode it called automatically for images. + When ``pillow_heif`` used in ``standalone`` mode, if you wish you can call it manually. .. note:: If there is no orientation tag, this function will not add it and do nothing.