[Image-SIG] [PATCH] Fix ordering of color layer for PSD file format

Xavier Trochu xavier.trochu at wanadoo.fr
Fri Oct 3 10:32:28 EDT 2003


The attached patch correct an issue with some photoshop files.

The issue occur when the order of the layer in the file in not one that  
PIL understands (i.e. ARGB was wrongly read as RGBA), the patch fix  
this by keeping the order consistent when building the tile array.

This patch also add support for reading the name of the layers.

Greetings,

Xavier
-------------- next part --------------
--- PsdImagePlugin.py.ori	Fri Oct 03 14:10:04 2003
+++ PsdImagePlugin.py	Fri Oct 03 14:05:16 2003
@@ -18,7 +18,7 @@
 
 __version__ = "0.4"
 
-import string
+import string, struct
 import Image, ImageFile, ImagePalette
 
 MODES = {
@@ -38,10 +38,16 @@
 # helpers
 
 def i16(c):
-    return ord(c[1]) + (ord(c[0])<<8)
+    return struct.unpack('>h', c)[0]
 
 def i32(c):
-    return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
+    return struct.unpack('>i', c)[0]
+
+def u16(c):
+    return struct.unpack('>H', c)[0]
+
+def u32(c):
+    return struct.unpack('>I', c)[0]
 
 # --------------------------------------------------------------------.
 # read PSD images
@@ -64,21 +70,34 @@
         #
         # header
 
-        s = read(26)
-        if s[:4] != "8BPS" or i16(s[4:]) != 1:
+        (psd_signature, 
+            psd_version, 
+            psd_channels, 
+            psd_rows, 
+            psd_columns, 
+            psd_depth, 
+            psd_mode) = struct.unpack('>4sh6xhiihh', read(26))
+
+        if Image.DEBUG > 2:
+            print "psd_signature is", psd_signature
+            print "psd_version is", psd_version
+            print "psd_channels is", psd_channels
+            print "psd_rows is", psd_rows
+            print "psd_columns is", psd_columns
+            print "psd_depth is", psd_depth
+            print "psd_mode is", psd_mode
+        
+        if psd_signature != "8BPS" or psd_version != 1:
             raise SyntaxError, "not a PSD file"
 
-        psd_bits = i16(s[22:])
-        psd_channels = i16(s[12:])
-        psd_mode = i16(s[24:])
 
-        mode, channels = MODES[(psd_mode, psd_bits)]
+        mode, channels = MODES[(psd_mode, psd_depth)]
 
         if channels > psd_channels:
             raise IOError, "not enough channels"
 
         self.mode = mode
-        self.size = i32(s[18:]), i32(s[14:])
+        self.size = psd_columns, psd_rows
 
         #
         # color mode data
@@ -107,7 +126,7 @@
                 data = read(i32(read(4)))
                 if (len(data) & 1):
                     read(1) # padding
-                self.resources.append((id, name, data))
+                self.resources.append((signature, id, name, data))
 
         #
         # layer and mask information
@@ -164,8 +183,8 @@
     # read layerinfo block
     layers = []
     read = file.read
-
-    for i in range(abs(i16(read(2)))):
+    srange = i16(read(2))
+    for i in range(abs(srange)):
 
         # bounding box
         y0 = i32(read(4)); x0 = i32(read(4))
@@ -174,9 +193,10 @@
         # image info
         info = []
         mode = []
-        for i in range(i16(read(2))):
+        len = i16(read(2))
+        for i in range(len):
             type = i16(read(2))
-            if type == 65535:
+            if type == -1:
                 m = "A"
             else:
                 m = "RGB"[type]
@@ -185,6 +205,7 @@
             info.append((m, size))
 
         # figure out the image mode
+        modecopy = mode[:]
         mode.sort()
         if mode == ["R"]:
             mode = "L"
@@ -197,16 +218,20 @@
 
         # skip over blend flags and extra information
         filler = read(12)
-        name = None # FIXME
-        file.seek(i32(read(4)), 1)
+        end = u32(read(4)) + file.tell()
+        file.seek(i32(read(4)), 1) # skip over layer mask/adj data
+        file.seek(i32(read(4)), 1) # skip over blending range
+        len = ord(read(1))
+        name = read(len)
+        file.seek(end, 0) # skip to the end of the layer info
 
-        layers.append((name, mode, (x0, y0, x1, y1)))
+        layers.append((name, mode, modecopy, (x0, y0, x1, y1)))
 
     # get tiles
     i = 0
-    for name, mode, bbox in layers:
+    for name, mode, rmode, bbox in layers:
         tile = []
-        for m in mode:
+        for m in rmode:
             t = _maketile(file, m, bbox, 1)
             if t:
                 tile.extend(t)


More information about the Image-SIG mailing list