//--------------------------------------------------------------
        #region XNA Content Pipeline
        //--------------------------------------------------------------

        /// <summary>
        /// Converts an XNA <see cref="TextureContent"/> to a DigitalRune <see cref="Texture"/>.
        /// </summary>
        /// <param name="textureContent">The <see cref="TextureContent"/>.</param>
        /// <returns>The <see cref="Texture"/>.</returns>
        public static Texture ToTexture(TextureContent textureContent)
        {
            SurfaceFormat surfaceFormat;
            var           bitmapContent0 = textureContent.Faces[0][0];

            if (!bitmapContent0.TryGetFormat(out surfaceFormat))
            {
                throw new InvalidContentException("Invalid surface format.", textureContent.Identity);
            }

            var texture2DContent = textureContent as Texture2DContent;

            if (texture2DContent != null)
            {
                var description = new TextureDescription
                {
                    Dimension = TextureDimension.Texture2D,
                    Width     = bitmapContent0.Width,
                    Height    = bitmapContent0.Height,
                    Depth     = 1,
                    MipLevels = texture2DContent.Mipmaps.Count,
                    ArraySize = 1,
                    Format    = surfaceFormat.ToDataFormat()
                };

                var texture = new Texture(description);
                for (int mipIndex = 0; mipIndex < description.MipLevels; mipIndex++)
                {
                    var bitmapContent = texture2DContent.Mipmaps[mipIndex];
                    var image         = texture.Images[texture.GetImageIndex(mipIndex, 0, 0)];
                    Buffer.BlockCopy(bitmapContent.GetPixelData(), 0, image.Data, 0, image.Data.Length);
                }

                return(texture);
            }

            var textureCubeContent = textureContent as TextureCubeContent;

            if (textureCubeContent != null)
            {
                var description = new TextureDescription
                {
                    Dimension = TextureDimension.TextureCube,
                    Width     = bitmapContent0.Width,
                    Height    = bitmapContent0.Height,
                    Depth     = 1,
                    MipLevels = textureCubeContent.Faces[0].Count,
                    ArraySize = 6,
                    Format    = surfaceFormat.ToDataFormat()
                };

                var texture = new Texture(description);
                for (int faceIndex = 0; faceIndex < 6; faceIndex++)
                {
                    for (int mipIndex = 0; mipIndex < description.MipLevels; mipIndex++)
                    {
                        var bitmapContent = textureCubeContent.Faces[faceIndex][mipIndex];
                        var image         = texture.Images[texture.GetImageIndex(mipIndex, faceIndex, 0)];
                        Buffer.BlockCopy(bitmapContent.GetPixelData(), 0, image.Data, 0, image.Data.Length);
                    }
                }

                return(texture);
            }

            var texture3DContent = textureContent as Texture3DContent;

            if (texture3DContent != null)
            {
                var description = new TextureDescription
                {
                    Dimension = TextureDimension.Texture3D,
                    Width     = bitmapContent0.Width,
                    Height    = bitmapContent0.Height,
                    Depth     = texture3DContent.Faces.Count,
                    MipLevels = texture3DContent.Faces[0].Count,
                    ArraySize = 1,
                    Format    = surfaceFormat.ToDataFormat()
                };

                var texture = new Texture(description);
                for (int zIndex = 0; zIndex < description.Depth; zIndex++)
                {
                    for (int mipIndex = 0; mipIndex < description.MipLevels; mipIndex++)
                    {
                        var bitmapContent = texture3DContent.Faces[zIndex][mipIndex];
                        var image         = texture.Images[texture.GetImageIndex(mipIndex, 0, zIndex)];
                        Buffer.BlockCopy(bitmapContent.GetPixelData(), 0, image.Data, 0, image.Data.Length);
                    }
                }

                return(texture);
            }

            throw new InvalidOperationException("Invalid texture dimension.");
        }
Пример #2
0
    //--------------------------------------------------------------
    #region Creation & Cleanup
    //--------------------------------------------------------------

    /// <summary>
    /// Initializes a new instance of the <see cref="Texture"/> class.
    /// </summary>
    /// <param name="description">The description.</param>
    /// <exception cref="ArgumentException">
    /// The <paramref name="description"/> is invalid.
    /// </exception>
    public Texture(TextureDescription description)
    {
      ValidateTexture(description);
      Description = description;
      Images = CreateImageCollection(description);
    }
Пример #3
0
        /// <summary>
        /// Decodes the TGA file header.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="offset">The offset in the stream at which the data starts.</param>
        /// <param name="convFlags">The conversion flags.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="stream"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="InvalidDataException">
        /// Invalid data.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// The specified format is not supported.
        /// </exception>
        private static TextureDescription DecodeTGAHeader(Stream stream, out int offset, out ConversionFlags convFlags)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            TextureDescription description = new TextureDescription
            {
                Dimension = TextureDimension.Texture2D,
                Format    = DataFormat.R8G8B8A8_UNORM,
            };

            offset    = 0;
            convFlags = ConversionFlags.None;

            long size            = stream.Length - stream.Position;
            int  sizeOfTGAHeader = Marshal.SizeOf(typeof(Header));

            if (size < sizeOfTGAHeader)
            {
                throw new InvalidDataException("The TGA file is corrupt.");
            }

            var header = stream.ReadStruct <Header>();

            if (header.ColorMapType != 0 || header.ColorMapLength != 0)
            {
                throw new NotSupportedException("TGA files with color maps are not supported.");
            }

            if ((header.Descriptor & (DescriptorFlags.Interleaved2Way | DescriptorFlags.Interleaved4Way)) != 0)
            {
                throw new NotSupportedException("TGA files with interleaved images are not supported.");
            }

            if (header.Width == 0 || header.Height == 0)
            {
                throw new NotSupportedException("The TGA file is corrupt. Width and height are invalid.");
            }

            switch (header.ImageType)
            {
            case ImageType.TrueColor:
            case ImageType.TrueColorRLE:
                switch (header.BitsPerPixel)
                {
                case 16:
                    description.Format = DataFormat.B5G5R5A1_UNORM;
                    break;

                case 24:
                    description.Format = DataFormat.R8G8B8A8_UNORM;
                    convFlags         |= ConversionFlags.Expand;
                    // We could use DXGI_FORMAT_B8G8R8X8_UNORM, but we prefer DXGI 1.0 formats
                    break;

                case 32:
                    description.Format = DataFormat.R8G8B8A8_UNORM;
                    // We could use DXGI.Format.B8G8R8A8_UNORM, but we prefer DXGI 1.0 formats
                    break;
                }

                if (header.ImageType == ImageType.TrueColorRLE)
                {
                    convFlags |= ConversionFlags.RLE;
                }
                break;

            case ImageType.BlackAndWhite:
            case ImageType.BlackAndWhiteRLE:
                switch (header.BitsPerPixel)
                {
                case 8:
                    description.Format = DataFormat.R8_UNORM;
                    break;

                default:
                    throw new NotSupportedException("The black-and-white format used by the TGA file is not supported. Only 8-bit black-and-white images are supported.");
                }

                if (header.ImageType == ImageType.BlackAndWhiteRLE)
                {
                    convFlags |= ConversionFlags.RLE;
                }
                break;

            case ImageType.NoImage:
            case ImageType.ColorMapped:
            case ImageType.ColorMappedRLE:
                throw new NotSupportedException("The image format used by the TGA file is not supported.");

            default:
                throw new InvalidDataException("Unknown image format used by the TGA file.");
            }

            description.Width     = header.Width;
            description.Height    = header.Height;
            description.Depth     = 1;
            description.MipLevels = 1;
            description.ArraySize = 1;

            if ((header.Descriptor & DescriptorFlags.InvertX) != 0)
            {
                convFlags |= ConversionFlags.InvertX;
            }

            if ((header.Descriptor & DescriptorFlags.InvertY) != 0)
            {
                convFlags |= ConversionFlags.InvertY;
            }

            offset = sizeOfTGAHeader;
            if (header.IDLength != 0)
            {
                offset += header.IDLength;
            }
            return(description);
        }
Пример #4
0
    /// <summary>
    /// Determines the number of image array entries and pixel size.
    /// </summary>
    /// <param name="description">The texture description.</param>
    /// <param name="nImages">The number of entries in the image array.</param>
    /// <param name="pixelSize">The total pixel size.</param>
    private static void DetermineImages(TextureDescription description, out int nImages, out int pixelSize)
    {
      Debug.Assert(description.Width > 0 && description.Height > 0 && description.Depth > 0);
      Debug.Assert(description.ArraySize > 0);
      Debug.Assert(description.MipLevels > 0);

      pixelSize = 0;
      nImages = 0;

      switch (description.Dimension)
      {
        case TextureDimension.Texture1D:
        case TextureDimension.Texture2D:
        case TextureDimension.TextureCube:
          for (int item = 0; item < description.ArraySize; item++)
          {
            int w = description.Width;
            int h = description.Height;

            for (int level = 0; level < description.MipLevels; level++)
            {
              int rowPitch, slicePitch;
              TextureHelper.ComputePitch(description.Format, w, h, out rowPitch, out slicePitch, ComputePitchFlags.None);
              pixelSize += slicePitch;
              nImages++;

              if (h > 1)
                h >>= 1;

              if (w > 1)
                w >>= 1;
            }
          }
          break;

        case TextureDimension.Texture3D:
          {
            int w = description.Width;
            int h = description.Height;
            int d = description.Depth;

            for (int level = 0; level < description.MipLevels; level++)
            {
              int rowPitch, slicePitch;
              TextureHelper.ComputePitch(description.Format, w, h, out rowPitch, out slicePitch, ComputePitchFlags.None);

              for (int slice = 0; slice < d; slice++)
              {
                pixelSize += slicePitch;
                nImages++;
              }

              if (h > 1)
                h >>= 1;

              if (w > 1)
                w >>= 1;

              if (d > 1)
                d >>= 1;
            }
          }
          break;

        default:
          Debug.Fail("Unexpected texture dimension");
          break;
      }
    }
Пример #5
0
    private static ImageCollection CreateImageCollection(TextureDescription description, bool skipMipLevel0 = false)
    {
      int numberOfImages, pixelSize;
      DetermineImages(description, out numberOfImages, out pixelSize);
      var images = new ImageCollection(numberOfImages);

      int index = 0;
      switch (description.Dimension)
      {
        case TextureDimension.Texture1D:
        case TextureDimension.Texture2D:
        case TextureDimension.TextureCube:
          Debug.Assert(description.ArraySize != 0);
          Debug.Assert(description.MipLevels > 0);

          for (int item = 0; item < description.ArraySize; item++)
          {
            int w = description.Width;
            int h = description.Height;

            for (int level = 0; level < description.MipLevels; level++)
            {
              if (!skipMipLevel0 || level != 0)
                images[index] = new Image(w, h, description.Format);

              index++;

              if (h > 1)
                h >>= 1;

              if (w > 1)
                w >>= 1;
            }
          }
          break;

        case TextureDimension.Texture3D:
          {
            Debug.Assert(description.MipLevels > 0);
            Debug.Assert(description.Depth > 0);

            int w = description.Width;
            int h = description.Height;
            int d = description.Depth;

            for (int level = 0; level < description.MipLevels; level++)
            {
              for (int slice = 0; slice < d; slice++)
              {
                // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA
                // with all slices of a given mip level being continuous in memory.
                if (!skipMipLevel0 || level != 0)
                  images[index] = new Image(w, h, description.Format);

                index++;
              }

              if (h > 1)
                h >>= 1;

              if (w > 1)
                w >>= 1;

              if (d > 1)
                d >>= 1;
            }
          }
          break;

        default:
          Debug.Fail("Unexpected texture dimension");
          break;
      }

      return images;
    }
Пример #6
0
        private static Texture DecodeMultiframe(ImagingFactory imagingFactory, WicFlags flags, TextureDescription description, BitmapDecoder decoder)
        {
            var  texture   = new Texture(description);
            Guid dstFormat = ToWic(description.Format, false);

            for (int index = 0; index < description.ArraySize; ++index)
            {
                var image = texture.Images[index];
                using (var frame = decoder.GetFrame(index))
                {
                    var pfGuid = frame.PixelFormat;
                    var size   = frame.Size;

                    if (size.Width == description.Width && size.Height == description.Height)
                    {
                        // This frame does not need resized
                        if (pfGuid == dstFormat)
                        {
                            frame.CopyPixels(image.Data, image.RowPitch);
                        }
                        else
                        {
                            using (var converter = new FormatConverter(imagingFactory))
                            {
                                converter.Initialize(frame, dstFormat, GetWicDither(flags), null, 0, BitmapPaletteType.Custom);
                                converter.CopyPixels(image.Data, image.RowPitch);
                            }
                        }
                    }
                    else
                    {
                        // This frame needs resizing
                        using (var scaler = new BitmapScaler(imagingFactory))
                        {
                            scaler.Initialize(frame, description.Width, description.Height, GetWicInterp(flags));

                            Guid pfScaler = scaler.PixelFormat;
                            if (pfScaler == dstFormat)
                            {
                                scaler.CopyPixels(image.Data, image.RowPitch);
                            }
                            else
                            {
                                // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we
                                // convert it to our desired format
                                using (var converter = new FormatConverter(imagingFactory))
                                {
                                    converter.Initialize(scaler, dstFormat, GetWicDither(flags), null, 0, BitmapPaletteType.Custom);
                                    converter.CopyPixels(image.Data, image.RowPitch);
                                }
                            }
                        }
                    }
                }
            }

            return(texture);
        }
Пример #7
0
        private static Texture DecodeSingleframe(ImagingFactory imagingFactory, WicFlags flags, TextureDescription description, Guid convertGuid, BitmapFrameDecode frame)
        {
            var texture = new Texture(description);
            var image   = texture.Images[0];

            if (convertGuid == Guid.Empty)
            {
                frame.CopyPixels(image.Data, image.RowPitch);
            }
            else
            {
                using (var converter = new FormatConverter(imagingFactory))
                {
                    converter.Initialize(frame, convertGuid, GetWicDither(flags), null, 0, BitmapPaletteType.Custom);
                    converter.CopyPixels(image.Data, image.RowPitch);
                }
            }

            return(texture);
        }
Пример #8
0
        private static TextureDescription DecodeMetadata(ImagingFactory imagingFactory, WicFlags flags, BitmapDecoder decoder, BitmapFrameDecode frame, out Guid pixelFormat)
        {
            var size = frame.Size;

            var description = new TextureDescription
            {
                Dimension = TextureDimension.Texture2D,
                Width     = size.Width,
                Height    = size.Height,
                Depth     = 1,
                MipLevels = 1,
                ArraySize = (flags & WicFlags.AllFrames) != 0 ? decoder.FrameCount : 1,
                Format    = DetermineFormat(imagingFactory, frame.PixelFormat, flags, out pixelFormat)
            };

            if (description.Format == DataFormat.Unknown)
            {
                throw new NotSupportedException("The pixel format is not supported.");
            }

            if ((flags & WicFlags.IgnoreSrgb) == 0)
            {
                // Handle sRGB.
#pragma warning disable 168
                try
                {
                    Guid containerFormat = decoder.ContainerFormat;
                    var  metareader      = frame.MetadataQueryReader;
                    if (metareader != null)
                    {
                        // Check for sRGB color space metadata.
                        bool sRgb = false;

                        if (containerFormat == ContainerFormatGuids.Png)
                        {
                            // Check for sRGB chunk.
                            if (metareader.GetMetadataByName("/sRGB/RenderingIntent") != null)
                            {
                                sRgb = true;
                            }
                        }
                        else if (containerFormat == ContainerFormatGuids.Jpeg)
                        {
                            if (Equals(metareader.GetMetadataByName("/app1/ifd/exif/{ushort=40961}"), 1))
                            {
                                sRgb = true;
                            }
                        }
                        else if (containerFormat == ContainerFormatGuids.Tiff)
                        {
                            if (Equals(metareader.GetMetadataByName("/ifd/exif/{ushort=40961}"), 1))
                            {
                                sRgb = true;
                            }
                        }
                        else
                        {
                            if (Equals(metareader.GetMetadataByName("System.Image.ColorSpace"), 1))
                            {
                                sRgb = true;
                            }
                        }

                        if (sRgb)
                        {
                            description.Format = TextureHelper.MakeSRgb(description.Format);
                        }
                    }
                }
                // ReSharper disable once EmptyGeneralCatchClause
                catch (Exception exception)
                {
                    // Some formats just don't support metadata (BMP, ICO, etc.).
                }
            }
#pragma warning restore 168

            return(description);
        }