skip to Main Content

I need to create a multi layer tif and when I open in photoshop in need to be as separated layers like in the picture:

photoshop with tif

I need to do it without photoshop so I though so that I can do with Wand in python:

from wand.image import Image

with Image(filename="./GPD_TEST_Product.png") as img:
    img.read(filename="./GPD_TEST_Reflection.png")
    img.read(filename="./GPD_TEST_Shadow.png")
    img.read(filename="./GPD_TEST_Background.png")  
    img.save(filename="final.tif")

but when I open it with photoshop I got:

tif without laters

but when I open it with preview on mac I can see the layers…

layers in preview

My other idea is to create a psd with layers and try to convert it to .tif with imagemagic, but still when I open it with photoshop, is merged.

here is the file which I’m working on:
https://drive.google.com/drive/folders/1ioWG2rJ32FVstUYJK8ITuhmGSUr7I_Ps?fbclid=IwAR1HtNsChsr6befuUTPHklqKREtwxCMLk39cRhbeshio_MU0fGU-P35kxlU

Any help will be appreciate.

2

Answers


  1. Chosen as BEST ANSWER

    If anyone need generating tiff with layers and thumbnail is not white background but composite image here is my solution:

    from psdtags import *
    from tifffile import imwrite
    from imagecodecs import imread
    import numpy as np
    from PIL import Image
    
    
    # backgroundImage = Image.open('GPD_TEST_Background.png')
    productImage = Image.open('GPD_TEST_Product.png')
    reflectionImage = Image.open('GPD_TEST_Reflection.png')
    shadowImage = Image.open('GPD_TEST_Shadow.png')
    
    w, h = productImage.size
    
    # create background with defined color
    backgroundImage = Image.new(mode="RGBA", size=(w,h), color=(255, 255, 255,255))
    
    background = np.array(backgroundImage)
    product = np.array(productImage)
    reflection = np.array(reflectionImage)
    shadow = np.array(shadowImage)
    
    #thumbnail
    thumbnail = Image.alpha_composite(backgroundImage, reflectionImage)
    thumbnail = Image.alpha_composite(thumbnail, shadowImage)
    thumbnail = Image.alpha_composite(thumbnail, productImage)
    thumbnail = np.array(thumbnail)
    
    image_source_data = TiffImageSourceData(
        name='Layered TIFF Test',
        psdformat=PsdFormat.LE32BIT,
        layers=PsdLayers(
            key=PsdKey.LAYER,
            has_transparency=False,
            layers=[
                PsdLayer(
                    name='Background',
                    rectangle=PsdRectangle(0, 0, *background.shape[:2]),
                    channels=[
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL0,
                            compression=PsdCompressionType.RLE,
                            data=background[..., 0],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL1,
                            compression=PsdCompressionType.RLE,
                            data=background[..., 1],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL2,
                            compression=PsdCompressionType.RLE,
                            data=background[..., 2],
                        ),
                    ],
                    mask=PsdLayerMask(),
                    opacity=255,
                    blendmode=PsdBlendMode.NORMAL,
                    blending_ranges=(),
                    clipping=PsdClippingType.BASE,
                    flags=PsdLayerFlag.PHOTOSHOP5
                    | PsdLayerFlag.TRANSPARENCY_PROTECTED,
                    info=[
                        PsdString(PsdKey.UNICODE_LAYER_NAME, 'Background'),
                    ],
                ),
                PsdLayer(
                    name='Reflection',
                    rectangle=PsdRectangle(0, 0, *reflection.shape[:2]),
                    channels=[
                        PsdChannel(
                            channelid=PsdChannelId.TRANSPARENCY_MASK,
                            compression=PsdCompressionType.RLE,
                            data=reflection[..., 3],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL0,
                            compression=PsdCompressionType.RLE,
                            data=reflection[..., 0],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL1,
                            compression=PsdCompressionType.RLE,
                            data=reflection[..., 1],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL2,
                            compression=PsdCompressionType.RLE,
                            data=reflection[..., 2],
                        ),
                    ],
                    mask=PsdLayerMask(),
                    opacity=255,
                    blendmode=PsdBlendMode.NORMAL,
                    blending_ranges=(),
                    clipping=PsdClippingType.BASE,
                    flags=PsdLayerFlag.PHOTOSHOP5,
                    info=[
                        PsdString(PsdKey.UNICODE_LAYER_NAME, 'Reflection'),
                    ],
                ),
                PsdLayer(
                    name='Shadow',
                    rectangle=PsdRectangle(0, 0, *shadow.shape[:2]),
                    channels=[
                        PsdChannel(
                            channelid=PsdChannelId.TRANSPARENCY_MASK,
                            compression=PsdCompressionType.RLE,
                            data=shadow[..., 3],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL0,
                            compression=PsdCompressionType.RLE,
                            data=shadow[..., 0],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL1,
                            compression=PsdCompressionType.RLE,
                            data=shadow[..., 1],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL2,
                            compression=PsdCompressionType.RLE,
                            data=shadow[..., 2],
                        ),
                    ],
                    mask=PsdLayerMask(),
                    opacity=255,
                    blendmode=PsdBlendMode.NORMAL,
                    blending_ranges=(),
                    clipping=PsdClippingType.BASE,
                    flags=PsdLayerFlag.PHOTOSHOP5,
                    info=[
                        PsdString(PsdKey.UNICODE_LAYER_NAME, 'Shadow'),
                    ],
                ),
                PsdLayer(
                    name='Product',
                    rectangle=PsdRectangle(0, 0, *product.shape[:2]),
                    channels=[
                        PsdChannel(
                            channelid=PsdChannelId.TRANSPARENCY_MASK,
                            compression=PsdCompressionType.RLE,
                            data=product[..., 3],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL0,
                            compression=PsdCompressionType.RLE,
                            data=product[..., 0],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL1,
                            compression=PsdCompressionType.RLE,
                            data=product[..., 1],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL2,
                            compression=PsdCompressionType.RLE,
                            data=product[..., 2],
                        ),
                    ],
                    mask=PsdLayerMask(),
                    opacity=255,
                    blendmode=PsdBlendMode.NORMAL,
                    blending_ranges=(),
                    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,
            ),
        ],
    )
    
    
    imwrite(
        'LayeredTiffTest.tif',
        thumbnail,
        photometric='rgb',
        metadata=None,
        extratags=[image_source_data.tifftag()],
    )
    
    print(TiffImageSourceData.fromtiff('LayeredTiffTest.tif'))
    

    What do you think about it?


  2. The layer and thumbnail image and metadata of layered TIFF files are stored in the ImageResources (#34377) and ImageSourceData (#37724) TIFF tags. The psdtags Python library can read and write those tags but creating the tags from scratch requires knowledge of the format. Something like this should work (I don’t have Photoshop to verify):

    from psdtags import *
    from tifffile import imwrite
    from imagecodecs import imread
    
    background = imread('GPD_TEST_Background.png')
    product = imread('GPD_TEST_Product.png')
    reflection = imread('GPD_TEST_Reflection.png')
    shadow = imread('GPD_TEST_Shadow.png')
    
    image_source_data = TiffImageSourceData(
        name='Layered TIFF Test',
        psdformat=PsdFormat.LE32BIT,
        layers=PsdLayers(
            key=PsdKey.LAYER,
            has_transparency=False,
            layers=[
                PsdLayer(
                    name='Background',
                    rectangle=PsdRectangle(0, 0, *background.shape[:2]),
                    channels=[
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL0,
                            compression=PsdCompressionType.RLE,
                            data=background[..., 0],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL1,
                            compression=PsdCompressionType.RLE,
                            data=background[..., 1],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL2,
                            compression=PsdCompressionType.RLE,
                            data=background[..., 2],
                        ),
                    ],
                    mask=PsdLayerMask(),
                    opacity=255,
                    blendmode=PsdBlendMode.NORMAL,
                    blending_ranges=(),
                    clipping=PsdClippingType.BASE,
                    flags=PsdLayerFlag.PHOTOSHOP5
                    | PsdLayerFlag.TRANSPARENCY_PROTECTED,
                    info=[
                        PsdString(PsdKey.UNICODE_LAYER_NAME, 'Background'),
                    ],
                ),
                PsdLayer(
                    name='Reflection',
                    rectangle=PsdRectangle(0, 0, *reflection.shape[:2]),
                    channels=[
                        PsdChannel(
                            channelid=PsdChannelId.TRANSPARENCY_MASK,
                            compression=PsdCompressionType.RLE,
                            data=reflection[..., 3],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL0,
                            compression=PsdCompressionType.RLE,
                            data=reflection[..., 0],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL1,
                            compression=PsdCompressionType.RLE,
                            data=reflection[..., 1],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL2,
                            compression=PsdCompressionType.RLE,
                            data=reflection[..., 2],
                        ),
                    ],
                    mask=PsdLayerMask(),
                    opacity=255,
                    blendmode=PsdBlendMode.NORMAL,
                    blending_ranges=(),
                    clipping=PsdClippingType.BASE,
                    flags=PsdLayerFlag.PHOTOSHOP5,
                    info=[
                        PsdString(PsdKey.UNICODE_LAYER_NAME, 'Reflection'),
                    ],
                ),
                PsdLayer(
                    name='Shadow',
                    rectangle=PsdRectangle(0, 0, *shadow.shape[:2]),
                    channels=[
                        PsdChannel(
                            channelid=PsdChannelId.TRANSPARENCY_MASK,
                            compression=PsdCompressionType.RLE,
                            data=shadow[..., 3],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL0,
                            compression=PsdCompressionType.RLE,
                            data=shadow[..., 0],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL1,
                            compression=PsdCompressionType.RLE,
                            data=shadow[..., 1],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL2,
                            compression=PsdCompressionType.RLE,
                            data=shadow[..., 2],
                        ),
                    ],
                    mask=PsdLayerMask(),
                    opacity=255,
                    blendmode=PsdBlendMode.NORMAL,
                    blending_ranges=(),
                    clipping=PsdClippingType.BASE,
                    flags=PsdLayerFlag.PHOTOSHOP5,
                    info=[
                        PsdString(PsdKey.UNICODE_LAYER_NAME, 'Shadow'),
                    ],
                ),
                PsdLayer(
                    name='Product',
                    rectangle=PsdRectangle(0, 0, *product.shape[:2]),
                    channels=[
                        PsdChannel(
                            channelid=PsdChannelId.TRANSPARENCY_MASK,
                            compression=PsdCompressionType.RLE,
                            data=product[..., 3],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL0,
                            compression=PsdCompressionType.RLE,
                            data=product[..., 0],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL1,
                            compression=PsdCompressionType.RLE,
                            data=product[..., 1],
                        ),
                        PsdChannel(
                            channelid=PsdChannelId.CHANNEL2,
                            compression=PsdCompressionType.RLE,
                            data=product[..., 2],
                        ),
                    ],
                    mask=PsdLayerMask(),
                    opacity=255,
                    blendmode=PsdBlendMode.NORMAL,
                    blending_ranges=(),
                    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,
            ),
        ],
    )
    
    imwrite(
        'LayeredTiffTest.tif',
        background,
        photometric='rgb',
        metadata=None,
        extratags=[image_source_data.tifftag()],
    )
    
    print(TiffImageSourceData.fromtiff('LayeredTiffTest.tif'))
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search