cgohlke / psdtags

Read and write layered TIFF ImageSourceData and ImageResources tags
https://pypi.org/project/psdtags
BSD 3-Clause "New" or "Revised" License
21 stars 3 forks source link

ValueError: operands could not be broadcast together with shapes #9

Closed vincenzocivale closed 11 months ago

vincenzocivale commented 11 months ago

I'm trying to create two layer tiff from two png with the script below:

import numpy
import imagecodecs
import tifffile

from psdtags import (
    __version__,
    PsdBlendMode,
    PsdChannel,
    PsdChannelId,
    PsdClippingType,
    PsdColorSpaceType,
    PsdCompressionType,
    PsdEmpty,
    PsdFilterMask,
    PsdFormat,
    PsdKey,
    PsdLayer,
    PsdLayerFlag,
    PsdLayerMask,
    PsdLayers,
    PsdRectangle,
    PsdString,
    PsdUserMask,
    TiffImageSourceData,
    overlay,
)

import numpy as np

# read individual layer images from files
background: numpy.ndarray = imagecodecs.imread('background.png')
product: numpy.ndarray = imagecodecs.imread(r'C:\Users\cical\Desktop\Università\Progetto per Giuseppe\ComputerVision\pexels-arianna-jadé-4754648_mask.png')

# positions of layers in canvas
background_offset = (0, 0)
product_offset = (79, 83)

# create the ImageSourceData structure for the layered TIFF
image_source_data = TiffImageSourceData(
    name='Layered TIFF',
    psdformat=PsdFormat.LE32BIT,
    layers=PsdLayers(
        key=PsdKey.LAYER,
        has_transparency=False,
        layers=[
            PsdLayer(
                name='Background',
                rectangle=PsdRectangle(
                    background_offset[0],
                    background_offset[1],
                    background_offset[0] + background.shape[0],
                    background_offset[1] + background.shape[1],
                ),
                channels=[
                    PsdChannel(
                        channelid=PsdChannelId.CHANNEL0,
                        compression=PsdCompressionType.ZIP_PREDICTED,
                        data=background[..., 0],
                    ),
                    PsdChannel(
                        channelid=PsdChannelId.CHANNEL1,
                        compression=PsdCompressionType.ZIP_PREDICTED,
                        data=background[..., 1],
                    ),
                    PsdChannel(
                        channelid=PsdChannelId.CHANNEL2,
                        compression=PsdCompressionType.ZIP_PREDICTED,
                        data=background[..., 2],
                    ),
                ],
                mask=PsdLayerMask(),
                opacity=255,
                blendmode=PsdBlendMode.NORMAL,
                clipping=PsdClippingType.BASE,
                flags=PsdLayerFlag.PHOTOSHOP5 | PsdLayerFlag.TRANSPARENCY_PROTECTED,
                info=[
                    PsdString(PsdKey.UNICODE_LAYER_NAME, 'Background'),
                ],
            ),
            PsdLayer(
                name='Product',
                rectangle=PsdRectangle(
                    product_offset[0],
                    product_offset[1],
                    product_offset[0] + product.shape[0],
                    product_offset[1] + product.shape[1],
                ),
                channels=[
                    PsdChannel(
                        channelid=PsdChannelId.TRANSPARENCY_MASK,
                        compression=PsdCompressionType.ZIP_PREDICTED,
                        data=product[..., 3],
                    ),
                    PsdChannel(
                        channelid=PsdChannelId.CHANNEL0,
                        compression=PsdCompressionType.ZIP_PREDICTED,
                        data=product[..., 0],
                    ),
                    PsdChannel(
                        channelid=PsdChannelId.CHANNEL1,
                        compression=PsdCompressionType.ZIP_PREDICTED,
                        data=product[..., 1],
                    ),
                    PsdChannel(
                        channelid=PsdChannelId.CHANNEL2,
                        compression=PsdCompressionType.ZIP_PREDICTED,
                        data=product[..., 2],
                    ),
                ],
                mask=PsdLayerMask(),
                opacity=255,
                blendmode=PsdBlendMode.NORMAL,
                clipping=PsdClippingType.BASE,
                flags=PsdLayerFlag.PHOTOSHOP5,
                info=[
                    PsdString(PsdKey.UNICODE_LAYER_NAME, 'Product'),
                ],
            ),
        ],
    ),
    usermask=PsdUserMask(
        colorspace=PsdColorSpaceType.RGB,
        components=(65535, 0, 0, 0),
        opacity=50,
    ),
    info=[
        PsdEmpty(PsdKey.PATTERNS),
        PsdFilterMask(
            colorspace=PsdColorSpaceType.RGB,
            components=(65535, 0, 0, 0),
            opacity=50,
        ),
    ],
)

# create a composite of the layers
composite = overlay(
    (background, background_offset),
    (product, product_offset),
    shape=background.shape
)
# write a layered TIFF file
tifffile.imwrite(
    'layered.tif',
    # write composite as main TIFF image, accessible to regular TIFF readers
    composite,
    photometric='rgb',
    compression='adobe_deflate',
    # 72 dpi resolution
    resolution=((720000, 10000), (720000, 10000)),
    resolutionunit='inch',
    # do not write tifffile specific metadata
    metadata=None,
    # write layers and sRGB profile as extra tags
    extratags=[
        # ImageSourceData tag
        image_source_data.tifftag(),
        # InterColorProfile tag
        (34675, 7, None, imagecodecs.cms_profile('srgb'), True),
    ],
)

# read the ImageSourceData structure from the TIFF file
isd = TiffImageSourceData.fromtiff('layered.tif')
print(isd)
print(f'psdtags {__version__}')

# plot the layer and composite images in the TIFF file
for layer in isd.layers:
    tifffile.imshow(layer.asarray(), title=layer.name)
tifffile.imshow(tifffile.imread('layered.tif'), title='Composite', show=True)

But i recive error:

Traceback (most recent call last):
  File "C:\Users\cical\Desktop\Università\Progetto per Giuseppe\ComputerVision\prova.py", line 142, in <module>
    composite = overlay(
                ^^^^^^^^
  File "C:\Users\cical\anaconda3\Lib\site-packages\psdtags\psdtags.py", line 3775, in overlay
    over(composite, layer[0] / vmax, layer[1])
  File "C:\Users\cical\anaconda3\Lib\site-packages\psdtags\psdtags.py", line 3767, in over
    x = b[..., 3:] * (1.0 - a[..., 3:])
        ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
ValueError: operands could not be broadcast together with shapes (2738,1825,3,1) (2738,1825,0) 

Please, someone can help me? I'm a newbie

cgohlke commented 11 months ago

composite = overlay( (background, background_offset), (product, product_offset), shape=background.shape )

background.shape is not a valid canvas shape. Also make sure that all layers passed to overlay are 2D RGBA images.

Anyway, it is not necessary to save an overlay image to TIFF. Any image of compatible shape and dtype should do.