예제 #1
0
        /// <summary>
        /// Reads resolution information from a PSD file object.
        /// </summary>
        /// <param name="psd">The PSD file object from which to obtain resolution information.</param>
        /// <returns>
        /// The resolution information obtained from the PSD file, or <c>null</c> if the file contains no resolution
        /// information.
        /// </returns>
        public static ResolutionInfo FromPSD(PSDFile psd)
        {
            var resource = psd.ImageResources.FirstOrDefault(ir => ir.ID == ResolutionInfoResourceID);

            if (resource == null)
            {
                return(null);
            }

            var resInfo = new ResolutionInfo();

            using (var ms = new MemoryStream(resource.Data, writable: false))
            {
                int horizontalResolutionDPIFixedPoint = ms.ReadBigEndianInt32();
                resInfo.HorizontalResolutionDPI = horizontalResolutionDPIFixedPoint / FixedPointDivisor;
                if (resInfo.HorizontalResolutionDPI <= 0.0)
                {
                    throw new PSDFormatException($"horizontal resolution is {resInfo.HorizontalResolutionDPI}, expected more than 0.0");
                }

                resInfo.HorizontalResolutionDisplayUnit = (ResolutionDisplayUnit)ms.ReadBigEndianInt16();
                if (!Enum.IsDefined(typeof(ResolutionDisplayUnit), resInfo.HorizontalResolutionDisplayUnit))
                {
                    throw new PSDFormatException(
                              $"horizontal resolution display unit is {resInfo.HorizontalResolutionDisplayUnit}, expected one of {string.Join(", ", EnumUtils.GetUnderlyingValues<ResolutionDisplayUnit, short>())}"
                              );
                }

                resInfo.WidthDisplayUnit = (SizeDisplayUnit)ms.ReadBigEndianInt16();
                if (!Enum.IsDefined(typeof(SizeDisplayUnit), resInfo.WidthDisplayUnit))
                {
                    throw new PSDFormatException(
                              $"width display unit is {resInfo.WidthDisplayUnit}, expected one of {string.Join(", ", EnumUtils.GetUnderlyingValues<SizeDisplayUnit, short>())}"
                              );
                }

                int verticalResolutionDPIFixedPoint = ms.ReadBigEndianInt32();
                resInfo.VerticalResolutionDPI = verticalResolutionDPIFixedPoint / FixedPointDivisor;
                if (resInfo.VerticalResolutionDPI <= 0.0)
                {
                    throw new PSDFormatException($"vertical resolution is {resInfo.VerticalResolutionDPI}, expected more than 0.0");
                }

                resInfo.VerticalResolutionDisplayUnit = (ResolutionDisplayUnit)ms.ReadBigEndianInt16();
                if (!Enum.IsDefined(typeof(ResolutionDisplayUnit), resInfo.VerticalResolutionDisplayUnit))
                {
                    throw new PSDFormatException(
                              $"vertical resolution display unit is {resInfo.VerticalResolutionDisplayUnit}, expected one of {string.Join(", ", EnumUtils.GetUnderlyingValues<ResolutionDisplayUnit, short>())}"
                              );
                }

                resInfo.HeightDisplayUnit = (SizeDisplayUnit)ms.ReadBigEndianInt16();
                if (!Enum.IsDefined(typeof(SizeDisplayUnit), resInfo.HeightDisplayUnit))
                {
                    throw new PSDFormatException(
                              $"height display unit is {resInfo.HeightDisplayUnit}, expected one of {string.Join(", ", EnumUtils.GetUnderlyingValues<SizeDisplayUnit, short>())}"
                              );
                }
            }

            return(resInfo);
        }
예제 #2
0
            /// <summary>
            /// Reads the PSD header from a stream and populates a <see cref="PSDFile"/> with the information.
            /// </summary>
            /// <param name="psd">The PSD file object to populate.</param>
            /// <param name="stream">The stream from which to read the PSD header.</param>
            public static void ReadHeader(PSDFile psd, Stream stream)
            {
                string magic = stream.ReadUsAsciiString(4);

                if (!string.Equals(magic, Magic, StringComparison.Ordinal))
                {
                    throw new PSDFormatException($"unexpected magic value (is \"{magic}\", expected \"{Magic}\")");
                }

                short version = stream.ReadBigEndianInt16();

                if (version < 1 || version > 2)
                {
                    throw new PSDFormatException($"version is {version}, expected 1 or 2");
                }
                psd.Version = version;

                byte[] reserved = stream.ReadBytes(6);
                if (reserved.Any(b => b != 0x00))
                {
                    throw new PSDFormatException("nonzero byte in reserved 6-byte value");
                }

                short numberOfChannels = stream.ReadBigEndianInt16();

                if (numberOfChannels < MinChannels || numberOfChannels > MaxChannels)
                {
                    throw new PSDFormatException(
                              $"number of channels is is {numberOfChannels}, expected at least {MinChannels} and at most {MaxChannels}");
                }
                psd.NumberOfChannels = numberOfChannels;

                int height = stream.ReadBigEndianInt32();

                if (height < 1)
                {
                    throw new PSDFormatException($"height is {height}, expected at least 1");
                }
                if (version == 1 && height > Version1MaxDimension)
                {
                    throw new PSDFormatException(
                              $"height is {height} and this is a version 1 document, expected at most {Version1MaxDimension}");
                }
                if (version == 2 && height > Version2MaxDimension)
                {
                    throw new PSDFormatException(
                              $"height is {height} and this is a version 2 document, expected at most {Version2MaxDimension}");
                }
                psd.Height = height;

                int width = stream.ReadBigEndianInt32();

                if (width < 1)
                {
                    throw new PSDFormatException($"width is {width}, expected at least 1");
                }
                if (version == 1 && width > Version1MaxDimension)
                {
                    throw new PSDFormatException(
                              $"width is {width} and this is a version 1 document, expected at most {Version1MaxDimension}");
                }
                if (version == 2 && width > Version2MaxDimension)
                {
                    throw new PSDFormatException(
                              $"width is {width} and this is a version 2 document, expected at most {Version2MaxDimension}");
                }
                psd.Width = width;

                short depth = stream.ReadBigEndianInt16();

                if (depth != 1 && depth != 8 && depth != 16 && depth != 32)
                {
                    throw new PSDFormatException($"depth is {depth}, expected 1 or 8 or 16 or 32");
                }
                psd.Depth = depth;

                short colorMode = stream.ReadBigEndianInt16();

                if (!Enum.IsDefined(typeof(ColorMode), colorMode))
                {
                    throw new PSDFormatException(
                              $"color mode is {colorMode}, expected one of {string.Join(", ", EnumUtils.GetUnderlyingValues<ColorMode, short>())}");
                }
                psd.ColorMode = (ColorMode)colorMode;
            }
예제 #3
0
            /// <summary>
            /// Reads metadata about a PSD file's precomposed image data and populates a <see cref="PSDFile"/> with it.
            /// </summary>
            /// <param name="psd">The PSD file object to populate.</param>
            /// <param name="stream">The stream from which to read the precomposed image data metadata.</param>
            public static void CreateImageDataPlaceholder(PSDFile psd, Stream stream)
            {
                var placeholder = new PSDImageDataPlaceholder();

                // read compression method
                short compressionValue = stream.ReadBigEndianInt16();

                if (!Enum.IsDefined(typeof(CompressionType), compressionValue))
                {
                    throw new PSDFormatException($"unexpected compression type {compressionValue}, expected one of {string.Join(", ", EnumUtils.GetUnderlyingValues<CompressionType, short>())}");
                }
                placeholder.Compression = (CompressionType)compressionValue;
                placeholder.Offset      = stream.Position;

                psd.PrecomposedImageData = placeholder;
            }
예제 #4
0
            /// <summary>
            /// Reads the global mask information subsection of a PSD layer and mask information section from a stream
            /// and populates a <see cref="PSDFile"/> with the information.
            /// </summary>
            /// <param name="psd">The PSD file object to populate.</param>
            /// <param name="stream">The stream from which to read the layer information subsection.</param>
            public static void ReadGlobalMaskInformation(PSDFile psd, Stream stream)
            {
                int length = stream.ReadBigEndianInt32();

                if (length == 0)
                {
                    // no global mask info
                    psd.GlobalLayerMask = null;
                    return;
                }

                var mask = new PSDGlobalLayerMask();

                mask.OverlayColorSpace = stream.ReadBigEndianInt16();
                mask.ColorComponent1   = stream.ReadBigEndianInt16();
                mask.ColorComponent2   = stream.ReadBigEndianInt16();
                mask.ColorComponent3   = stream.ReadBigEndianInt16();
                mask.ColorComponent4   = stream.ReadBigEndianInt16();

                short opacity = stream.ReadBigEndianInt16();

                if (opacity < 0 || opacity > 100)
                {
                    throw new PSDFormatException($"global mask opacity must be at least 0 and at most 100, got {opacity}");
                }
                mask.Opacity = opacity;

                byte kind = stream.ReadByteOrThrow();

                if (!Enum.IsDefined(typeof(LayerMaskKind), kind))
                {
                    throw new PSDFormatException($"unknown layer mask kind {kind}, expected one of {string.Join(", ", EnumUtils.GetUnderlyingValues<LayerMaskKind, byte>())}");
                }
                mask.Kind = (LayerMaskKind)kind;

                int paddingByteCount = length - 13;

                stream.ReadBytes(paddingByteCount);

                psd.GlobalLayerMask = mask;
            }