예제 #1
0
        internal string GetAutoSavePath(ImageEngineFormat newformat)
        {
            string newpath        = null;
            bool   acceptablePath = false;
            int    count          = 1;


            string formatString = ImageFormats.GetExtensionOfFormat(newformat);

            string basepath = Path.GetDirectoryName(ImagePath) + "\\" + Path.GetFileNameWithoutExtension(ImagePath) + "." +
                              (newformat == ImageEngineFormat.Unknown ? Path.GetExtension(ImagePath) : formatString);

            newpath = basepath;

            // KFreon: Check that path is not already taken
            while (!acceptablePath)
            {
                if (File.Exists(newpath))
                {
                    newpath = Path.Combine(Path.GetDirectoryName(basepath), Path.GetFileNameWithoutExtension(basepath) + "_" + count++ + Path.GetExtension(basepath));
                }
                else
                {
                    acceptablePath = true;
                }
            }

            return(newpath);
        }
예제 #2
0
        /// <summary>
        /// Creates a DDS header from a set of information.
        /// </summary>
        /// <param name="Mips">Number of mipmaps.</param>
        /// <param name="Height">Height of top mipmap.</param>
        /// <param name="Width">Width of top mipmap.</param>
        /// <param name="surfaceformat">Format header represents.</param>
        public DDS_Header(int Mips, int Height, int Width, ImageEngineFormat surfaceformat, DXGI_FORMAT dx10Format = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN)
        {
            dwSize        = 124;
            dwFlags       = DDSdwFlags.DDSD_CAPS | DDSdwFlags.DDSD_HEIGHT | DDSdwFlags.DDSD_WIDTH | DDSdwFlags.DDSD_PIXELFORMAT | (Mips != 1 ? DDSdwFlags.DDSD_MIPMAPCOUNT : 0);
            this.Width    = Width;
            this.Height   = Height;
            dwCaps        = DDSdwCaps.DDSCAPS_TEXTURE | (Mips == 1 ? 0 : DDSdwCaps.DDSCAPS_COMPLEX | DDSdwCaps.DDSCAPS_MIPMAP);
            dwMipMapCount = Mips == 1 ? 1 : Mips;
            ddspf         = new DDS_PIXELFORMAT(surfaceformat);

            if (surfaceformat == ImageEngineFormat.DDS_DX10 || surfaceformat == ImageEngineFormat.DDS_ARGB_32F)
            {
                if (surfaceformat == ImageEngineFormat.DDS_ARGB_32F)
                {
                    dx10Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT;
                }

                DX10_DXGI_AdditionalHeader = new DDS_DXGI_DX10_Additional
                {
                    dxgiFormat        = dx10Format,
                    resourceDimension = D3D10_RESOURCE_DIMENSION.DDS_DIMENSION_TEXTURE2D,
                    miscFlag          = DDS_DXGI_DX10_Additional.D3D10_RESOURCE_MISC_FLAGS.D3D10_RESOURCE_MISC_GENERATE_MIPS,
                    miscFlags2        = DXGI_MiscFlags.DDS_ALPHA_MODE_UNKNOWN,
                    arraySize         = 1
                };
            }
        }
        void Load(Stream stream, int maxDimension)
        {
            CompressedSize = (int)stream.Length;
            Header         = ImageEngine.LoadHeader(stream);

            // DX10
            var DX10Format = DDS_Header.DXGI_FORMAT.DXGI_FORMAT_UNKNOWN;

            if (Header is Headers.DDS_Header)
            {
                DX10Format = ((Headers.DDS_Header)Header).DX10_DXGI_AdditionalHeader.dxgiFormat;
            }


            ImageEngineFormat tempFormat = Header.Format;

            if (DX10Format == DDS_Header.DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT)   // Trickses to get around the DX10 float header deal - Apparently float formats should be specified with the DX10 header...
            {
                tempFormat = ImageEngineFormat.DDS_ARGB_32F;
                var tempPF = ((DDS_Header)Header).ddspf;
                tempPF.dwRBitMask          = 1;
                tempPF.dwGBitMask          = 2;
                tempPF.dwBBitMask          = 3;
                tempPF.dwABitMask          = 4;
                ((DDS_Header)Header).ddspf = tempPF;
            }

            FormatDetails = new ImageFormats.ImageEngineFormatDetails(tempFormat, DX10Format);
            MipMaps       = ImageEngine.LoadImage(stream, Header, maxDimension, 0, FormatDetails);

            // Read original data
            OriginalData    = new byte[CompressedSize];
            stream.Position = 0;
            stream.Read(OriginalData, 0, CompressedSize);
        }
예제 #4
0
        /// <summary>
        /// Gets maximum number of channels a format can contain.
        /// NOTE: This likely isn't actually the max number. i.e. None exceed four, but some are only one or two channels.
        /// </summary>
        /// <param name="format">Format to channel count.</param>
        /// <returns>Max number of channels supported.</returns>
        static int MaxNumberOfChannels(ImageEngineFormat format)
        {
            int numChannels = 4;

            switch (format)
            {
            case ImageEngineFormat.DDS_A8:
            case ImageEngineFormat.DDS_ATI1:
            case ImageEngineFormat.DDS_G8_L8:
                numChannels = 1;
                break;

            case ImageEngineFormat.DDS_A8L8:
            case ImageEngineFormat.DDS_ATI2_3Dc:
            case ImageEngineFormat.DDS_G16_R16:
            case ImageEngineFormat.DDS_V8U8:
                numChannels = 2;
                break;

            case ImageEngineFormat.DDS_R5G6B5:
            case ImageEngineFormat.DDS_RGB_8:
            case ImageEngineFormat.JPG:
                numChannels = 3;
                break;
            }

            return(numChannels);
        }
예제 #5
0
        /// <summary>
        /// Checks image file size to ensure requested mipmap is present in image.
        /// Header mip count can be incorrect or missing. Use this method to validate the mip you're after.
        /// </summary>
        /// <param name="streamLength">Image file stream length.</param>
        /// <param name="mainWidth">Width of image.</param>
        /// <param name="mainHeight">Height of image.</param>
        /// <param name="desiredMipDimension">Max dimension of desired mip.</param>
        /// <param name="format">Format of image.</param>
        /// <param name="mipOffset">Offset of desired mipmap in image.</param>
        /// <returns></returns>
        public static bool EnsureMipInImage(long streamLength, int mainWidth, int mainHeight, int desiredMipDimension, ImageEngineFormat format, out int mipOffset)
        {
            if (mainWidth <= desiredMipDimension && mainHeight <= desiredMipDimension)
            {
                mipOffset = 128;
                return true; // One mip only
                // TODO: DX10
            }

            int dependentDimension = mainWidth > mainHeight ? mainWidth : mainHeight;
            int mipIndex = (int)Math.Log((dependentDimension / desiredMipDimension), 2);
            if (mipIndex < -1)
                throw new InvalidDataException($"Invalid dimensions for mipmapping. Got desired: {desiredMipDimension} and dependent: {dependentDimension}");

            int requiredOffset = GetMipOffset(mipIndex, format, mainHeight, mainWidth);  // +128 for header

            // KFreon: Something wrong with the count here by 1 i.e. the estimate is 1 more than it should be
            if (format == ImageEngineFormat.DDS_ARGB)
                requiredOffset -= 2;

            mipOffset = requiredOffset;

            // Should only occur when an image has 0 or 1 mipmap.
            if (streamLength <= requiredOffset)
                return false;

            return true;
        }
예제 #6
0
        /// <summary>
        /// Saves image using internal Codecs - DDS and mippables not supported.
        /// </summary>
        /// <param name="image">Image as bmp source.</param>
        /// <param name="destination">Image stream to save to.</param>
        /// <param name="format">Destination image format.</param>
        /// <returns>True on success.</returns>
        internal static bool SaveWithCodecs(BitmapSource image, Stream destination, ImageEngineFormat format)
        {
            BitmapFrame frame = BitmapFrame.Create(image);

            // KFreon: Choose encoder based on desired format.
            BitmapEncoder encoder = null;

            switch (format)
            {
            case ImageEngineFormat.BMP:
                encoder = new BmpBitmapEncoder();
                break;

            case ImageEngineFormat.JPG:
                encoder = new JpegBitmapEncoder();
                ((JpegBitmapEncoder)encoder).QualityLevel = 90;
                break;

            case ImageEngineFormat.PNG:
                encoder = new PngBitmapEncoder();
                break;

            default:
                throw new InvalidOperationException($"Unable to encode format: {format} using Windows 8.1 Codecs.");
            }

            encoder.Frames.Add(frame);
            encoder.Save(destination);
            return(true);
        }
예제 #7
0
        /// <summary>
        /// Parses a string to an ImageEngineFormat.
        /// </summary>
        /// <param name="format">String representation of ImageEngineFormat.</param>
        /// <returns>ImageEngineFormat of format.</returns>
        public static ImageEngineFormat ParseFromString(string format)
        {
            ImageEngineFormat parsedFormat = ImageEngineFormat.Unknown;

            if (format.Contains("dxt1", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_DXT1;
            }
            else if (format.Contains("dxt2", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_DXT2;
            }
            else if (format.Contains("dxt3", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_DXT3;
            }
            else if (format.Contains("dxt4", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_DXT4;
            }
            else if (format.Contains("dxt5", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_DXT5;
            }
            else if (format.Contains("bmp", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.BMP;
            }
            else if (format.Contains("argb", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_ARGB;
            }
            else if (format.Contains("ati1", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_ATI1;
            }
            else if (format.Contains("ati2", StringComparison.OrdinalIgnoreCase) || format.Contains("3dc", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_ATI2_3Dc;
            }
            else if (format.Contains("l8", StringComparison.OrdinalIgnoreCase) || format.Contains("g8", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_G8_L8;
            }
            else if (format.Contains("v8u8", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.DDS_V8U8;
            }
            else if (format.Contains("jpg", StringComparison.OrdinalIgnoreCase) || format.Contains("jpeg", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.JPG;
            }
            else if (format.Contains("png", StringComparison.OrdinalIgnoreCase))
            {
                parsedFormat = ImageEngineFormat.PNG;
            }


            return(parsedFormat);
        }
예제 #8
0
        /// <summary>
        /// Searches for a format within a string. Good for automatic file naming.
        /// </summary>
        /// <param name="stringWithFormatInIt">String containing format somewhere in it.</param>
        /// <returns>Format in string, or UNKNOWN otherwise.</returns>
        public static ImageEngineFormat FindFormatInString(string stringWithFormatInIt)
        {
            ImageEngineFormat detectedFormat = ImageEngineFormat.Unknown;

            foreach (var formatName in Enum.GetNames(typeof(ImageEngineFormat)))
            {
                string actualFormat = formatName.Replace("DDS_", "");
                bool   check        = stringWithFormatInIt.Contains(actualFormat, StringComparison.OrdinalIgnoreCase);

                if (actualFormat.Contains("3Dc"))
                {
                    check = stringWithFormatInIt.Contains("3dc", StringComparison.OrdinalIgnoreCase) || stringWithFormatInIt.Contains("ati2", StringComparison.OrdinalIgnoreCase);
                }
                else if (actualFormat == "A8L8")
                {
                    check = stringWithFormatInIt.Contains("L8", StringComparison.OrdinalIgnoreCase) && !stringWithFormatInIt.Contains("G", StringComparison.OrdinalIgnoreCase);
                }
                else if (actualFormat == "G8_L8")
                {
                    check = !stringWithFormatInIt.Contains("A", StringComparison.OrdinalIgnoreCase) && stringWithFormatInIt.Contains("G8", StringComparison.OrdinalIgnoreCase);
                }
                else if (actualFormat.Contains("ARGB"))
                {
                    check = stringWithFormatInIt.Contains("A8R8G8B8", StringComparison.OrdinalIgnoreCase) || stringWithFormatInIt.Contains("ARGB", StringComparison.OrdinalIgnoreCase);
                }

                if (check)
                {
                    detectedFormat = (ImageEngineFormat)Enum.Parse(typeof(ImageEngineFormat), formatName);
                    break;
                }
            }

            return(detectedFormat);
        }
예제 #9
0
 /// <summary>
 /// Loads DDS that has no header - primarily for ME3Explorer. DDS data is standard, just without a header.
 /// ASSUMES VALID DDS DATA. Also, single mipmap only.
 /// </summary>
 /// <param name="rawDDSData">Standard DDS data but lacking header.</param>
 /// <param name="surfaceFormat">Surface format of DDS.</param>
 /// <param name="width">Width of image.</param>
 /// <param name="height">Height of image.</param>
 public ImageEngineImage(byte[] rawDDSData, ImageEngineFormat surfaceFormat, int width, int height)
 {
     Format = new Format(surfaceFormat);
     DDSGeneral.DDS_HEADER tempHeader = null;
     MipMaps = ImageEngine.LoadImage(rawDDSData, surfaceFormat, width, height, out tempHeader);
     header  = tempHeader;
 }
예제 #10
0
 /// <summary>
 /// Saves image to byte[].
 /// </summary>
 /// <param name="MipMaps">Mipmaps to save.</param>
 /// <param name="format">Format to save image as.</param>
 /// <param name="generateMips">Determines how to handle mipmaps.</param>
 /// <param name="desiredMaxDimension">Maximum dimension to allow. Resizes if required.</param>
 /// <param name="mipToSave">Mipmap to save. If > 0, all other mipmaps removed, and this mipmap saved.</param>
 /// <param name="mergeAlpha">True = Flattens alpha into RGB.</param>
 /// <returns>Byte[] containing fully formatted image.</returns>
 internal static byte[] Save(List <MipMap> MipMaps, ImageEngineFormat format, MipHandling generateMips, int desiredMaxDimension, int mipToSave, bool mergeAlpha)
 {
     using (MemoryStream ms = new MemoryStream())
     {
         Save(MipMaps, format, ms, generateMips, mergeAlpha, desiredMaxDimension, mipToSave);
         return(ms.ToArray());
     }
 }
예제 #11
0
 /// <summary>
 /// Builds a DDS image from an existing mipmap.
 /// </summary>
 /// <param name="mip">Mip to base image on.</param>
 /// <param name="DDSFormat">Format of mipmap.</param>
 public ImageEngineImage(MipMap mip, ImageEngineFormat DDSFormat)
 {
     Format  = new Format(DDSFormat);
     MipMaps = new List <MipMap>()
     {
         mip
     };
     header = DDSGeneral.Build_DDS_Header(1, mip.Height, mip.Width, DDSFormat);
 }
예제 #12
0
 /// <summary>
 /// Creates a DDS header from a set of information.
 /// </summary>
 /// <param name="Mips">Number of mipmaps.</param>
 /// <param name="Height">Height of top mipmap.</param>
 /// <param name="Width">Width of top mipmap.</param>
 /// <param name="surfaceformat">Format header represents.</param>
 /// <param name="customMasks">Custom user defined masks for colours.</param>
 public DDS_Header(int Mips, int Height, int Width, ImageEngineFormat surfaceformat, List<uint> customMasks = null)
 {
     dwSize = 124;
     dwFlags = DDSdwFlags.DDSD_CAPS | DDSdwFlags.DDSD_HEIGHT | DDSdwFlags.DDSD_WIDTH | DDSdwFlags.DDSD_PIXELFORMAT | (Mips != 1 ? DDSdwFlags.DDSD_MIPMAPCOUNT : 0);
     this.Width = Width;
     this.Height = Height;
     dwCaps = DDSdwCaps.DDSCAPS_TEXTURE | (Mips == 1 ? 0 : DDSdwCaps.DDSCAPS_COMPLEX | DDSdwCaps.DDSCAPS_MIPMAP);
     dwMipMapCount = Mips == 1 ? 1 : Mips;
     ddspf = new DDS_PIXELFORMAT(surfaceformat, customMasks);
 }
예제 #13
0
        /// <summary>
        /// Gets file extension of supported surface formats.
        /// Doesn't include preceding dot.
        /// </summary>
        /// <param name="format">Format to get file extension for.</param>
        /// <returns>File extension without dot.</returns>
        static string GetExtensionOfFormat(ImageEngineFormat format)
        {
            string formatString = format.ToString().ToLowerInvariant();

            if (formatString.Contains('_'))
            {
                formatString = "dds";
            }

            return(formatString);
        }
예제 #14
0
 static FourCC ParseFormatToFourCC(ImageEngineFormat format)
 {
     if (Enum.IsDefined(typeof(FourCC), (int)format))
     {
         return((FourCC)format);
     }
     else
     {
         return(FourCC.Unknown);
     }
 }
예제 #15
0
        /// <summary>
        /// Loads DdsImage from Data.
        /// </summary>
        public void LoadDds()
        {
            if (!EepkToolInterlop.LoadTextures)
            {
                return;
            }

            try
            {
                ddsIsLoading = true;
                byte[] data       = Data.ToArray();
                int    numMipMaps = 0;

                //PROBLEM: Most files load fine with DDSReader, but it CANT load files that are saved with CSharpImageLibrary.
                //CSharpImageLibrary may be able to load them on Win7/Win8 machines, but I cant test that...

                using (var ImageSource = new ImageEngineImage(data))
                {
                    DdsImage    = new WriteableBitmap(ImageSource.GetWPFBitmap());
                    ImageFormat = ImageSource.Format.SurfaceFormat;
                    numMipMaps  = ImageSource.NumMipMaps;
                }

                //If CSharpImageLibrary fails to load the image, then try DDSReader
                //IMPORTANT: DDSReader CANNOT load files saved by CSharpImageLibrary!
                //if (DdsImage == null || numMipMaps == 0)
                //{

                //    DDSReader.Utils.PixelFormat format;
                //    DdsImage = new WriteableBitmap(DDSReader.DDS.LoadImage(data, out format, true));
                //    ImageFormat = ImageEngineFormat.DDS_DXT5; //Default to DXT5

                //If DdsImage is still null, then the image has failed to load.
                //    if (DdsImage == null)
                //    {
                //        throw new InvalidDataException(string.Format("Unable to parse \"{0}\".", Name));
                //    }
                //}
            }
            catch
            {
                loadDdsFail = true;
            }
            finally
            {
                loadDds      = true;
                ddsIsLoading = false;
            }
        }
예제 #16
0
 public void UndoAnalysis(int newGameVersion)
 {
     wasAnalysed = false;
     Files.Clear();
     OriginalFiles.Clear();
     ExpIDs.Clear();
     OriginalExpIDs.Clear();
     found          = false;
     ExpectedFormat = ImageEngineFormat.Unknown;
     ExpectedMips   = 0;
     AutofixSuccess = true;
     FileDuplicates.Clear();
     TreeDuplicates.Clear();
     TexName     = null;
     GameVersion = newGameVersion;
 }
예제 #17
0
        /// <summary>
        /// Gets block size of DDS format.
        /// Number of channels if not compressed.
        /// 1 if not a DDS format.
        /// </summary>
        /// <param name="format">DDS format to test.</param>
        /// <param name="componentSize">Size of channel components in bytes. e.g. 16bit = 2.</param>
        /// <returns>Number of blocks/channels in format.</returns>
        static int GetBlockSize(ImageEngineFormat format, int componentSize = 1)
        {
            int blocksize = 1;

            switch (format)
            {
            case ImageEngineFormat.DDS_ATI1:
            case ImageEngineFormat.DDS_DXT1:
                blocksize = 8;
                break;

            case ImageEngineFormat.DDS_DXT2:
            case ImageEngineFormat.DDS_DXT3:
            case ImageEngineFormat.DDS_DXT4:
            case ImageEngineFormat.DDS_DXT5:
            case ImageEngineFormat.DDS_ATI2_3Dc:
            case ImageEngineFormat.DDS_DX10:
                blocksize = 16;
                break;

            case ImageEngineFormat.DDS_V8U8:
            case ImageEngineFormat.DDS_A8L8:
            case ImageEngineFormat.DDS_ARGB_4:
                blocksize = 2;
                break;

            case ImageEngineFormat.DDS_ARGB_8:
            case ImageEngineFormat.DDS_ABGR_8:
            case ImageEngineFormat.DDS_G16_R16:
                blocksize = 4;
                break;

            case ImageEngineFormat.DDS_RGB_8:
                blocksize = 3;
                break;

            case ImageEngineFormat.DDS_ARGB_32F:
                blocksize = 16;
                break;

            case ImageEngineFormat.DDS_CUSTOM:
                blocksize = 4 * componentSize;
                break;
            }
            return(blocksize);
        }
예제 #18
0
        internal static List <MipMap> LoadImage(byte[] rawDDSData, ImageEngineFormat surfaceFormat, int width, int height, out DDSGeneral.DDS_HEADER header)
        {
            header = DDSGeneral.Build_DDS_Header(1, height, width, surfaceFormat);
            List <MipMap> MipMaps = null;

            // Create new fully formatted DDS i.e. one with a header.
            MemoryStream stream = new MemoryStream();
            BinaryWriter bw     = new BinaryWriter(stream);

            DDSGeneral.Write_DDS_Header(header, bw);
            bw.Write(rawDDSData);

            switch (surfaceFormat)
            {
            case ImageEngineFormat.DDS_DXT1:
            case ImageEngineFormat.DDS_DXT2:
            case ImageEngineFormat.DDS_DXT3:
            case ImageEngineFormat.DDS_DXT4:
            case ImageEngineFormat.DDS_DXT5:
                if (WindowsWICCodecsAvailable)
                {
                    MipMaps = WIC_Codecs.LoadWithCodecs(stream, 0, 0, true);
                }
                else
                {
                    MipMaps = DDSGeneral.LoadDDS(stream, header, new Format(surfaceFormat), 0);
                }
                break;

            case ImageEngineFormat.DDS_ARGB:
            case ImageEngineFormat.DDS_A8L8:
            case ImageEngineFormat.DDS_RGB:
            case ImageEngineFormat.DDS_ATI1:
            case ImageEngineFormat.DDS_ATI2_3Dc:
            case ImageEngineFormat.DDS_G8_L8:
            case ImageEngineFormat.DDS_V8U8:
                MipMaps = DDSGeneral.LoadDDS(stream, header, new Format(surfaceFormat), 0);
                break;

            default:
                throw new InvalidDataException("Image format is unknown.");
            }
            bw.Dispose(); // Also disposes MemoryStream
            return(MipMaps);
        }
예제 #19
0
        /// <summary>
        /// Determines if format is a block compressed format.
        /// </summary>
        /// <param name="format">DDS Surface Format.</param>
        /// <returns>True if block compressed.</returns>
        static bool IsBlockCompressed(ImageEngineFormat format)
        {
            switch (format)
            {
            case ImageEngineFormat.DDS_ATI1:
            case ImageEngineFormat.DDS_DXT1:
            case ImageEngineFormat.DDS_DXT2:
            case ImageEngineFormat.DDS_DXT3:
            case ImageEngineFormat.DDS_DXT4:
            case ImageEngineFormat.DDS_DXT5:
            case ImageEngineFormat.DDS_ATI2_3Dc:
            case ImageEngineFormat.DDS_DX10:
                return(true);

            default:
                return(false);
            }
        }
        void DisableUnsupportedFormats(ComboBox box)
        {
            foreach (var item in box.Items)
            {
                var value = UsefulThings.WPF.EnumToItemsSource.GetValueBack(item);
                ImageEngineFormat selectedFormat = (ImageEngineFormat)value;
                bool disableContainer            = false;

                // Check supported save formats.
                if (ImageFormats.SaveUnsupported.Contains(selectedFormat))
                {
                    disableContainer = true;
                }

                if (disableContainer)
                {
                    var container = (ComboBoxItem)(box.ItemContainerGenerator.ContainerFromItem(item));
                    container.IsEnabled = false;
                }
            }
        }
예제 #21
0
 /// <summary>
 /// Saves image in specified format to stream.
 /// Stream position not reset before or after.
 /// </summary>
 /// <param name="destination">Stream to write to at current position.</param>
 /// <param name="format">Format to save to.</param>
 /// <param name="GenerateMips">Determines how mipmaps are handled during saving.</param>
 /// <param name="desiredMaxDimension">Maximum dimension of saved image. Keeps aspect.</param>
 /// <param name="mipToSave">Specifies a mipmap to save within the whole.</param>
 /// <param name="removeAlpha">True = removes alpha. False = Uses threshold value and alpha values to mask RGB FOR DXT1 ONLY, otherwise removes completely.</param>
 /// <param name="customMasks">Custom user defined masks for DDS colours.</param>
 public void Save(Stream destination, ImageEngineFormat format, MipHandling GenerateMips, int desiredMaxDimension = 0, int mipToSave = 0, bool removeAlpha = true, List<uint> customMasks = null)
 {
     var data = Save(format, GenerateMips, desiredMaxDimension, mipToSave, removeAlpha, customMasks);
     destination.Write(data, 0, data.Length);
 }
예제 #22
0
        /// <summary>
        /// Determines DDS Surface Format given the header.
        /// </summary>
        /// <param name="ddspf">DDS PixelFormat structure.</param>
        /// <returns>Friendly format.</returns>
        public static ImageEngineFormat DetermineDDSSurfaceFormat(DDS_Header.DDS_PIXELFORMAT ddspf)
        {
            ImageEngineFormat format = ParseFourCC(ddspf.dwFourCC);

            if (format == ImageEngineFormat.Unknown)
            {
                // Due to some previous settings, need to check these first.
                if (ddspf.dwABitMask <= 4 && ddspf.dwABitMask != 0 &&
                    ddspf.dwBBitMask <= 4 && ddspf.dwBBitMask != 0 &&
                    ddspf.dwGBitMask <= 4 && ddspf.dwGBitMask != 0 &&
                    ddspf.dwRBitMask <= 4 && ddspf.dwRBitMask != 0)
                {
                    format = ImageEngineFormat.DDS_CUSTOM;
                }


                // KFreon: Apparently all these flags mean it's a V8U8 image...
                else if (ddspf.dwRGBBitCount == 16 &&
                         ddspf.dwRBitMask == 0x00FF &&
                         ddspf.dwGBitMask == 0xFF00 &&
                         ddspf.dwBBitMask == 0x00 &&
                         ddspf.dwABitMask == 0x00 &&
                         (ddspf.dwFlags & DDS_PFdwFlags.DDPF_SIGNED) == DDS_PFdwFlags.DDPF_SIGNED)
                {
                    format = ImageEngineFormat.DDS_V8U8;
                }

                // KFreon: Test for L8/G8
                else if (ddspf.dwABitMask == 0 &&
                         ddspf.dwBBitMask == 0 &&
                         ddspf.dwGBitMask == 0 &&
                         ddspf.dwRBitMask == 0xFF &&
                         ddspf.dwFlags == DDS_PFdwFlags.DDPF_LUMINANCE &&
                         ddspf.dwRGBBitCount == 8)
                {
                    format = ImageEngineFormat.DDS_G8_L8;
                }

                // KFreon: A8L8. This can probably be something else as well, but it seems to work for now
                else if (ddspf.dwRGBBitCount == 16 &&
                         ddspf.dwFlags == (DDS_PFdwFlags.DDPF_ALPHAPIXELS | DDS_PFdwFlags.DDPF_LUMINANCE))
                {
                    format = ImageEngineFormat.DDS_A8L8;
                }

                // KFreon: G_R only.
                else if (((ddspf.dwFlags & DDS_PFdwFlags.DDPF_RGB) == DDS_PFdwFlags.DDPF_RGB && !((ddspf.dwFlags & DDS_PFdwFlags.DDPF_ALPHAPIXELS) == DDS_PFdwFlags.DDPF_ALPHAPIXELS)) &&
                         ddspf.dwABitMask == 0 &&
                         ddspf.dwBBitMask == 0 &&
                         ddspf.dwGBitMask != 0 &&
                         ddspf.dwRBitMask != 0)
                {
                    format = ImageEngineFormat.DDS_G16_R16;
                }

                // KFreon: RGB. RGB channels have something in them, but alpha doesn't.
                else if (((ddspf.dwFlags & DDS_PFdwFlags.DDPF_RGB) == DDS_PFdwFlags.DDPF_RGB && !((ddspf.dwFlags & DDS_PFdwFlags.DDPF_ALPHAPIXELS) == DDS_PFdwFlags.DDPF_ALPHAPIXELS)) &&
                         ddspf.dwABitMask == 0 &&
                         ddspf.dwBBitMask != 0 &&
                         ddspf.dwGBitMask != 0 &&
                         ddspf.dwRBitMask != 0)
                {
                    // TODO more formats?
                    if (ddspf.dwBBitMask == 31)
                    {
                        format = ImageEngineFormat.DDS_R5G6B5;
                    }
                    else
                    {
                        format = ImageEngineFormat.DDS_RGB_8;
                    }
                }

                // KFreon: RGB and A channels are present.
                else if (((ddspf.dwFlags & (DDS_PFdwFlags.DDPF_RGB | DDS_PFdwFlags.DDPF_ALPHAPIXELS)) == (DDS_PFdwFlags.DDPF_RGB | DDS_PFdwFlags.DDPF_ALPHAPIXELS)) ||
                         ddspf.dwABitMask != 0 &&
                         ddspf.dwBBitMask != 0 &&
                         ddspf.dwGBitMask != 0 &&
                         ddspf.dwRBitMask != 0)
                {
                    // TODO: Some more formats here?
                    format = ImageEngineFormat.DDS_ARGB_8;
                }

                // KFreon: If nothing else fits, but there's data in one of the bitmasks, assume it can be read.
                else if (ddspf.dwABitMask != 0 || ddspf.dwRBitMask != 0 || ddspf.dwGBitMask != 0 || ddspf.dwBBitMask != 0)
                {
                    format = ImageEngineFormat.DDS_CUSTOM;
                }
                else
                {
                    throw new FormatException("DDS Format is unknown.");
                }
            }

            return(format);
        }
예제 #23
0
 internal static int GetMipOffset(double mipIndex, ImageEngineFormat format, int baseWidth, int baseHeight)
 {
     // -1 because if we want the offset of the mip, it's the sum of all sizes before it NOT including itself.
     return GetCompressedSizeUpToIndex(mipIndex - 1, format, baseWidth, baseHeight);
 }
예제 #24
0
            /// <summary>
            /// Build PixelFormat sub-header for a specified surface format.
            /// </summary>
            /// <param name="surfaceFormat">Format to base PixelHeader on.</param>
            public DDS_PIXELFORMAT(ImageEngineFormat surfaceFormat) : this()
            {
                dwSize   = 32;
                dwFourCC = ParseFormatToFourCC(surfaceFormat);

                if (dwFourCC != FourCC.Unknown)
                {
                    dwFlags = DDS_PFdwFlags.DDPF_FOURCC;
                }

                switch (surfaceFormat)
                {
                    // Compressed formats don't need anything written here since pitch/linear size is unreliable. Why bother?
                    #region Uncompressed
                case ImageEngineFormat.DDS_G8_L8:
                    dwFlags      |= DDS_PFdwFlags.DDPF_LUMINANCE;
                    dwRGBBitCount = 8;
                    dwRBitMask    = 0xFF;
                    break;

                case ImageEngineFormat.DDS_ARGB_8:
                    dwFlags      |= DDS_PFdwFlags.DDPF_ALPHAPIXELS | DDS_PFdwFlags.DDPF_RGB;
                    dwRGBBitCount = 32;
                    dwABitMask    = 0xFF000000;
                    dwRBitMask    = 0x00FF0000;
                    dwGBitMask    = 0x0000FF00;
                    dwBBitMask    = 0x000000FF;
                    break;

                case ImageEngineFormat.DDS_ARGB_4:
                    dwFlags      |= DDS_PFdwFlags.DDPF_ALPHAPIXELS | DDS_PFdwFlags.DDPF_RGB;
                    dwRGBBitCount = 24;
                    dwABitMask    = 0xF000;
                    dwRBitMask    = 0x0F00;
                    dwGBitMask    = 0x00F0;
                    dwBBitMask    = 0x000F;
                    break;

                case ImageEngineFormat.DDS_V8U8:
                    dwFlags      |= DDS_PFdwFlags.DDPF_SIGNED;
                    dwRGBBitCount = 16;
                    dwRBitMask    = 0x00FF;
                    dwGBitMask    = 0xFF00;
                    break;

                case ImageEngineFormat.DDS_A8L8:
                    dwFlags      |= DDS_PFdwFlags.DDPF_LUMINANCE | DDS_PFdwFlags.DDPF_ALPHAPIXELS;
                    dwRGBBitCount = 16;
                    dwABitMask    = 0xFF00;
                    dwRBitMask    = 0x00FF;
                    break;

                case ImageEngineFormat.DDS_RGB_8:
                    dwFlags      |= DDS_PFdwFlags.DDPF_RGB;
                    dwRBitMask    = 0xFF0000;
                    dwGBitMask    = 0x00FF00;
                    dwBBitMask    = 0x0000FF;
                    dwRGBBitCount = 24;
                    break;

                case ImageEngineFormat.DDS_G16_R16:
                    dwFlags      |= DDS_PFdwFlags.DDPF_RGB;
                    dwGBitMask    = 0xFFFF0000;
                    dwRBitMask    = 0x0000FFFF;
                    dwRGBBitCount = 32;
                    break;

                case ImageEngineFormat.DDS_ABGR_8:
                    dwFlags      |= DDS_PFdwFlags.DDPF_ALPHAPIXELS | DDS_PFdwFlags.DDPF_RGB;
                    dwRGBBitCount = 32;
                    dwABitMask    = 0xFF000000;
                    dwBBitMask    = 0x00FF0000;
                    dwGBitMask    = 0x0000FF00;
                    dwRBitMask    = 0x000000FF;
                    break;

                case ImageEngineFormat.DDS_ARGB_32F:
                    dwFlags      |= DDS_PFdwFlags.DDPF_ALPHAPIXELS | DDS_PFdwFlags.DDPF_RGB;
                    dwRGBBitCount = 128;
                    dwABitMask    = 0;
                    dwRBitMask    = 0;
                    dwGBitMask    = 0;
                    dwBBitMask    = 0;
                    break;
                    #endregion Uncompressed
                }
            }
예제 #25
0
 static FourCC ParseFormatToFourCC(ImageEngineFormat format)
 {
     if (Enum.IsDefined(typeof(FourCC), (int)format))
         return (FourCC)format;
     else
         return FourCC.Unknown;
 }
예제 #26
0
            /// <summary>
            /// Details the given format.
            /// </summary>
            /// <param name="dxgiFormat">Optional DX10 format. Default = Unknown.</param>
            /// <param name="inFormat">Image Format.</param>
            public ImageEngineFormatDetails(ImageEngineFormat inFormat, Headers.DDS_Header.DXGI_FORMAT dxgiFormat = new Headers.DDS_Header.DXGI_FORMAT())
            {
                Format = inFormat;

                DX10Format = dxgiFormat;

                BitCount = 8;
                {
                    switch (inFormat)
                    {
                    case ImageEngineFormat.DDS_G8_L8:
                    case ImageEngineFormat.DDS_A8:
                    case ImageEngineFormat.DDS_ATI1:
                        BitCount = 8;
                        break;

                    case ImageEngineFormat.DDS_A8L8:
                    case ImageEngineFormat.DDS_V8U8:
                    case ImageEngineFormat.DDS_ATI2_3Dc:
                        BitCount = 16;
                        break;

                    case ImageEngineFormat.BMP:
                    case ImageEngineFormat.DDS_ABGR_8:
                    case ImageEngineFormat.DDS_ARGB_8:
                    case ImageEngineFormat.GIF:
                    case ImageEngineFormat.PNG:
                    case ImageEngineFormat.TGA:
                    case ImageEngineFormat.TIF:
                    case ImageEngineFormat.DDS_DXT1:
                    case ImageEngineFormat.DDS_DXT2:
                    case ImageEngineFormat.DDS_DXT3:
                    case ImageEngineFormat.DDS_DXT4:
                    case ImageEngineFormat.DDS_DXT5:
                    case ImageEngineFormat.DDS_G16_R16:
                        BitCount = 32;
                        break;

                    case ImageEngineFormat.JPG:
                    case ImageEngineFormat.DDS_RGB_8:
                        BitCount = 24;
                        break;

                    case ImageEngineFormat.DDS_ARGB_32F:
                        BitCount = 128;
                        break;

                    case ImageEngineFormat.DDS_R5G6B5:
                        BitCount = 16;
                        break;

                    case ImageEngineFormat.DDS_ARGB_4:
                    case ImageEngineFormat.DDS_CUSTOM:
                    case ImageEngineFormat.DDS_DX10:
                        BitCount = GetDX10BitCount(DX10Format);
                        break;
                    }
                }

                // Functions
                ReadByte          = ReadByteFromByte;
                ReadUShort        = ReadUShortFromByte;
                ReadFloat         = ReadFloatFromByte;
                SetMaxValue       = WriteByteMax;
                WriteColour       = WriteByte;
                ReadUShortAsArray = ReadUShortFromByteAsArray;
                ReadFloatAsArray  = ReadFloatFromByteOrUShortAsArray;

                if (ComponentSize == 2)
                {
                    ReadByte          = ReadByteFromUShort;
                    ReadUShort        = ReadUShortFromUShort;
                    ReadFloat         = ReadFloatFromUShort;
                    SetMaxValue       = WriteUShortMax;
                    WriteColour       = WriteUShort;
                    ReadUShortAsArray = ReadUShortFromUShortAsArray;
                    // Don't need ReadFloatAsArray set here, as it's shared between byte and ushort reading.
                }
                else if (ComponentSize == 4)
                {
                    ReadByte          = ReadByteFromFloat;
                    ReadUShort        = ReadUShortFromFloat;
                    ReadFloat         = ReadFloatFromFloat;
                    SetMaxValue       = WriteFloatMax;
                    WriteColour       = WriteFloat;
                    ReadUShortAsArray = ReadUShortFromFloatAsArray;
                    ReadFloatAsArray  = ReadFloatFromFloatAsArray;
                }


                switch (inFormat)
                {
                case ImageEngineFormat.DDS_ATI1:
                    BlockEncoder = DDS_Encoders.CompressBC4Block;
                    break;

                case ImageEngineFormat.DDS_ATI2_3Dc:
                    BlockEncoder = DDS_Encoders.CompressBC5Block;
                    break;

                case ImageEngineFormat.DDS_DX10:
                    if (DX10Format.ToString().Contains("BC7"))
                    {
                        BlockEncoder = DDS_Encoders.CompressBC7Block;
                    }
                    else
                    {
                        BlockEncoder = DDS_Encoders.CompressBC6Block;
                    }
                    break;

                case ImageEngineFormat.DDS_DXT1:
                    BlockEncoder = DDS_Encoders.CompressBC1Block;
                    break;

                case ImageEngineFormat.DDS_DXT2:
                case ImageEngineFormat.DDS_DXT3:
                    BlockEncoder = DDS_Encoders.CompressBC2Block;
                    break;

                case ImageEngineFormat.DDS_DXT4:
                case ImageEngineFormat.DDS_DXT5:
                    BlockEncoder = DDS_Encoders.CompressBC3Block;
                    break;
                }

                switch (inFormat)
                {
                case ImageEngineFormat.DDS_DXT1:
                    BlockDecoder = DDS_Decoders.DecompressBC1Block;
                    break;

                case ImageEngineFormat.DDS_DXT2:
                case ImageEngineFormat.DDS_DXT3:
                    BlockDecoder = DDS_Decoders.DecompressBC2Block;
                    break;

                case ImageEngineFormat.DDS_DXT4:
                case ImageEngineFormat.DDS_DXT5:
                    BlockDecoder = DDS_Decoders.DecompressBC3Block;
                    break;

                case ImageEngineFormat.DDS_ATI1:
                    BlockDecoder = DDS_Decoders.DecompressATI1Block;
                    break;

                case ImageEngineFormat.DDS_ATI2_3Dc:
                    BlockDecoder = DDS_Decoders.DecompressATI2Block;
                    break;

                case ImageEngineFormat.DDS_DX10:
                    if (DX10Format.ToString().Contains("BC7"))
                    {
                        BlockDecoder = DDS_Decoders.DecompressBC7Block;
                    }
                    else
                    {
                        BlockDecoder = DDS_Decoders.DecompressBC6Block;
                    }
                    break;
                }
            }
예제 #27
0
        internal static byte[] SaveWithCodecs(byte[] imageData, ImageEngineFormat format, int width, int height, AlphaSettings alphaSetting)
        {
            var image = UsefulThings.WPF.Images.CreateWriteableBitmap(imageData, width, height);
            image.Freeze();
            BitmapFrame frame = null;

            if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
                frame = BitmapFrame.Create(new FormatConvertedBitmap(image, PixelFormats.Bgr32, image.Palette, 0));
            else
                frame = BitmapFrame.Create(image);

            frame.Freeze();

            // KFreon: Choose encoder based on desired format.
            BitmapEncoder encoder = null;
            int estimatedImageSize = 0;

            int estimateHeaderSize = 1024;
            switch (format)
            {
                case ImageEngineFormat.BMP:
                    encoder = new BmpBitmapEncoder();
                    estimatedImageSize = estimateHeaderSize + width * height * 4;  // Fairly good estimation
                    break;
                case ImageEngineFormat.JPG:
                    encoder = new JpegBitmapEncoder();
                    ((JpegBitmapEncoder)encoder).QualityLevel = JPGCompressionSetting;
                    estimatedImageSize = estimateHeaderSize + width * height / 6;  // Estimation
                    break;
                case ImageEngineFormat.PNG:
                    encoder = new PngBitmapEncoder();
                    estimatedImageSize = estimateHeaderSize + width * height / 2;  // Estimation
                    break;
                case ImageEngineFormat.GIF:
                    encoder = new GifBitmapEncoder();
                    estimatedImageSize = estimateHeaderSize + width * height / 5;  // Estimation
                    break;
                case ImageEngineFormat.TIF:
                    encoder = new TiffBitmapEncoder();
                    estimatedImageSize = estimateHeaderSize + width * height; // Esimation
                    break;
                default:
                    throw new InvalidOperationException($"Unable to encode format: {format} using Windows 8.1 Codecs.");
            }

            encoder.Frames.Add(frame);
            using (MemoryStream ms = new MemoryStream(estimatedImageSize))  // Big enough to reduce memory copying.
            {
                encoder.Save(ms);
                return ms.ToArray();
            }
        }
예제 #28
0
 internal static int GetCompressedSizeOfImage(int mipCount, ImageEngineFormat format, int baseWidth, int baseHeight)
 {
     return GetCompressedSizeUpToIndex(mipCount - 1, format, baseWidth, baseHeight);
 }
예제 #29
0
        private MemoryStream buildDdsImage(int mipMapIndex, out ImageEngineFormat imageFormat)
        {
            DomainPropertyByteValue formatProp = PropertyHeader.GetProperty("Format").FirstOrDefault()?.Value as DomainPropertyByteValue;

            imageFormat = ImageEngineFormat.Unknown;

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

            string format = formatProp.PropertyString.Replace("PF_", null);

            switch (format)
            {
            case "DXT1":
            {
                imageFormat = ImageEngineFormat.DDS_DXT1;

                break;
            }

            case "DXT5":
            {
                imageFormat = ImageEngineFormat.DDS_DXT5;

                break;
            }

            case "G8":
            {
                imageFormat = ImageEngineFormat.DDS_G8_L8;

                break;
            }

            case "A8R8G8B8":
            {
                imageFormat = ImageEngineFormat.DDS_ARGB;

                break;
            }

            default:
            {
                return(null);
            }
            }

            DomainMipMap mipMap = MipMaps[mipMapIndex];

            DDSGeneral.DDS_HEADER header = DDSGeneral.Build_DDS_Header(0, mipMap.Height, mipMap.Width, imageFormat);

            MemoryStream stream = new MemoryStream();

            BinaryWriter writer = new BinaryWriter(stream);

            DDSGeneral.Write_DDS_Header(header, writer);

            stream.Write(mipMap.ImageData, 0, mipMap.ImageData.Length);

            stream.Flush();

            stream.Position = 0;

            return(stream);
        }
예제 #30
0
 /// <summary>
 /// Saves fully formatted image in specified format to stream.
 /// </summary>
 /// <param name="destination">Stream to save to.</param>
 /// <param name="format">Format to save as.</param>
 /// <param name="GenerateMips">Determines how mipmaps are handled during saving.</param>
 /// <param name="desiredMaxDimension">Maximum size for saved image. Resizes if required, but uses mipmaps if available.</param>
 /// <param name="mergeAlpha">ONLY valid when desiredMaxDimension != 0. True = alpha flattened, directly affecting RGB.</param>
 /// <param name="mipToSave">Selects a certain mip to save. 0 based.</param>
 /// <returns>True if success</returns>
 public bool Save(Stream destination, ImageEngineFormat format, MipHandling GenerateMips, int desiredMaxDimension = 0, int mipToSave = 0, bool mergeAlpha = false)
 {
     return(ImageEngine.Save(MipMaps, format, destination, GenerateMips, mergeAlpha, desiredMaxDimension, mipToSave));
 }
예제 #31
0
        /// <summary>
        /// Save mipmaps as given format to stream.
        /// </summary>
        /// <param name="MipMaps">List of Mips to save.</param>
        /// <param name="format">Desired format.</param>
        /// <param name="destination">Stream to save to.</param>
        /// <param name="mipChoice">Determines how to handle mipmaps.</param>
        /// <param name="maxDimension">Maximum value for either image dimension.</param>
        /// <param name="mergeAlpha">True = alpha flattened down, directly affecting RGB.</param>
        /// <param name="mipToSave">0 based index on which mipmap to make top of saved image.</param>
        /// <returns>True on success.</returns>
        internal static bool Save(List <MipMap> MipMaps, ImageEngineFormat format, Stream destination, MipHandling mipChoice, bool mergeAlpha, int maxDimension = 0, int mipToSave = 0)
        {
            Format        temp    = new Format(format);
            List <MipMap> newMips = new List <MipMap>(MipMaps);

            if ((temp.IsMippable && mipChoice == MipHandling.GenerateNew) || (temp.IsMippable && newMips.Count == 1 && mipChoice == MipHandling.Default))
            {
                DDSGeneral.BuildMipMaps(newMips, mergeAlpha);
            }

            // KFreon: Resize if asked
            if (maxDimension != 0 && maxDimension < newMips[0].Width && maxDimension < newMips[0].Height)
            {
                if (!UsefulThings.General.IsPowerOfTwo(maxDimension))
                {
                    throw new ArgumentException($"{nameof(maxDimension)} must be a power of 2. Got {nameof(maxDimension)} = {maxDimension}");
                }


                // KFreon: Check if there's a mipmap suitable, removes all larger mipmaps
                var validMipmap = newMips.Where(img => (img.Width == maxDimension && img.Height <= maxDimension) || (img.Height == maxDimension && img.Width <= maxDimension));  // Check if a mip dimension is maxDimension and that the other dimension is equal or smaller
                if (validMipmap?.Count() != 0)
                {
                    int index = newMips.IndexOf(validMipmap.First());
                    newMips.RemoveRange(0, index);
                }
                else
                {
                    // KFreon: Get the amount the image needs to be scaled. Find largest dimension and get it's scale.
                    double scale = maxDimension * 1f / (newMips[0].Width > newMips[0].Height ? newMips[0].Width: newMips[0].Height);

                    // KFreon: No mip. Resize.
                    newMips[0] = Resize(newMips[0], scale, mergeAlpha);
                }
            }

            // KFreon: Ensure we have a power of two for dimensions
            double fixScale = 0;

            if (!UsefulThings.General.IsPowerOfTwo(newMips[0].Width) || !UsefulThings.General.IsPowerOfTwo(newMips[0].Height))
            {
                int newWidth = UsefulThings.General.RoundToNearestPowerOfTwo(newMips[0].Width);
                int newHeigh = UsefulThings.General.RoundToNearestPowerOfTwo(newMips[0].Height);

                // KFreon: Assuming same scale in both dimensions...
                fixScale = 1.0 * newWidth / newMips[0].Width;

                newMips[0] = Resize(newMips[0], fixScale, mergeAlpha);
            }


            if (fixScale != 0 || mipChoice == MipHandling.KeepTopOnly)
            {
                DestroyMipMaps(newMips, mipToSave);
            }

            if (fixScale != 0 && temp.IsMippable && mipChoice != MipHandling.KeepTopOnly)
            {
                DDSGeneral.BuildMipMaps(newMips, mergeAlpha);
            }


            bool result = false;

            if (temp.SurfaceFormat.ToString().Contains("DDS"))
            {
                result = DDSGeneral.Save(newMips, destination, temp);
            }
            else
            {
                // KFreon: Try saving with built in codecs
                var mip = newMips[0];
                if (WindowsWICCodecsAvailable)
                {
                    result = WIC_Codecs.SaveWithCodecs(mip.BaseImage, destination, format);
                }
            }

            if (mipChoice != MipHandling.KeepTopOnly && temp.IsMippable)
            {
                // KFreon: Necessary. Must be how I handle the lowest mip levels. i.e. WRONGLY :(
                // Figure out how big the file should be and make it that size

                int size   = 0;
                int width  = newMips[0].Width;
                int height = newMips[0].Height;

                int divisor = 1;
                if (temp.IsBlockCompressed)
                {
                    divisor = 4;
                }

                while (width >= 1 && height >= 1)
                {
                    int tempWidth  = width;
                    int tempHeight = height;

                    if (temp.IsBlockCompressed)
                    {
                        if (tempWidth < 4)
                        {
                            tempWidth = 4;
                        }
                        if (tempHeight < 4)
                        {
                            tempHeight = 4;
                        }
                    }


                    size   += tempWidth / divisor * tempHeight / divisor * temp.BlockSize;
                    width  /= 2;
                    height /= 2;
                }

                if (size > destination.Length - 128)
                {
                    byte[] blanks = new byte[size - (destination.Length - 128)];
                    destination.Write(blanks, 0, blanks.Length);
                }
            }

            return(result);
        }
예제 #32
0
        internal static byte[] Save(List<MipMap> mipMaps, ImageEngineFormat saveFormat, AlphaSettings alphaSetting, List<uint> customMasks = null)
        {
            // Set compressor for Block Compressed textures
            Action<byte[], int, int, byte[], int, AlphaSettings> compressor = null;

            bool needCheckSize = saveFormat.ToString().Contains("DXT") || saveFormat.ToString().Contains("ATI");

            switch (saveFormat)
            {
                case ImageEngineFormat.DDS_ATI1:
                    compressor = DDS_Encoders.CompressBC4Block;
                    break;
                case ImageEngineFormat.DDS_ATI2_3Dc:
                    compressor = DDS_Encoders.CompressBC5Block;
                    break;
                case ImageEngineFormat.DDS_DX10:
                    Debugger.Break();
                    break; // TODO: NOT SUPPORTED YET. DX10
                case ImageEngineFormat.DDS_DXT1:
                    compressor = DDS_Encoders.CompressBC1Block;
                    break;
                case ImageEngineFormat.DDS_DXT2:
                case ImageEngineFormat.DDS_DXT3:
                    compressor = DDS_Encoders.CompressBC2Block;
                    break;
                case ImageEngineFormat.DDS_DXT4:
                case ImageEngineFormat.DDS_DXT5:
                    compressor = DDS_Encoders.CompressBC3Block;
                    break;
            }

            int height = mipMaps[0].Height;
            int width = mipMaps[0].Width;

            if (needCheckSize && !CheckSize_DXT(width, height))
                throw new InvalidOperationException($"DXT compression formats require dimensions to be multiples of 4. Got: {width}x{height}.");

            int fullSize = GetCompressedSizeOfImage(mipMaps.Count, saveFormat, width, height);
            // +1 to get the full size, not just the offset of the last mip.
            //int fullSize = GetMipOffset(mipMaps.Count + 1, saveFormat, mipMaps[0].Width, mipMaps[0].Height);

            byte[] destination = new byte[fullSize];

            // Create header and write to destination
            DDS_Header header = new DDS_Header(mipMaps.Count, height, width, saveFormat, customMasks);
            header.WriteToArray(destination, 0);

            int blockSize = ImageFormats.GetBlockSize(saveFormat);

            if (ImageFormats.IsBlockCompressed(saveFormat))
            {
                int mipOffset = 128;
                foreach (MipMap mipmap in mipMaps)
                    mipOffset = WriteCompressedMipMap(destination, mipOffset, mipmap, blockSize, compressor, alphaSetting);
            }
            else
            {
                // UNCOMPRESSED
                var action = new Action<int>(mipIndex =>
                {
                    if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
                    {
                        // Remove alpha by setting AMask = 0
                        var ddspf = header.ddspf;
                        ddspf.dwABitMask = 0;
                        header.ddspf = ddspf;
                    }

                    // Get MipOffset
                    int offset = GetMipOffset(mipIndex, saveFormat, width, height);

                    WriteUncompressedMipMap(destination, offset, mipMaps[mipIndex], saveFormat, header.ddspf);
                });

                if (ImageEngine.EnableThreading)
                    Parallel.For(0, mipMaps.Count, new ParallelOptions { MaxDegreeOfParallelism = ImageEngine.NumThreads }, action);
                else
                    for (int i = 0; i < mipMaps.Count; i++)
                        action(i);
            }

            return destination;
        }
예제 #33
0
 static int WriteUncompressedMipMap(byte[] destination, int mipOffset, MipMap mipmap, ImageEngineFormat saveFormat, DDS_Header.DDS_PIXELFORMAT ddspf)
 {
     return DDS_Encoders.WriteUncompressed(mipmap.Pixels, destination, mipOffset, ddspf);
 }
예제 #34
0
 /// <summary>
 /// Calculates the compressed size of an image with given parameters.
 /// </summary>
 /// <param name="numMipmaps">Number of mipmaps in image. JPG etc only have 1.</param>
 /// <param name="format">Format of image.</param>
 /// <param name="width">Width of image (top mip if mip-able)</param>
 /// <param name="height">Height of image (top mip if mip-able)</param>
 /// <returns>Size of compressed image.</returns>
 public static int GetCompressedSize(int numMipmaps, ImageEngineFormat format, int width, int height)
 {
     return DDS.DDSGeneral.GetCompressedSizeOfImage(numMipmaps, format, width, height);
 }
예제 #35
0
 /// <summary>
 /// Gets block size of DDS format.
 /// Number of channels if not compressed.
 /// 1 if not a DDS format.
 /// </summary>
 /// <param name="format">DDS format to test.</param>
 /// <returns>Number of blocks/channels in format.</returns>
 public static int GetBlockSize(ImageEngineFormat format)
 {
     int blocksize = 1;
     switch (format)
     {
         case ImageEngineFormat.DDS_ATI1:
         case ImageEngineFormat.DDS_DXT1:
             blocksize = 8;
             break;
         case ImageEngineFormat.DDS_DXT2:
         case ImageEngineFormat.DDS_DXT3:
         case ImageEngineFormat.DDS_DXT4:
         case ImageEngineFormat.DDS_DXT5:
         case ImageEngineFormat.DDS_ATI2_3Dc:
             blocksize = 16;
             break;
         case ImageEngineFormat.DDS_V8U8:
         case ImageEngineFormat.DDS_A8L8:
             blocksize = 2;
             break;
         case ImageEngineFormat.DDS_ARGB:
             blocksize = 4;
             break;
         case ImageEngineFormat.DDS_RGB:
             blocksize = 3;
             break;
         case ImageEngineFormat.DDS_CUSTOM:
             blocksize = 4;
             break;
     }
     return blocksize;
 }
예제 #36
0
 public static string StringifyFormat(ImageEngineFormat format)
 {
     return(format.ToString().Replace("DDS_", "").Replace("_3Dc", ""));
 }
예제 #37
0
        internal static int GetCompressedSizeUpToIndex(double mipIndex, ImageEngineFormat format, int baseWidth, int baseHeight)
        {
            /*
                Mipmapping halves both dimensions per mip down. Dimensions are then divided by 4 if block compressed as a texel is 4x4 pixels.
                e.g. 4096 x 4096 block compressed texture with 8 byte blocks e.g. DXT1
                Sizes of mipmaps:
                    4096 / 4 x 4096 / 4 x 8
                    (4096 / 4 / 2) x (4096 / 4 / 2) x 8
                    (4096 / 4 / 2 / 2) x (4096 / 4 / 2 / 2) x 8

                Pattern: Each dimension divided by 2 per mip size decreased.
                Thus, total is divided by 4.
                    Size of any mip = Sum(1/4^n) x divWidth x divHeight x blockSize,
                        where n is the desired mip (0 based),
                        divWidth and divHeight are the block compress adjusted dimensions (uncompressed textures lead to just original dimensions, block compressed are divided by 4)

                Turns out the partial sum of the infinite sum: Sum(1/4^n) = 1/3 x (4 - 4^-n). Who knew right?
            */

            // TODO: DDS going down past 4x4

            double divisor = 1;
            if (ImageFormats.IsBlockCompressed(format))
                divisor = 4;

            double shift = 1d / (4 << (int)(2 * (mipIndex - 1)));

            if (mipIndex == 0)
                shift = 1d;
            else if (mipIndex == -1)
                shift = 4d;

            double sumPart = mipIndex == -1 ? 0 :
                (1d / 3d) * (4d - shift);   // Shifting represents 4^-mipIndex. Math.Pow seems slow.

            double totalSize = 128 + (sumPart * ImageFormats.GetBlockSize(format) * (baseWidth / divisor) * (baseHeight / divisor));

            return (int)totalSize;
        }
예제 #38
0
        public void replaceImage(string strImgSize, ImageFile im, string archiveDir)
        {
            ImageSize imgSize = ImageSize.stringToSize(strImgSize);

            if (!imgList.Exists(img => img.imgSize == imgSize))
            {
                throw new FileNotFoundException("Image with resolution " + imgSize + " isn't found");
            }

            int       imageIdx = privateImageList.FindIndex(img => img.imgSize == imgSize);
            ImageInfo imgInfo  = privateImageList[imageIdx];

            ImageFile         imgFile       = im;
            ImageEngineFormat imgFileFormat = Textures.Methods.ParseFormat(imgFile.format);


            // check if images have same format type
            if (texFormat != imgFileFormat)
            {
                bool res = KFreonLib.Misc.Methods.DisplayYesNoDialogBox("Warning, replacing image has format " + imgFile.subtype() + " while original has " + texFormat + ", would you like to replace it anyway?", "Warning, different image format found");
                if (res)
                {
                    imgFile.format = Textures.Methods.StringifyFormat(texFormat);
                }
                else
                {
                    return;
                }
                //throw new FormatException("Different image format, original is " + texFormat + ", new is " + imgFile.subtype());
            }

            byte[] imgBuffer;

            // if the image is empty then recover the archive compression from the image list
            if (imgInfo.storageType == storage.empty)
            {
                imgInfo.storageType = privateImageList.Find(img => img.storageType != storage.empty && img.storageType != storage.pccSto).storageType;
                imgInfo.uncSize     = imgFile.resize().Length;
                imgInfo.cprSize     = imgFile.resize().Length;
            }

            switch (imgInfo.storageType)
            {
            case storage.arcCpr:
            case storage.arcUnc:
                string archivePath = archiveDir + "\\" + arcName + ".tfc";
                if (!File.Exists(archivePath))
                {
                    throw new FileNotFoundException("Texture archive not found in " + archivePath);
                }

                if (getFileFormat() == ".tga")
                {
                    imgBuffer = imgFile.resize();     // shrink image to essential data
                }
                else
                {
                    imgBuffer = imgFile.imgData;
                }

                if (imgBuffer.Length != imgInfo.uncSize)
                {
                    throw new FormatException("image sizes do not match, original is " + imgInfo.uncSize + ", new is " + imgBuffer.Length);
                }

                using (FileStream archiveStream = new FileStream(archivePath, FileMode.Append, FileAccess.Write))
                {
                    int newOffset = (int)archiveStream.Position;

                    if (imgInfo.storageType == storage.arcCpr)
                    {
                        imgBuffer = ZBlock.Compress(imgBuffer);

                        /*byte[] compressed = ZBlock.Compress(imgBuffer);
                         * archiveStream.Write(compressed, 0, compressed.Length);*/
                        imgInfo.cprSize = imgBuffer.Length;
                    }
                    //else
                    archiveStream.Write(imgBuffer, 0, imgBuffer.Length);

                    imgInfo.offset = newOffset;
                }
                break;

            case storage.pccSto:
                imgBuffer = imgFile.imgData;     // copy image data as-is
                if (imgBuffer.Length != imgInfo.uncSize)
                {
                    throw new FormatException("image sizes do not match, original is " + imgInfo.uncSize + ", new is " + imgBuffer.Length);
                }

                using (MemoryStream dataStream = new MemoryStream(imageData))
                {
                    dataStream.Seek(imgInfo.offset, SeekOrigin.Begin);
                    dataStream.Write(imgBuffer, 0, imgBuffer.Length);
                }

                break;
            }

            imgList[imageIdx] = imgInfo;
        }
예제 #39
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);
                }
            }
        }
예제 #40
0
        /// <summary>
        /// Saves fully formatted image in specified format to byte array.
        /// </summary>
        /// <param name="format">Format to save as.</param>
        /// <param name="GenerateMips">Determines how mipmaps are handled during saving.</param>
        /// <param name="desiredMaxDimension">Maximum size for saved image. Resizes if required, but uses mipmaps if available.</param>
        /// <param name="mipToSave">Index of mipmap to save directly.</param>
        /// <param name="removeAlpha">True = Alpha removed. False = Uses threshold value and alpha values to mask RGB FOR DXT1, otherwise completely removed.</param>
        /// <param name="customMasks">Custom user defined masks for colours.</param>
        /// <returns></returns>
        public byte[] Save(ImageEngineFormat format, MipHandling GenerateMips, int desiredMaxDimension = 0, int mipToSave = 0, bool removeAlpha = true, List<uint> customMasks = null)
        {
            if (format == ImageEngineFormat.Unknown)
                throw new InvalidOperationException("Save format cannot be 'Unknown'");

            AlphaSettings alphaSetting = AlphaSettings.KeepAlpha;
            if (removeAlpha)
                alphaSetting = AlphaSettings.RemoveAlphaChannel;
            else if (format == ImageEngineFormat.DDS_DXT2 || format == ImageEngineFormat.DDS_DXT4)
                alphaSetting = AlphaSettings.Premultiply;

            return ImageEngine.Save(MipMaps, format, GenerateMips, alphaSetting, desiredMaxDimension, mipToSave, customMasks);
        }
예제 #41
0
 /// <summary>
 /// Determines if given format supports mipmapping.
 /// </summary>
 /// <param name="format">Image format to check.</param>
 /// <returns></returns>
 static bool IsFormatMippable(ImageEngineFormat format)
 {
     return(format.ToString().Contains("DDS"));
 }
예제 #42
0
        /// <summary>
        /// Updates current texture object from tree.
        /// </summary>
        /// <param name="treeInd">Index of texture in tree.</param>
        /// <param name="treetex">Tree texture object to get info from.</param>
        public void UpdateTex(int treeInd, TreeTexInfo treetex)
        {
            found = true;
            TreeInd = treeInd;
            TexName = treetex.TexName;

            // KFreon: Reorder files so DLC isn't first
            /*List<string> files = new List<string>(treetex.Files);
            List<int> ids = new List<int>(treetex.ExpIDs);

            int count = files.Count;
            int index = -1;

            if (files[0].Contains("DLC"))
                for (int i = 0; i < count; i++)
                    if (!files[i].Contains("DLC"))
                    {
                        index = i;
                        break;
                    }

            if (index != -1)
            {
                string thing = files[index];
                files.RemoveAt(index);
                files.Insert(0, thing);

                int thing2 = ids[index];
                ids.RemoveAt(index);
                ids.Insert(0, thing2);
            }

            Files.AddRange(files);
            ExpIDs.AddRange(ids);*/
            Files.AddRange(treetex.Files);
            ExpIDs.AddRange(treetex.ExpIDs);


            
            List<PCCExpID> things = new List<PCCExpID>();

            for (int i = 0; i < Files.Count; i++)
                things.Add(new PCCExpID(Files[i], ExpIDs[i]));


            // KFreon: Reorder ME1 files
            if (GameVersion == 1)
            {
                things = things.OrderByDescending(t => t.file.Length).ToList();

                Files.Clear();
                ExpIDs.Clear();

                foreach (var item in things)
                {
                    Files.Add(item.file);
                    ExpIDs.Add(item.expid);
                }
            }

            //ExpIDs.AddRange(treetex.ExpIDs);

            OriginalFiles = new List<string>(Files);
            OriginalExpIDs = new List<int>(ExpIDs);

            ExpectedMips = treetex.NumMips;
            ExpectedFormat = treetex.Format;

            // KFreon: File Dups
            List<TPFTexInfo> dups = new List<TPFTexInfo>(FileDuplicates);
            FileDuplicates.Clear();
            foreach (TPFTexInfo tex in dups)
            {
                TPFTexInfo texn = tex;
                texn.found = true;
                texn.TreeInd = TreeInd;
                texn.TexName = treetex.TexName;

                texn.Files.AddRange(treetex.Files);
                texn.ExpIDs.AddRange(treetex.ExpIDs);

                texn.ExpectedFormat = treetex.Format;
                texn.ExpectedMips = treetex.NumMips;

                texn.OriginalExpIDs = new List<int>(ExpIDs);
                texn.OriginalFiles = new List<string>(Files);

                FileDuplicates.Add(texn);
            }

            ValidDimensions = ValidateDimensions(treetex);
        }
예제 #43
0
 public void UndoAnalysis(int newGameVersion)
 {
     wasAnalysed = false;
     Files.Clear();
     OriginalFiles.Clear();
     ExpIDs.Clear();
     OriginalExpIDs.Clear();
     found = false;
     ExpectedFormat = ImageEngineFormat.Unknown;
     ExpectedMips = 0;
     AutofixSuccess = true;
     FileDuplicates.Clear();
     TreeDuplicates.Clear();
     TexName = null;
     GameVersion = newGameVersion;
 }
예제 #44
0
 public static string StringifyFormat(ImageEngineFormat format)
 {
     return format.ToString().Replace("DDS_", "").Replace("_3Dc","");
 }
예제 #45
0
        /// <summary>
        /// Gets file extension of supported surface formats.
        /// Doesn't include preceding dot.
        /// </summary>
        /// <param name="format">Format to get file extension for.</param>
        /// <returns>File extension without dot.</returns>
        public static string GetExtensionOfFormat(ImageEngineFormat format)
        {
            string formatString = format.ToString().ToLowerInvariant();
            if (formatString.Contains('_'))
                formatString = "dds";

            return formatString;
        }
예제 #46
0
            /// <summary>
            /// Build PixelFormat sub-header for a specified surface format.
            /// </summary>
            /// <param name="surfaceFormat">Format to base PixelHeader on.</param>
            /// <param name="customMasks">Custom user defined masks for colours.</param>
            public DDS_PIXELFORMAT(ImageEngineFormat surfaceFormat, List<uint> customMasks = null)
                : this()
            {
                dwSize = 32;
                dwFourCC = ParseFormatToFourCC(surfaceFormat);

                if (dwFourCC != FourCC.Unknown)
                    dwFlags = DDS_PFdwFlags.DDPF_FOURCC;

                switch (surfaceFormat)
                {
                    // Compressed formats don't need anything written here since pitch/linear size is unreliable. Why bother?
                    #region Uncompressed
                    case ImageEngineFormat.DDS_G8_L8:
                        dwFlags = DDS_PFdwFlags.DDPF_LUMINANCE;
                        dwRGBBitCount = 8;
                        dwRBitMask = 0xFF;
                        break;
                    case ImageEngineFormat.DDS_ARGB:
                        dwFlags = DDS_PFdwFlags.DDPF_ALPHAPIXELS | DDS_PFdwFlags.DDPF_RGB;
                        dwRGBBitCount = 32;
                        dwABitMask = 0xFF000000;
                        dwRBitMask = 0x00FF0000;
                        dwGBitMask = 0x0000FF00;
                        dwBBitMask = 0x000000FF;
                        break;
                    case ImageEngineFormat.DDS_V8U8:
                        dwFlags = DDS_PFdwFlags.DDPF_SIGNED;
                        dwRGBBitCount = 16;
                        dwRBitMask = 0x00FF;
                        dwGBitMask = 0xFF00;
                        break;
                    case ImageEngineFormat.DDS_A8L8:
                        dwFlags = DDS_PFdwFlags.DDPF_LUMINANCE | DDS_PFdwFlags.DDPF_ALPHAPIXELS;
                        dwRGBBitCount = 16;
                        dwABitMask = 0xFF00;
                        dwRBitMask = 0x00FF;
                        break;
                    case ImageEngineFormat.DDS_RGB:
                        dwFlags = DDS_PFdwFlags.DDPF_RGB;
                        dwRBitMask = 0xFF0000;
                        dwGBitMask = 0x00FF00;
                        dwBBitMask = 0x0000FF;
                        dwRGBBitCount = 24;
                        break;
                    case ImageEngineFormat.DDS_CUSTOM:
                        if (customMasks != null)
                        {
                            int numChannels = customMasks.Where(mask => mask != 0).Count();
                            dwABitMask = customMasks[0];
                            dwRBitMask = customMasks[1];
                            dwGBitMask = customMasks[2];
                            dwBBitMask = customMasks[3];
                            dwRGBBitCount = 8 * numChannels;

                            if (numChannels == 1)
                                dwFlags = DDS_PFdwFlags.DDPF_LUMINANCE;
                            else if (numChannels == 2)
                                dwFlags = DDS_PFdwFlags.DDPF_LUMINANCE | DDS_PFdwFlags.DDPF_ALPHAPIXELS;
                        }
                        break;
                    #endregion Uncompressed
                }
            }
예제 #47
0
 /// <summary>
 /// Determines if format is a block compressed format.
 /// </summary>
 /// <param name="format">DDS Surface Format.</param>
 /// <returns>True if block compressed.</returns>
 public static bool IsBlockCompressed(ImageEngineFormat format)
 {
     return GetBlockSize(format) >= 8;
 }
예제 #48
0
 /// <summary>
 /// Determines if given format supports mipmapping.
 /// </summary>
 /// <param name="format">Image format to check.</param>
 /// <returns></returns>
 public static bool IsFormatMippable(ImageEngineFormat format)
 {
     return format.ToString().Contains("DDS");
 }
예제 #49
0
 /// <summary>
 /// Saves image in specified format to file. If file exists, it will be overwritten.
 /// </summary>
 /// <param name="destination">File to save to.</param>
 /// <param name="format">Desired image format.</param>
 /// <param name="GenerateMips">Determines how mipmaps are handled during saving.</param>
 /// <param name="desiredMaxDimension">Maximum size for saved image. Resizes if required, but uses mipmaps if available.</param>
 /// <param name="mergeAlpha">DXT1 only. True = Uses threshold value and alpha values to mask RGB.</param>
 /// <param name="mipToSave">Index of mipmap to save as single image.</param>
 /// <returns>True if success.</returns>
 public bool Save(string destination, ImageEngineFormat format, MipHandling GenerateMips, int desiredMaxDimension = 0, int mipToSave = 0, bool mergeAlpha = false)
 {
     using (FileStream fs = new FileStream(destination, FileMode.Create))
         return(Save(fs, format, GenerateMips, desiredMaxDimension, mipToSave, mergeAlpha));
 }
예제 #50
0
        /// <summary>
        /// Gets maximum number of channels a format can contain.
        /// NOTE: This likely isn't actually the max number. i.e. None exceed four, but some are only one or two channels.
        /// </summary>
        /// <param name="format">Format to channel count.</param>
        /// <returns>Max number of channels supported.</returns>
        public static int MaxNumberOfChannels(ImageEngineFormat format)
        {
            var estimate = GetBlockSize(format);

            // DXT and non-DDS
            if (estimate > 4 || estimate == 1)
                return 4;
            else
                return estimate;
        }
예제 #51
0
 /// <summary>
 /// Saves fully formatted image in specified format to byte array.
 /// </summary>
 /// <param name="format">Format to save as.</param>
 /// <param name="GenerateMips">Determines how mipmaps are handled during saving.</param>
 /// <param name="desiredMaxDimension">Maximum size for saved image. Resizes if required, but uses mipmaps if available.</param>
 /// <param name="mipToSave">Index of mipmap to save directly.</param>
 /// <param name="mergeAlpha">ONLY valid when desiredMaxDimension != 0. True = alpha flattened, directly affecting RGB.</param>
 /// <returns></returns>
 public byte[] Save(ImageEngineFormat format, MipHandling GenerateMips, int desiredMaxDimension = 0, int mipToSave = 0, bool mergeAlpha = false)
 {
     return(ImageEngine.Save(MipMaps, format, GenerateMips, desiredMaxDimension, mipToSave, mergeAlpha));
 }
예제 #52
0
        /// <summary>
        /// Saves image in specified format to file. If file exists, it will be overwritten.
        /// </summary>
        /// <param name="destination">File to save to.</param>
        /// <param name="format">Desired image format.</param>
        /// <param name="GenerateMips">Determines how mipmaps are handled during saving.</param>
        /// <param name="desiredMaxDimension">Maximum size for saved image. Resizes if required, but uses mipmaps if available.</param>
        /// <param name="removeAlpha">True = Alpha removed. False = Uses threshold value and alpha values to mask RGB FOR DXT1 ONLY, otherwise removes completely.</param>
        /// <param name="mipToSave">Index of mipmap to save as single image.</param>
        /// <param name="customMasks">Custom user defined masks for colours.</param>
        public async Task Save(string destination, ImageEngineFormat format, MipHandling GenerateMips, int desiredMaxDimension = 0, int mipToSave = 0, bool removeAlpha = true, List<uint> customMasks = null)
        {
            var data = Save(format, GenerateMips, desiredMaxDimension, mipToSave, removeAlpha, customMasks);

            using (FileStream fs = new FileStream(destination, FileMode.Create))
                await fs.WriteAsync(data, 0, data.Length);
        }