question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Correct way to write a multi-layered tiff file for reading in Photoshop?

See original GitHub issue

Hello again

I’ve been trying to use imageio to write a multi-layered TIFF file that can be read by Photoshop. I prepared a variable of multiple numpy arrays (the images read in by imageio).

If I use mimwrite I seem to only get one layer in Photoshop. It is RGB and at the correct bit depth. I’m using tifffile as the plugin driver.

By LAYERS, I mean individual, editable layers that each contain their own independent RGB data in Photoshop. If layered files are written out of Photoshop as TIFF without flattening, they can be read back in just fine, so not sure why this is not working.

When searching for an answer, most people seem to refer to color channels as layers (R, G, B, Alpha1, Alpha2) when working with images in Python. They refer to “Multipage” TIFF, so maybe that’s the terminology. I didn’t see anything in the imageio docs about writing Multipage, only a patch note saying Multipage was supported when reading TIFF files.

The data seems like it’s in the file because I merged 3 files that were 1.1 MB each and the resulting TIFF is 3.2MB, but Photoshop only seems to recognize the first file layer of RGB data that was read in. There are only 3 channels in the file (R,G,B).

Not sure if I’m missing something, if I have to use some kind of loop to create the file and then add each opened image as a layer, or if there’s some extra data that needs to be added to the file for Photoshop to recognize them properly.

Here’s the test code (applicable part):

image_data = []

for idx, f in enumerate(filepaths):
    image = imageio.imread(f)
    image_data.append(image)
    
image_array = np.array(image_data)
imageio.mimwrite(outtif, image_array, format="tif")

# I tried this also with same result, since it seems to be a numpy array when opened
for idx, f in enumerate(filepaths):
    image = imageio.imread(f)
    image_data.append(image)

imageio.mimwrite(outtif, image_data, format="tif")

Printing the shape of image_array produces:

(3, 300, 300, 3)

Here’s the expected results in Photoshop: proper_layers

Actual result: no_layers

Would appreciate a point in the right direction.

Thanks

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:30 (13 by maintainers)

github_iconTop GitHub Comments

2reactions
KeygenLLCcommented, Dec 19, 2021

@FirefoxMetzger

Finding files in the bowels of my archive was proving to be a pain, so I just made something new.

I made a simple logo for imageIO in Illustrator, then brought it into Photoshop, tweaked and made it 32-bit.

Included in the Zip

All files were exported using ProEXR. I made 5 EXR versions and included the masters. All are sRGB color space. I can do rec709 or other color space versions if you need.

  1. Uncompressed EXR
  2. RLE
  3. Piz
  4. Zip
  5. Zip16
  6. PSD
  7. TIFF
  8. 24-bit PNG (8-bit per channel)

Notes

The compressed EXRs use lossless compression. The uncompressed layered EXR is almost 400MB. The others are below 20 and 10. Just be aware wherever you uncompress it, it’s about 500MB of files, but only 21MB zipped.

The included TIFF is just in case you or @cgohlke try to dissect it at some point. I also included the After Effects file just so you have it if you need it in the future.

Layer Setup:

Some layers in the PSD have editable layer masks, while the rest have burnt in opacity. The background is a solid color as a locked background layer. I did this to test the exporter, but also so if you want to investigate the differences in layers with masks vs opacity. ProEXR exported them all the same with no problems and Photoshop saved all the data in the TIFF.

One layer has a generic name “Layer 1”. I did this to see if it mattered since it was a default and had a space in the name.

I didn’t use any overlay modes (multiply, add, etc), but can make another test with them if needed.

Lastly, the background is not pure black and the “whites” are not pure white. Colors are accurate. If you want me to push things above white and below black to test them, let me know.

Interest thing with ProEXR:

It actually saves all the layer data and keeps the opacity of the layer as an attribute, so when I import into After Effects, the opacity of the layer is adjustable. I thought it would bake in the master layer opacity, but glad it doesn’t. If you haven’t used Photoshop, besides the opacity of pixels in a layer, each layer has an overall opacity control from 0-100%. This is the data ProEXR is also keeping intact.

It’s also saving text data in the file, which shows up as a hidden layer in the AE comp with notes about all the layers.

Here is the text data:

ProEXR File Description

=Attributes=
PSlayers (string): "Background[visible:true, mode:Normal]{r:Background.R, g:Background.G, b:Background.B}, Reflect1[visible:true, mode:Normal, opaci..."
capDate (string): "2021:12:18 18:22:22"
channels (chlist)
chromaticities (chromaticities): r(0.648438, 0.330867) g(0.321172, 0.597870) b(0.155902, 0.066052) w(0.345703, 0.358539)
chromaticitiesName (string): "sRGB IEC61966-2.1"
compression (compression): None
dataWindow (box2i): [0, 0, 1919, 1079]
displayWindow (box2i): [0, 0, 1919, 1079]
iccProfile (iccProfile)
lineOrder (lineOrder): Increasing Y
pixelAspectRatio (float): 1.000000
screenWindowCenter (v2f): [0.000000, 0.000000]
screenWindowWidth (float): 1.000000
type (string): "scanlineimage"
utcOffset (float): 18000.000000
writer (string): "ProEXR for Photoshop"
xDensity (float): 72.000000

=Channels=
B (float)
Background.B (float)
Background.G (float)
Background.R (float)
G (float)
I.A (float)
I.B (float)
I.G (float)
I.R (float)
IShadow.A (float)
IShadow.B (float)
IShadow.G (float)
IShadow.R (float)
Layer 1.A (float)
Layer 1.B (float)
Layer 1.G (float)
Layer 1.R (float)
O.A (float)
O.B (float)
O.G (float)
O.R (float)
ORight.A (float)
ORight.B (float)
ORight.G (float)
ORight.R (float)
R (float)
Reflect1.A (float)
Reflect1.B (float)
Reflect1.G (float)
Reflect1.R (float)
Reflect2.A (float)
Reflect2.B (float)
Reflect2.G (float)
Reflect2.R (float)
image.A (float)
image.B (float)
image.G (float)
image.R (float)

Files

A PNG preview from Photoshop, a screenshot of the Photoshop layers, followed by a screenshot of compositions and layers in After Effects. If you’re curious, the font is Source Serif Pro from Google Fonts. Didn’t want you to run into licensing issues if I used a font I paid for (even though it should technically be okay).

imageIO_logo_construct_009_32bit

imagio_logo_layers imageIO_logo_AE

imageIO_Logo_EXR.zip

1reaction
cgohlkecommented, Jan 15, 2022

Is it a public project?

I published what I got so far at PyPI and GitHub.

Install with python -m pip install psdtags tifffile imagecodecs matplotlib

To view the layer and mask information in a layered TIFF file from a command line:

> python -m psdtags imageIO_logo_construct_009_32bit.tif
<TiffImageSourceData 'imageIO_logo_construct_009_32bit.tif'>
  <PsdFormat 8BIM>
  <PsdLayers Lr32[9]>
    shape: (1080, 1920)
    dtype: float32
    has_transparency: False
    <PsdLayer 'Background'>
      rect: (0, 0, 1080, 1920)
      opacity: 255
      blendmode: NORMAL
      clipping: BASE
      flags: PsdLayerFlags.PHOTOSHOP5|TRANSPARENCY_PROTECTED
      channels: 3
      <PsdChannel CHANNEL0 ZIP_PREDICTED>
      <PsdChannel CHANNEL1 ZIP_PREDICTED>
      <PsdChannel CHANNEL2 ZIP_PREDICTED>
      <PsdLayerMask None>
    <PsdLayer 'Reflect1'>
      rect: (587, 483, 911, 1433)
      opacity: 8
      blendmode: NORMAL
      clipping: BASE
      flags: PsdLayerFlags.PHOTOSHOP5
      channels: 5
      <PsdChannel TRANSPARENCY_MASK ZIP_PREDICTED>
      <PsdChannel CHANNEL0 ZIP_PREDICTED>
      <PsdChannel CHANNEL1 ZIP_PREDICTED>
      <PsdChannel CHANNEL2 ZIP_PREDICTED>
      <PsdChannel USER_LAYER_MASK ZIP_PREDICTED>
      <PsdLayerMask (-10, 0, 802, 1920)>
        color: 0
    <PsdLayer 'Reflect2'>
      rect: (587, 490, 802, 1427)
      opacity: 13
      blendmode: NORMAL
      clipping: BASE
      flags: PsdLayerFlags.PHOTOSHOP5
      channels: 5
      <PsdChannel TRANSPARENCY_MASK ZIP_PREDICTED>
      <PsdChannel CHANNEL0 ZIP_PREDICTED>
      <PsdChannel CHANNEL1 ZIP_PREDICTED>
      <PsdChannel CHANNEL2 ZIP_PREDICTED>
      <PsdChannel USER_LAYER_MASK ZIP_PREDICTED>
      <PsdLayerMask (616, 0, 1080, 1920)>
        color: 255
    <PsdLayer 'image'>
      rect: (443, 496, 662, 1184)
      opacity: 255
      blendmode: NORMAL
      clipping: BASE
      flags: PsdLayerFlags.PHOTOSHOP5
      channels: 4
      <PsdChannel TRANSPARENCY_MASK ZIP_PREDICTED>
      <PsdChannel CHANNEL0 ZIP_PREDICTED>
      <PsdChannel CHANNEL1 ZIP_PREDICTED>
      <PsdChannel CHANNEL2 ZIP_PREDICTED>
      <PsdLayerMask None>
    <PsdLayer 'Layer 1'>
      rect: (372, 513, 411, 555)
      opacity: 255
      blendmode: NORMAL
      clipping: BASE
      flags: PsdLayerFlags.PHOTOSHOP5
      channels: 4
      <PsdChannel TRANSPARENCY_MASK ZIP_PREDICTED>
      <PsdChannel CHANNEL0 ZIP_PREDICTED>
      <PsdChannel CHANNEL1 ZIP_PREDICTED>
      <PsdChannel CHANNEL2 ZIP_PREDICTED>
      <PsdLayerMask None>
    <PsdLayer 'ORight'>
      rect: (367, 1276, 589, 1423)
      opacity: 255
      blendmode: NORMAL
      clipping: BASE
      flags: PsdLayerFlags.PHOTOSHOP5
      channels: 5
      <PsdChannel TRANSPARENCY_MASK ZIP_PREDICTED>
      <PsdChannel CHANNEL0 ZIP_PREDICTED>
      <PsdChannel CHANNEL1 ZIP_PREDICTED>
      <PsdChannel CHANNEL2 ZIP_PREDICTED>
      <PsdChannel USER_LAYER_MASK ZIP_PREDICTED>
      <PsdLayerMask (212, 1088, 519, 1323)>
        color: 255
    <PsdLayer 'I'>
      rect: (282, 1190, 590, 1321)
      opacity: 255
      blendmode: NORMAL
      clipping: BASE
      flags: PsdLayerFlags.PHOTOSHOP5
      channels: 4
      <PsdChannel TRANSPARENCY_MASK ZIP_PREDICTED>
      <PsdChannel CHANNEL0 ZIP_PREDICTED>
      <PsdChannel CHANNEL1 ZIP_PREDICTED>
      <PsdChannel CHANNEL2 ZIP_PREDICTED>
      <PsdLayerMask None>
    <PsdLayer 'IShadow'>
      rect: (468, 1232, 584, 1314)
      opacity: 204
      blendmode: NORMAL
      clipping: BASE
      flags: PsdLayerFlags.PHOTOSHOP5
      channels: 4
      <PsdChannel TRANSPARENCY_MASK ZIP_PREDICTED>
      <PsdChannel CHANNEL0 ZIP_PREDICTED>
      <PsdChannel CHANNEL1 ZIP_PREDICTED>
      <PsdChannel CHANNEL2 ZIP_PREDICTED>
      <PsdLayerMask None>
    <PsdLayer 'O'>
      rect: (370, 1178, 567, 1285)
      opacity: 255
      blendmode: NORMAL
      clipping: BASE
      flags: PsdLayerFlags.PHOTOSHOP5
      channels: 5
      <PsdChannel TRANSPARENCY_MASK ZIP_PREDICTED>
      <PsdChannel CHANNEL0 ZIP_PREDICTED>
      <PsdChannel CHANNEL1 ZIP_PREDICTED>
      <PsdChannel CHANNEL2 ZIP_PREDICTED>
      <PsdChannel USER_LAYER_MASK ZIP_PREDICTED>
      <PsdLayerMask (157, 1144, 545, 1446)>
        color: 255
  <PsdUserMask 'RGB'>
    values: (65535, 0, 0, 0)
    opacity: 50
    flag: 128
Read more comments on GitHub >

github_iconTop Results From Across the Web

Multi-page TIFF Files- How to Open and edit each photo
You can open multi-page tiff file with Adobe Reader. Then export it in tiff format. It automatically saves a separate Tiff file for...
Read more >
File formats in Adobe Photoshop
Learn how to work with file formats (such as PSD, PSB, and PDF) in Adobe ... Lossless compression; supported by PDF and TIFF...
Read more >
Find Layered TIFF Files - Adobe Support Community - 7691366
The best that I have been able to do is use the Bridge FIND command to search all metadata excluding the keyword “Adobe...
Read more >
Script to open a multi-image TIFF into a layer stack?
He needs Photoshop (Mac version) to read these files, and place the multiple images into a stack of layers in one document. We...
Read more >
Save files in graphics formats in Photoshop - Adobe Support
Previously, Photoshop always wrote TIFF files with the channel order interleaved. Theoretically, the Planar order file can be read and written ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found