Example #1
0
        public void TestTooWideForVersion1()
        {
            var image  = new PSDFile();
            var header = GetValidHeader();

            header[18] = 0x00;
            header[19] = 0x00;
            header[20] = 0x75;
            header[21] = 0x31;
            using (var headerStream = new MemoryStream(header, writable: false))
            {
                Assert.Throws <PSDFormatException>(() => PSDFile.Reading.ReadHeader(image, headerStream));
            }

            var v2Image  = new PSDFile();
            var v2Header = GetValidHeader();

            v2Header[5]  = 0x02;
            v2Header[18] = 0x00;
            v2Header[19] = 0x00;
            v2Header[20] = 0x75;
            v2Header[21] = 0x31;
            using (var v2HeaderStream = new MemoryStream(v2Header, writable: false))
            {
                PSDFile.Reading.ReadHeader(v2Image, v2HeaderStream);
                Assert.Equal(2, v2Image.Version);
                Assert.Equal(4, v2Image.NumberOfChannels);
                Assert.Equal(32, v2Image.Height);
                Assert.Equal(30001, v2Image.Width);
                Assert.Equal(8, v2Image.Depth);
                Assert.Equal(ColorMode.CMYK, v2Image.ColorMode);
            }
        }
Example #2
0
        public void TestZeroChannels()
        {
            var image  = new PSDFile();
            var header = GetValidHeader();

            header[13] = 0x00;
            using (var headerStream = new MemoryStream(header, writable: false))
            {
                Assert.Throws <PSDFormatException>(() => PSDFile.Reading.ReadHeader(image, headerStream));
            }
        }
Example #3
0
        public void TestInvalidReservedValue()
        {
            var image  = new PSDFile();
            var header = GetValidHeader();

            header[11] = 0x01;
            using (var headerStream = new MemoryStream(header, writable: false))
            {
                Assert.Throws <PSDFormatException>(() => PSDFile.Reading.ReadHeader(image, headerStream));
            }
        }
Example #4
0
        public void TestWrongColorMode()
        {
            var image  = new PSDFile();
            var header = GetValidHeader();

            header[25] = 0x05;
            using (var headerStream = new MemoryStream(header, writable: false))
            {
                Assert.Throws <PSDFormatException>(() => PSDFile.Reading.ReadHeader(image, headerStream));
            }
        }
Example #5
0
        public void TestInvalidMagic()
        {
            var image  = new PSDFile();
            var header = GetValidHeader();

            header[0] = 0x46;
            header[1] = 0x55;
            header[2] = 0x43;
            header[3] = 0x4B;
            using (var headerStream = new MemoryStream(header, writable: false))
            {
                Assert.Throws <PSDFormatException>(() => PSDFile.Reading.ReadHeader(image, headerStream));
            }
        }
Example #6
0
        public void TestValidHeader()
        {
            var image = new PSDFile();

            using (var validHeaderStream = new MemoryStream(GetValidHeader(), writable: false))
            {
                PSDFile.Reading.ReadHeader(image, validHeaderStream);
                Assert.Equal(1, image.Version);
                Assert.Equal(4, image.NumberOfChannels);
                Assert.Equal(32, image.Height);
                Assert.Equal(16, image.Width);
                Assert.Equal(8, image.Depth);
                Assert.Equal(ColorMode.CMYK, image.ColorMode);
            }
        }
Example #7
0
        public void TestTooWideForVersion2()
        {
            var image  = new PSDFile();
            var header = GetValidHeader();

            header[5]  = 0x02;
            header[18] = 0x00;
            header[19] = 0x04;
            header[20] = 0x93;
            header[21] = 0xE1;
            using (var headerStream = new MemoryStream(header, writable: false))
            {
                Assert.Throws <PSDFormatException>(() => PSDFile.Reading.ReadHeader(image, headerStream));
            }
        }
Example #8
0
        private void LoadPsdFile(int index)
        {
            try
            {
                string ext         = Path.GetExtension(filesEntries[index].path).ToLower();
                string psdfilename = filesEntries[index].path;
                string psdpath     = "data/icon/items/";
                if (Path.GetDirectoryName(filesEntries[index].path).ToLower() == "script\\backgrounds")
                {
                    psdpath = "data/icon/backgrounds/";
                }
                if (ext != ".psd")
                {
                    string fname = Path.GetFileNameWithoutExtension(psdfilename);
                    psdfilename = psdpath + fname + ".psd";
                }
                psdfilename = psdfilename.ToLower();
                foreach (ArcsTahFilesEntry fentry in filesEntries)
                {
                    if (fentry.path.ToLower() == psdfilename)
                    {
                        using (GenericTAHStream tahstream = new GenericTAHStream(info, fentry))
                        {
                            PSDFile psd = new PSDFile();
                            psd.Load(tahstream.stream);
#if false
                            TDCGExplorer.TDCGExplorer.MainFormWindow.PictureBox.Image  = psd.Bitmap;
                            TDCGExplorer.TDCGExplorer.MainFormWindow.PictureBox.Width  = psd.Bitmap.Width;
                            TDCGExplorer.TDCGExplorer.MainFormWindow.PictureBox.Height = psd.Bitmap.Height;
#else
                            TDCGExplorer.TDCGExplorer.MainFormWindow.SetBitmap(psd.Bitmap);
#endif
                        }
                        return;
                    }
                }
            }
            catch (Exception)
            {
            }
            NoImageIcon();
        }
Example #9
0
        static int Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("Usage: PSD2PAM.exe FILE.psd FILE.pam");
                return(1);
            }

            // read the PSD file
            var photochop = new PSDFile();

            using (var reading = new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                photochop.Read(reading);

                var versionInfo = photochop.ImageResources.FirstOrDefault(ir => ir.ID == 0x0421);
                if (versionInfo?.Data[4] == 0)
                {
                    // does not have valid precomposed image
                    Console.WriteLine("PSD2PAM requires that a valid precomposed image is part of the file.");
                    return(1);
                }

                int width        = photochop.Width;
                int height       = photochop.Height;
                int channelCount = photochop.NumberOfChannels;
                int depth        = photochop.Depth;
                if (depth == 1)
                {
                    Console.WriteLine("PSD2PAM doesn't currently support 1-bit images.");
                    return(1);
                }

                long maxValue;
                switch (depth)
                {
                case 8:
                    maxValue = 0xFF;
                    break;

                case 16:
                    maxValue = 0xFFFF;
                    break;

                case 32:
                    maxValue = 0xFFFFFFFF;
                    break;

                default:
                    Console.WriteLine("Unsupported depth {0}.", depth);
                    return(1);
                }

                int bytesPerColorComponent = depth / 8;

                string tupleTypeString = "";
                switch (photochop.ColorMode)
                {
                case ColorMode.RGB:
                    tupleTypeString = "TUPLTYPE RGB\n";
                    break;

                case ColorMode.CMYK:
                    tupleTypeString = "TUPLTYPE CMYK\n";
                    break;

                case ColorMode.Grayscale:
                    tupleTypeString = "TUPLTYPE GRAYSCALE\n";
                    break;
                }

                string header = string.Format(
                    CultureInfo.InvariantCulture,
                    "P7\nWIDTH {0}\nHEIGHT {1}\nDEPTH {2}\nMAXVAL {3}\n{4}ENDHDR\n",
                    width,
                    height,
                    channelCount,
                    maxValue,
                    tupleTypeString
                    );

                reading.Seek(photochop.PrecomposedImageData.Offset, SeekOrigin.Begin);

                using (var tempFiles = new TemporaryFilesDeleteOnDispose(1 + channelCount))
                {
                    // get planar image
                    using (var planarImageStorage = new FileStream(tempFiles.FileNames[0],
                                                                   FileMode.Create, FileAccess.Write, FileShare.None))
                        using (var zippage = new GZipStream(planarImageStorage, CompressionLevel.Fastest))
                        {
                            switch (photochop.PrecomposedImageData.Compression)
                            {
                            case CompressionType.RawData:
                                PixelDataDecoding.DecodeRawData(reading, zippage, null);
                                break;

                            case CompressionType.PackBits:
                                int scanlineCount = height * channelCount;
                                PixelDataDecoding.DecodePackBits(reading, zippage, scanlineCount, photochop.Version == 2);
                                break;

                            case CompressionType.ZipWithoutPrediction:
                                PixelDataDecoding.DecodeZip(reading, zippage, null);
                                break;

                            case CompressionType.ZipWithPrediction:
                                PixelDataDecoding.DecodeZipPredicted(reading, zippage, null, depth, width);
                                break;
                            }
                        }

                    // split planar image into plane files
                    var buf = new byte[width * bytesPerColorComponent];
                    using (var reader = new FileStream(tempFiles.FileNames[0], FileMode.Open, FileAccess.Read,
                                                       FileShare.Read))
                        using (var unzippage = new GZipStream(reader, CompressionMode.Decompress))
                        {
                            for (int c = 0; c < channelCount; ++c)
                            {
                                using (var writer = new FileStream(tempFiles.FileNames[1 + c], FileMode.Create,
                                                                   FileAccess.Write, FileShare.None))
                                    using (var zippage = new GZipStream(writer, CompressionLevel.Fastest))
                                    {
                                        for (int y = 0; y < height; ++y)
                                        {
                                            if (y % 32 == 31)
                                            {
                                                Console.WriteLine("splitting channel {0}/{1} row {2}/{3}", c + 1, channelCount,
                                                                  y + 1, height);
                                            }

                                            int rd = unzippage.Read(buf, 0, buf.Length);
                                            if (rd < buf.Length)
                                            {
                                                throw new Exception("short read");
                                            }
                                            zippage.Write(buf, 0, buf.Length);
                                        }
                                    }
                            }
                        }

                    using (var streamDisposal = new DisposableStreamGroup())
                    {
                        // reopen the planes
                        for (int c = 0; c < channelCount; ++c)
                        {
                            var stream = new FileStream(tempFiles.FileNames[1 + c], FileMode.Open,
                                                        FileAccess.Read, FileShare.Read);
                            var unzipper = new GZipStream(stream, CompressionMode.Decompress, leaveOpen: false);
                            streamDisposal.Streams.Add(unzipper);
                        }

                        // interleave the components
                        var pixel = new byte[bytesPerColorComponent];
                        using (var writer = new FileStream(args[1], FileMode.Create, FileAccess.Write))
                            using (var zipper = new GZipStream(writer, CompressionLevel.Fastest))
                                using (var bufferer = new BufferedStream(zipper, 8 * 1024 * 1024))
                                {
                                    // write PAM header
                                    var pamHeaderBytes = header.Select(c => (byte)c).ToArray();
                                    bufferer.Write(pamHeaderBytes, 0, pamHeaderBytes.Length);

                                    // read the pixels
                                    for (int y = 0; y < height; ++y)
                                    {
                                        if (y % 32 == 31)
                                        {
                                            Console.WriteLine("copying row {0}/{1}", y + 1, height);
                                        }
                                        for (int x = 0; x < width; ++x)
                                        {
                                            for (int c = 0; c < channelCount; ++c)
                                            {
                                                int r = streamDisposal.Streams[c].Read(pixel, 0, pixel.Length);
                                                if (r != bytesPerColorComponent)
                                                {
                                                    throw new Exception("under-read");
                                                }

                                                // invert color (Photoshop -> PAM)
                                                for (int i = 0; i < pixel.Length; ++i)
                                                {
                                                    pixel[i] = (byte)(0xFF - pixel[i]);
                                                }

                                                bufferer.Write(pixel, 0, pixel.Length);
                                            }
                                        }
                                    }
                                }
                    }
                }
            }

            return(0);
        }
Example #10
0
        static void Main(string[] args)
        {
            var psd = new PSDFile();

            using (var readStream = new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                psd.Read(readStream);
            }

            Console.WriteLine("Version: {0}", psd.Version);
            Console.WriteLine("Number of channels: {0}", psd.NumberOfChannels);
            Console.WriteLine("Width: {0}", psd.Width);
            Console.WriteLine("Height: {0}", psd.Height);
            Console.WriteLine("Depth: {0}", psd.Depth);
            Console.WriteLine("Color mode: {0}", psd.ColorMode);

            Console.WriteLine("Image resources:");
            foreach (var res in psd.ImageResources)
            {
                Console.WriteLine("  Image resource ID: {0}", res.ID);
                //Console.WriteLine("    Name: {0}", res.Name);

                if (res.ID == ResolutionInfo.ResolutionInfoResourceID)
                {
                    Console.WriteLine("    Binary data:");

                    for (int rowOffset = 0; rowOffset < res.Data.Length; rowOffset += 8)
                    {
                        Console.Write("      ");
                        for (int i = 0; i < 8 && rowOffset + i < res.Data.Length; ++i)
                        {
                            Console.Write("{0:X2} ", res.Data[rowOffset + i]);
                        }
                        Console.WriteLine();
                    }

                    Console.WriteLine("    Resolution info:");
                    var resInfo = ResolutionInfo.FromPSD(psd);
                    Console.WriteLine("      Horizontal resolution: {0} dpi", resInfo.HorizontalResolutionDPI);
                    Console.WriteLine("        Display unit:        {0}", resInfo.HorizontalResolutionDisplayUnit);
                    Console.WriteLine("      Width display unit:    {0}", resInfo.WidthDisplayUnit);
                    Console.WriteLine("      Vertical resolution:   {0} dpi", resInfo.VerticalResolutionDPI);
                    Console.WriteLine("        Display unit:        {0}", resInfo.VerticalResolutionDisplayUnit);
                    Console.WriteLine("      Height display unit:   {0}", resInfo.HeightDisplayUnit);
                }
                else if (res.ID == VersionInfo.VersionInfoResourceID)
                {
                    var verInfo = VersionInfo.FromPSD(psd);
                    Console.WriteLine("    Version info:");
                    Console.WriteLine("      Version: {0}", verInfo.Version);
                    Console.WriteLine("      {0} valid precomposed data", verInfo.HasValidPrecomposedData ? "Has" : "Does not have");
                    Console.WriteLine("      Writer: {0}", verInfo.WriterName);
                    Console.WriteLine("      Reader: {0}", verInfo.ReaderName);
                    Console.WriteLine("      File version: {0}", verInfo.FileVersion);
                }
            }

            Console.WriteLine("Layers: {0}", psd.Layers.Length);
            foreach (PSDLayer layer in psd.Layers)
            {
                Console.WriteLine("    Layer: {0}", layer.Name);
                Console.WriteLine("      Channels: {0}", layer.Channels.Length);
                foreach (PSDLayerChannel chan in layer.Channels)
                {
                    Console.WriteLine("        {0} ({1} bytes {2} from 0x{3:x})", chan.ID, chan.Data.DataLength, chan.Data.Compression, chan.Data.Offset);
                }
                Console.WriteLine("      Additional layer information: {0} entries", layer.AdditionalInformation.Count);
                foreach (PSDAdditionalLayerInformation pali in layer.AdditionalInformation)
                {
                    Console.WriteLine("        Key: {0}", pali.Key);
                    Console.WriteLine("          Data length: {0}", pali.Data.Length);
                }
            }

            if (psd.GlobalLayerMask != null)
            {
                var glm = psd.GlobalLayerMask;
                Console.WriteLine("Global layer mask:");
                Console.WriteLine("  Overlay color space: {0}", glm.OverlayColorSpace);
                Console.WriteLine("  Color components: {0}, {1}, {2}, {3}", glm.ColorComponent1, glm.ColorComponent2, glm.ColorComponent3, glm.ColorComponent4);
                Console.WriteLine("  Opacity: {0}", glm.Opacity);
                Console.WriteLine("  Kind: {0}", glm.Kind);
            }
            else
            {
                Console.WriteLine("No global layer mask");
            }

            Console.WriteLine("Additional layer information: {0} entries", psd.AdditionalLayerInformation.Count);
            foreach (PSDAdditionalLayerInformation ali in psd.AdditionalLayerInformation)
            {
                Console.WriteLine("  Key: {0}", ali.Key);
                Console.WriteLine("    Data length: {0}", ali.Data.Length);
            }

            if (psd.PrecomposedImageData == null)
            {
                Console.WriteLine("No precomposed image data");
            }
            else
            {
                Console.WriteLine("Precomposed image data: {0} from 0x{1:x}", psd.PrecomposedImageData.Compression, psd.PrecomposedImageData.Offset);
            }

            if (args.Length > 1 && args[1] == "-d")
            {
                // decode
                for (int l = 0; l < psd.Layers.Length; ++l)
                {
                    PSDLayer layer = psd.Layers[l];
                    foreach (PSDLayerChannel chan in layer.Channels)
                    {
                        Console.WriteLine("extracting layer {0} channel {1} ({2})", l, chan.ID, chan.Data.Compression);
                        string name = $"{args[0]}.l{l}c{chan.ID}.bin";

                        using (var reader = new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.Read))
                            using (var writer = new FileStream(name, FileMode.Create, FileAccess.Write, FileShare.None))
                            {
                                reader.Seek(chan.Data.Offset, SeekOrigin.Begin);
                                switch (chan.Data.Compression)
                                {
                                case CompressionType.RawData:
                                    PixelDataDecoding.DecodeRawData(
                                        reader,
                                        writer,
                                        chan.Data.DataLength
                                        );
                                    break;

                                case CompressionType.PackBits:
                                    PixelDataDecoding.DecodePackBits(
                                        reader,
                                        writer,
                                        scanlineCount: layer.Bottom - layer.Top,
                                        fourByteLengths: psd.Version == 2
                                        );
                                    break;

                                case CompressionType.ZipWithoutPrediction:
                                    PixelDataDecoding.DecodeZip(
                                        reader,
                                        writer,
                                        chan.Data.DataLength
                                        );
                                    break;

                                case CompressionType.ZipWithPrediction:
                                    PixelDataDecoding.DecodeZipPredicted(
                                        reader,
                                        writer,
                                        chan.Data.DataLength,
                                        psd.Depth,
                                        psd.Width
                                        );
                                    break;
                                }
                            }
                    }
                }

                if (psd.PrecomposedImageData != null)
                {
                    string compositeName = $"{args[0]}.composite.bin";
                    using (var reader = new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.Read))
                        using (var writer = new FileStream(compositeName, FileMode.Create, FileAccess.Write, FileShare.None))
                        {
                            reader.Seek(psd.PrecomposedImageData.Offset, SeekOrigin.Begin);
                            switch (psd.PrecomposedImageData.Compression)
                            {
                            case CompressionType.RawData:
                                PixelDataDecoding.DecodeRawData(
                                    reader,
                                    writer,
                                    length: null
                                    );
                                break;

                            case CompressionType.PackBits:
                                PixelDataDecoding.DecodePackBits(
                                    reader,
                                    writer,
                                    scanlineCount: psd.Height * psd.NumberOfChannels,
                                    fourByteLengths: psd.Version == 2
                                    );
                                break;

                            case CompressionType.ZipWithoutPrediction:
                                PixelDataDecoding.DecodeZip(
                                    reader,
                                    writer,
                                    length: null
                                    );
                                break;

                            case CompressionType.ZipWithPrediction:
                                PixelDataDecoding.DecodeZipPredicted(
                                    reader,
                                    writer,
                                    length: null,
                                    depth: psd.Depth,
                                    imageWidth: psd.Width
                                    );
                                break;
                            }
                        }
                }
            }
        }