Exemple #1
0
 /// <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);
 }
Exemple #2
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;
    }
Exemple #3
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;
      }
    }
        /// <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.");
        }
Exemple #5
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;
    }
Exemple #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;
    }
Exemple #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;
    }
Exemple #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;
    }