Пример #1
0
        public override async Task ReadDomainObject(ByteArrayReader reader, DomainHeader header, DomainExportTableEntry export, bool skipProperties, bool skipParse)
        {
            await base.ReadDomainObject(reader, header, export, skipProperties, skipParse);

            if (skipParse)
            {
                return;
            }

            MipMapsCount = reader.ReadInt32();

            for (int i = 0; i < MipMapsCount; ++i)
            {
                await ProcessCompressedBulkData(reader, async bulkChunk => {
                    DomainMipMap mip = new DomainMipMap
                    {
                        Width  = reader.ReadInt32(),
                        Height = reader.ReadInt32()
                    };

                    if (mip.Width >= 4 || mip.Height >= 4)
                    {
                        mip.ImageData = (await bulkChunk.DecompressChunk(0))?.GetBytes();
                    }

                    MipMaps.Add(mip);
                });
            }

            Guid = await reader.ReadBytes(16);
        }
        BitmapSource GetWPFBitmap(MipMap mip, int maxDimension, bool ShowAlpha)
        {
            BitmapSource bmp = null;

            if (maxDimension != 0)
            {
                // Choose a mip of the correct size, if available.
                var sizedMip = MipMaps.Where(m => (m.Height <= maxDimension && m.Width <= maxDimension) || (m.Width <= maxDimension && m.Height <= maxDimension));
                if (sizedMip.Any())
                {
                    var mip1 = sizedMip.First();
                    bmp = mip1.ToImage();
                }
                else
                {
                    double scale = (double)maxDimension / (Height > Width ? Height : Width);
                    mip = ImageEngine.Resize(mip, scale);
                    bmp = mip.ToImage();
                }
            }
            else
            {
                bmp = mip.ToImage();
            }

            if (!ShowAlpha)
            {
                bmp = new FormatConvertedBitmap(bmp, System.Windows.Media.PixelFormats.Bgr32, null, 0);
            }

            bmp.Freeze();
            return(bmp);
        }
Пример #3
0
        public override async Task SaveObject(string filename)
        {
            if (MipMaps == null || !MipMaps.Any())
            {
                return;
            }

            ImageEngineFormat format;

            DomainMipMap mipMap = MipMaps.Where(mm => mm.ImageData != null && mm.ImageData.Length > 0).OrderByDescending(mm => mm.Width > mm.Height ? mm.Width : mm.Height).FirstOrDefault();

            if (mipMap == null)
            {
                return;
            }

            MemoryStream memory = buildDdsImage(MipMaps.IndexOf(mipMap), out format);

            if (memory == null)
            {
                return;
            }

            ImageEngineImage ddsImage = new ImageEngineImage(memory);

            FileStream stream = new FileStream(filename, FileMode.Create);

            await Task.Run(() => ddsImage.Save(stream, format, MipHandling.KeepTopOnly));

            stream.Close();

            memory.Close();
        }
Пример #4
0
        public void Write(Stream outputStream)
        {
            var mipMaps = MipMaps.Reverse().ToList();

            foreach (var mipMap in mipMaps)
            {
                mipMap.Write(outputStream);
            }
        }
Пример #5
0
 public PNG(BaseImage image)
 {
     Width  = image.Width;
     Height = image.Height;
     foreach (MipMap mipmap in image.MipMaps)
     {
         MipMaps.Add(new MipMap(mipmap));
     }
 }
Пример #6
0
        public override Stream GetObjectStream()
        {
            if (MipMaps == null || !MipMaps.Any())
            {
                return(null);
            }

            ImageEngineFormat format;

            DomainMipMap mipMap = MipMaps.Where(mm => mm.ImageData != null && mm.ImageData.Length > 0).OrderByDescending(mm => mm.Width > mm.Height ? mm.Width : mm.Height).FirstOrDefault();

            return(mipMap == null ? null : buildDdsImage(MipMaps.IndexOf(mipMap), out format));
        }
Пример #7
0
        private void PreprocessMipMaps()
        {
            bool hwCompressed = Format == TextureContentFormat.DXT1 || Format == TextureContentFormat.DXT3 || Format == TextureContentFormat.DXT5;
            int  width = Width, height = Height;
            int  realCount = 0;

            for (int i = 0; i < (GenerateMipMaps ? 1 : MipMapCount); i++)
            {
                if (hwCompressed)
                {
                    int    dataSize = 0;
                    byte[] data     = null;
                    ThreadingHelper.BlockOnUIThread(() =>
                    {
                        GL.BindTexture(TextureTarget.Texture2D, texture);
                        GL.GetTexLevelParameter(TextureTarget.Texture2D, i, GetTextureParameter.TextureCompressedImageSize, out dataSize);
                        data = new byte[dataSize];
                        GL.GetCompressedTexImage(TextureTarget.Texture2D, i, data);
                    });
                    MipMaps.Add(new TextureContentMipMap(width, height, Format, data));
                }
                else
                {
                    var bmp = new System.Drawing.Bitmap(width, height);

                    var bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

                    ThreadingHelper.BlockOnUIThread(() =>
                    {
                        GL.BindTexture(TextureTarget.Texture2D, texture);
                        GL.GetTexImage(TextureTarget.Texture2D, i, OpenTK.Graphics.OpenGL4.PixelFormat.Bgra, PixelType.UnsignedByte, bmpData.Scan0);
                    });

                    bmp.UnlockBits(bmpData);

                    MipMaps.Add(new TextureContentMipMap(width, height, Format, bmp));
                }
                width  /= 2;
                height /= 2;
                realCount++;
                if (width == 0 || height == 0)
                {
                    break;
                }
            }
            if (!GenerateMipMaps)
            {
                MipMapCount = realCount;
            }
        }
Пример #8
0
        /// <summary>
        /// Creates a WPF Bitmap from largest mipmap.
        /// Does NOT require that image remains alive.
        /// </summary>
        /// <param name="mergeAlpha">Only valid if maxDimension set. True = flattens alpha, directly affecting RGB.</param>
        /// <param name="maxDimension">Resizes image or uses a mipmap if available.</param>
        /// <returns>WPF bitmap of largest mipmap.</returns>
        public BitmapSource GetWPFBitmap(int maxDimension = 0, bool mergeAlpha = false)
        {
            MipMap mip = MipMaps[0];

            if (maxDimension != 0)
            {
                // Choose a mip of the correct size, if available.
                var sizedMip = MipMaps.Where(m => (m.Height == maxDimension && m.Width <= maxDimension) || (m.Width == maxDimension && m.Height <= maxDimension));
                if (sizedMip.Any())
                {
                    mip = sizedMip.First();
                }
                else
                {
                    double scale = maxDimension * 1f / (Height > Width ? Height : Width);
                    mip = ImageEngine.Resize(mip, scale, mergeAlpha);
                }
            }
            mip.BaseImage.Freeze();
            return(mip.BaseImage);
        }
Пример #9
0
        /// <summary>
        /// Creates a GDI+ bitmap from largest mipmap.
        /// Does NOT require that image remains alive.
        /// </summary>
        /// <param name="ignoreAlpha">True = Previews image without alpha channel.</param>
        /// <param name="maxDimension">Largest size to display.</param>
        /// <param name="mergeAlpha">ONLY valid when maxDimension is set. True = flattens alpha, directly affecting RGB.</param>
        /// <returns>GDI+ bitmap of largest mipmap.</returns>
        public System.Drawing.Bitmap GetGDIBitmap(bool ignoreAlpha, bool mergeAlpha, int maxDimension = 0)
        {
            MipMap mip = MipMaps[0];

            if (maxDimension != 0)
            {
                // Choose a mip of the correct size, if available.
                var sizedMip = MipMaps.Where(m => (m.Height == maxDimension && m.Width <= maxDimension) || (m.Width == maxDimension && m.Height <= maxDimension));
                if (sizedMip.Any())
                {
                    mip = sizedMip.First();
                }
                else
                {
                    double scale = maxDimension * 1f / (Height > Width ? Height : Width);
                    mip = ImageEngine.Resize(mip, scale, mergeAlpha);
                }
            }

            mip.BaseImage.Freeze();
            return(UsefulThings.WinForms.Imaging.CreateBitmap(mip.BaseImage, ignoreAlpha));
        }
        /// <summary>
        /// Scales top mipmap and DESTROYS ALL OTHERS.
        /// </summary>
        /// <param name="scale">Scaling factor. </param>
        public void Resize(double scale)
        {
            MipMap closestMip  = null;
            double newScale    = 0;
            double desiredSize = MipMaps[0].Width * scale;

            double min = double.MaxValue;

            foreach (var mip in MipMaps)
            {
                double temp = Math.Abs(mip.Width - desiredSize);
                if (temp < min)
                {
                    closestMip = mip;
                    min        = temp;
                }
            }

            newScale = desiredSize / closestMip.Width;

            MipMaps[0] = ImageEngine.Resize(closestMip, newScale);
            MipMaps.RemoveRange(1, NumMipMaps - 1);
        }
Пример #11
0
        private void GetFromBitmap(Bitmap bitmap)
        {
            Bitmap bmp = new Bitmap(bitmap);

            Width  = bmp.Width;
            Height = bmp.Height;

            MipMap mipMap = new MipMap(Width, Height);

            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    Color col   = bmp.GetPixel(x, y);
                    int   index = (y * Width + x) * 4;
                    mipMap.Pixels[index]     = col.B;
                    mipMap.Pixels[index + 1] = col.G;
                    mipMap.Pixels[index + 2] = col.R;
                    mipMap.Pixels[index + 3] = col.A;
                }
            }
            MipMaps.Add(mipMap);
        }
Пример #12
0
        public override async Task SaveObject(string filename, object configuration)
        {
            if (MipMaps == null || !MipMaps.Any())
            {
                return;
            }

            DdsSaveConfig config = configuration as DdsSaveConfig ?? new DdsSaveConfig(FileFormat.Unknown, 0, 0, false, false);

            FileFormat format;

            DomainMipMap mipMap = MipMaps.Where(mm => mm.ImageData != null && mm.ImageData.Length > 0).OrderByDescending(mm => mm.Width > mm.Height ? mm.Width : mm.Height).FirstOrDefault();

            if (mipMap == null)
            {
                return;
            }

            Stream memory = buildDdsImage(MipMaps.IndexOf(mipMap), out format);

            if (memory == null)
            {
                return;
            }

            DdsFile ddsImage = new DdsFile(memory);

            FileStream ddsStream = new FileStream(filename, FileMode.Create);

            config.FileFormat = format;

            await Task.Run(() => ddsImage.Save(ddsStream, config));

            ddsStream.Close();

            memory.Close();
        }
Пример #13
0
        protected override void _Read(BinaryReader reader)
        {
            Image  image = Image.FromStream(reader.BaseStream);
            Bitmap bmp   = new Bitmap(image);

            Width  = bmp.Width;
            Height = bmp.Height;

            MipMap mipMap = new MipMap(Width, Height);

            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    Color col   = bmp.GetPixel(x, y);
                    int   index = (y * Width + x) * 4;
                    mipMap.Pixels[index]     = col.B;
                    mipMap.Pixels[index + 1] = col.G;
                    mipMap.Pixels[index + 2] = col.R;
                    mipMap.Pixels[index + 3] = col.A;
                }
            }
            MipMaps.Add(mipMap);
        }
Пример #14
0
        public DDS(D3DFormat format, Bitmap bitmap)
        {
            SquishFlags flags      = SquishFlags.kDxt1;
            bool        compressed = true;

            switch (format)
            {
            case D3DFormat.DXT1:
                flags = SquishFlags.kDxt1;
                break;

            case D3DFormat.DXT3:
                flags = SquishFlags.kDxt3;
                break;

            case D3DFormat.DXT5:
                flags = SquishFlags.kDxt5;
                break;

            default:
                compressed = false;
                break;
            }

            Format = format;
            Width  = bitmap.Width;
            Height = bitmap.Height;

            MipMap mip = new MipMap
            {
                Width  = Width,
                Height = Height
            };

            byte[] data = new byte[mip.Width * mip.Height * 4];

            BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, mip.Width, mip.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            Marshal.Copy(bmpdata.Scan0, data, 0, bmpdata.Stride * bmpdata.Height);
            bitmap.UnlockBits(bmpdata);

            if (compressed)
            {
                for (uint i = 0; i < data.Length - 4; i += 4)
                {
                    byte r = data[i + 0];
                    data[i + 0] = data[i + 2];
                    data[i + 2] = r;
                }

                byte[] dest = new byte[Squish.Squish.GetStorageRequirements(mip.Width, mip.Height, flags | SquishFlags.kColourIterativeClusterFit)];
                Squish.Squish.CompressImage(data, mip.Width, mip.Height, ref dest, flags | SquishFlags.kColourIterativeClusterFit);
                mip.Data = dest;
            }
            else
            {
                mip.Data = data;
            }

            MipMaps.Add(mip);
        }
Пример #15
0
 /// <summary>
 /// Scales top mipmap and DESTROYS ALL OTHERS.
 /// </summary>
 /// <param name="scale">Scaling factor. </param>
 /// <param name="mergeAlpha">True = flattens alpha, directly affecting RGB.</param>
 public void Resize(double scale, bool mergeAlpha)
 {
     MipMaps[0] = ImageEngine.Resize(MipMaps[0], scale, mergeAlpha);
     MipMaps.RemoveRange(1, NumMipMaps - 1);
 }
        byte[] AttemptSaveUsingOriginalData(ImageFormats.ImageEngineFormatDetails destFormatDetails, MipHandling GenerateMips, int desiredMaxDimension, int mipToSave, AlphaSettings alphaSetting)
        {
            int        start      = 0;
            int        destStart  = 0;
            int        length     = OriginalData.Length;
            int        newWidth   = Width;
            int        newHeight  = Height;
            DDS_Header tempHeader = null;

            byte[] data             = null;
            byte[] tempOriginalData = OriginalData;

            if (destFormatDetails.IsDDS)
            {
                destStart = destFormatDetails.HeaderSize;
                start     = destStart;

                int mipCount = 0;

                if (mipToSave != 0)
                {
                    mipCount  = 1;
                    newWidth  = MipMaps[mipToSave].Width;
                    newHeight = MipMaps[mipToSave].Height;

                    start  = ImageFormats.GetCompressedSize(mipToSave, destFormatDetails, Width, Height);
                    length = ImageFormats.GetCompressedSize(1, destFormatDetails, newWidth, newHeight);
                }
                else if (desiredMaxDimension != 0 && desiredMaxDimension < Width && desiredMaxDimension < Height)
                {
                    int index = MipMaps.FindIndex(t => t.Width < desiredMaxDimension && t.Height < desiredMaxDimension);

                    // If none found, do a proper save and see what happens.
                    if (index == -1)
                    {
                        return(ImageEngine.Save(MipMaps, destFormatDetails, GenerateMips, alphaSetting, desiredMaxDimension, mipToSave));
                    }

                    mipCount -= index;
                    newWidth  = MipMaps[index].Width;
                    newHeight = MipMaps[index].Height;

                    start  = ImageFormats.GetCompressedSize(index, destFormatDetails, Width, Height);
                    length = ImageFormats.GetCompressedSize(mipCount, destFormatDetails, newWidth, newHeight);
                }
                else
                {
                    if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
                    {
                        // Can't edit alpha directly in premultiplied formats. Not easily anyway.
                        if (destFormatDetails.IsPremultipliedFormat)
                        {
                            return(ImageEngine.Save(MipMaps, destFormatDetails, GenerateMips, alphaSetting, desiredMaxDimension, mipToSave));
                        }


                        // DDS Formats only
                        switch (destFormatDetails.Format)
                        {
                        // Excluded cos they have no true alpha
                        case ImageEngineFormat.DDS_A8:
                        case ImageEngineFormat.DDS_A8L8:
                        case ImageEngineFormat.DDS_ATI1:
                        case ImageEngineFormat.DDS_ATI2_3Dc:
                        case ImageEngineFormat.DDS_V8U8:
                        case ImageEngineFormat.DDS_G16_R16:
                        case ImageEngineFormat.DDS_G8_L8:
                        case ImageEngineFormat.DDS_R5G6B5:
                        case ImageEngineFormat.DDS_RGB_8:
                        case ImageEngineFormat.DDS_DXT1:
                            break;

                        // Exluded cos they're alpha isn't easily edited
                        case ImageEngineFormat.DDS_DXT2:
                        case ImageEngineFormat.DDS_DXT4:
                            break;

                        // Excluded cos they're currently unsupported
                        case ImageEngineFormat.DDS_CUSTOM:
                        case ImageEngineFormat.DDS_DX10:
                        case ImageEngineFormat.DDS_ARGB_4:
                            break;

                        case ImageEngineFormat.DDS_ABGR_8:
                        case ImageEngineFormat.DDS_ARGB_32F:
                        case ImageEngineFormat.DDS_ARGB_8:
                        case ImageEngineFormat.DDS_DXT3:
                        case ImageEngineFormat.DDS_DXT5:
                            tempOriginalData = new byte[OriginalData.Length];
                            Array.Copy(OriginalData, tempOriginalData, OriginalData.Length);

                            // Edit alpha values
                            int    alphaStart = 128;
                            int    alphaJump  = 0;
                            byte[] alphaBlock = null;
                            if (destFormatDetails.IsBlockCompressed)
                            {
                                alphaJump  = 16;
                                alphaBlock = new byte[8];
                                for (int i = 0; i < 8; i++)
                                {
                                    alphaBlock[i] = 255;
                                }
                            }
                            else
                            {
                                alphaJump  = destFormatDetails.ComponentSize * 4;
                                alphaBlock = new byte[destFormatDetails.ComponentSize];

                                switch (destFormatDetails.ComponentSize)
                                {
                                case 1:
                                    alphaBlock[0] = 255;
                                    break;

                                case 2:
                                    alphaBlock = BitConverter.GetBytes(ushort.MaxValue);
                                    break;

                                case 4:
                                    alphaBlock = BitConverter.GetBytes(1f);
                                    break;
                                }
                            }

                            for (int i = alphaStart; i < OriginalData.Length; i += alphaJump)
                            {
                                Array.Copy(alphaBlock, 0, tempOriginalData, i, alphaBlock.Length);
                            }

                            break;
                        }
                    }


                    switch (GenerateMips)
                    {
                    case MipHandling.KeepExisting:
                        mipCount = NumMipMaps;
                        break;

                    case MipHandling.Default:
                        if (NumMipMaps > 1)
                        {
                            mipCount = NumMipMaps;
                        }
                        else
                        {
                            goto case MipHandling.GenerateNew;      // Eww goto...
                        }
                        break;

                    case MipHandling.GenerateNew:
                        ImageEngine.DestroyMipMaps(MipMaps);
                        ImageEngine.TestDDSMipSize(MipMaps, destFormatDetails, Width, Height, out double fixXScale, out double fixYScale, GenerateMips);

                        // Wrong sizing, so can't use original data anyway.
                        if (fixXScale != 0 || fixYScale != 0)
                        {
                            return(ImageEngine.Save(MipMaps, destFormatDetails, GenerateMips, alphaSetting, desiredMaxDimension, mipToSave));
                        }


                        mipCount = DDSGeneral.BuildMipMaps(MipMaps);

                        // Compress mipmaps excl top
                        byte[] formattedMips = DDSGeneral.Save(MipMaps.GetRange(1, MipMaps.Count - 1), destFormatDetails, alphaSetting);
                        if (formattedMips == null)
                        {
                            return(null);
                        }

                        // Get top mip size and create destination array
                        length = ImageFormats.GetCompressedSize(0, destFormatDetails, newWidth, newHeight);     // Should be the length of the top mipmap.
                        data   = new byte[formattedMips.Length + length];

                        // Copy smaller mips to destination
                        Array.Copy(formattedMips, destFormatDetails.HeaderSize, data, length, formattedMips.Length - destFormatDetails.HeaderSize);
                        break;

                    case MipHandling.KeepTopOnly:
                        mipCount = 1;
                        length   = ImageFormats.GetCompressedSize(1, destFormatDetails, newWidth, newHeight);
                        break;
                    }
                }

                // Header
                tempHeader = new DDS_Header(mipCount, newHeight, newWidth, destFormatDetails.Format, destFormatDetails.DX10Format);
            }

            // Use existing array, otherwise create one.
            data = data ?? new byte[length];
            Array.Copy(tempOriginalData, start, data, destStart, length - destStart);

            // Write header if existing (DDS Only)
            if (tempHeader != null)
            {
                tempHeader.WriteToArray(data, 0);
            }

            return(data);
        }
Пример #17
0
        public override async Task SetObject(string filename, List <DomainNameTableEntry> nameTable, object configuration)
        {
            DdsSaveConfig config = configuration as DdsSaveConfig ?? new DdsSaveConfig(FileFormat.Unknown, 0, 0, false, false);

            DdsFile image = await Task.Run(() => new DdsFile(filename));

            bool skipFirstMip = false;

            int width  = image.Width;
            int height = image.Height;

            if (MipMaps[0].ImageData == null || MipMaps[0].ImageData.Length == 0)
            {
                width  *= 2;
                height *= 2;

                skipFirstMip = true;
            }

            DomainPropertyIntValue sizeX = PropertyHeader.GetProperty("SizeX").FirstOrDefault()?.Value as DomainPropertyIntValue;
            DomainPropertyIntValue sizeY = PropertyHeader.GetProperty("SizeY").FirstOrDefault()?.Value as DomainPropertyIntValue;

            sizeX?.SetPropertyValue(skipFirstMip ? width * 2 : width);
            sizeY?.SetPropertyValue(skipFirstMip ? height * 2 : height);

            DomainPropertyIntValue mipTailBaseIdx = PropertyHeader.GetProperty("MipTailBaseIdx").FirstOrDefault()?.Value as DomainPropertyIntValue;

            int indexSize = width > height ? width : height;

            mipTailBaseIdx?.SetPropertyValue((int)Math.Log(skipFirstMip ? indexSize * 2 : indexSize, 2));

            DomainPropertyStringValue filePath = PropertyHeader.GetProperty("SourceFilePath").FirstOrDefault()?.Value as DomainPropertyStringValue;
            DomainPropertyStringValue fileTime = PropertyHeader.GetProperty("SourceFileTimestamp").FirstOrDefault()?.Value as DomainPropertyStringValue;

            filePath?.SetPropertyValue(filename);
            fileTime?.SetPropertyValue(File.GetLastWriteTime(filename).ToString("yyyy-MM-dd hh:mm:ss"));

            DomainPropertyByteValue pfFormat = PropertyHeader.GetProperty("Format").FirstOrDefault()?.Value as DomainPropertyByteValue;

            FileFormat imageFormat = FileFormat.Unknown;

            if (pfFormat != null)
            {
                imageFormat = DdsPixelFormat.ParseFileFormat(pfFormat.PropertyString);
            }

            if (imageFormat == FileFormat.Unknown)
            {
                throw new Exception($"Unknown DDS File Format ({pfFormat?.PropertyString ?? "Unknown"}).");
            }

            config.FileFormat = imageFormat;

            MipMaps.Clear();

            if (skipFirstMip)
            {
                MipMaps.Add(new DomainMipMap {
                    ImageData = null,
                    Width     = width,
                    Height    = height
                });
            }

            image.GenerateMipMaps(4, 4);

            foreach (DdsMipMap mipMap in image.MipMaps.OrderByDescending(mip => mip.Width))
            {
                MipMaps.Add(new DomainMipMap {
                    ImageData = image.WriteMipMap(mipMap, config),
                    Width     = mipMap.Width,
                    Height    = mipMap.Height
                });
            }
        }
Пример #18
0
        public override async Task SetObject(string filename, List <DomainNameTableEntry> nameTable)
        {
            ImageEngineImage image = await Task.Run(() => new ImageEngineImage(filename));

            int width  = image.Width;
            int height = image.Height;

            DomainPropertyIntValue sizeX = PropertyHeader.GetProperty("SizeX").FirstOrDefault()?.Value as DomainPropertyIntValue;
            DomainPropertyIntValue sizeY = PropertyHeader.GetProperty("SizeY").FirstOrDefault()?.Value as DomainPropertyIntValue;

            sizeX?.SetPropertyValue(width);
            sizeY?.SetPropertyValue(height);

            DomainPropertyIntValue mipTailBaseIdx = PropertyHeader.GetProperty("MipTailBaseIdx").FirstOrDefault()?.Value as DomainPropertyIntValue;

            mipTailBaseIdx?.SetPropertyValue((int)Math.Log(width > height ? width : height, 2));

            DomainPropertyStringValue filePath = PropertyHeader.GetProperty("SourceFilePath").FirstOrDefault()?.Value as DomainPropertyStringValue;
            DomainPropertyStringValue fileTime = PropertyHeader.GetProperty("SourceFileTimestamp").FirstOrDefault()?.Value as DomainPropertyStringValue;

            filePath?.SetPropertyValue(filename);
            fileTime?.SetPropertyValue(File.GetLastWriteTime(filename).ToString("yyyy-MM-dd hh:mm:ss"));

            DomainPropertyByteValue pfFormat = PropertyHeader.GetProperty("Format").FirstOrDefault()?.Value as DomainPropertyByteValue;

            ImageEngineFormat imageFormat = image.Format.InternalFormat;

            if (!imageFormat.ToString().Contains("DDS"))
            {
                throw new Exception($"Image is not in a DDS format.  It is actually {imageFormat}.");
            }

            if (pfFormat != null)
            {
                string formatStr = imageFormat.ToString().Replace("DDS", "PF");

                if (formatStr.Contains("ARGB"))
                {
                    formatStr = "PF_A8R8G8B8";
                }
                else if (formatStr.Contains("G8"))
                {
                    formatStr = "PF_G8";
                }

                DomainNameTableEntry formatTableEntry = nameTable.SingleOrDefault(nt => nt.Name.String == formatStr) ?? nameTable.AddDomainNameTableEntry(formatStr);

                pfFormat.SetPropertyValue(formatTableEntry);
            }

            MipMaps.Clear();

            while (true)
            {
                MemoryStream stream = new MemoryStream();

                image.Save(stream, imageFormat, MipHandling.KeepTopOnly);

                await stream.FlushAsync();

                MipMaps.Add(new DomainMipMap
                {
                    ImageData = (await ByteArrayReader.CreateNew(stream.ToArray(), 0x80).Splice()).GetBytes(), // Strip off 128 bytes for the DDS header
                    Width     = image.Width,
                    Height    = image.Height
                });

                if (width == 1 && height == 1)
                {
                    break;
                }

                if (width > 1)
                {
                    width /= 2;
                }
                if (height > 1)
                {
                    height /= 2;
                }

                if (image.Width > 4 && image.Height > 4)
                {
                    image.Resize(0.5, false);
                }
            }
        }