static private SaveWithCodecs ( byte imageData, ImageEngineFormat format, int width, int height, AlphaSettings alphaSetting ) : byte[] | ||
imageData | byte | |
format | ImageEngineFormat | |
width | int | |
height | int | |
alphaSetting | AlphaSettings | |
return | byte[] |
/// <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); }
/// <summary> /// Save mipmaps as given format to stream. /// </summary> /// <param name="MipMaps">List of Mips to save.</param> /// <param name="mipChoice">Determines how to handle mipmaps.</param> /// <param name="maxDimension">Maximum value for either image dimension.</param> /// <param name="alphaSetting">Determines how to handle alpha.</param> /// <param name="mipToSave">0 based index on which mipmap to make top of saved image.</param> /// <param name="destFormatDetails">Details about the destination format.</param> /// <returns>True on success.</returns> internal static byte[] Save(List <MipMap> MipMaps, ImageFormats.ImageEngineFormatDetails destFormatDetails, MipHandling mipChoice, AlphaSettings alphaSetting, int maxDimension = 0, int mipToSave = 0) { List <MipMap> newMips = new List <MipMap>(MipMaps); int width = newMips[0].Width; int height = newMips[0].Height; if ((destFormatDetails.IsMippable && mipChoice == MipHandling.GenerateNew) || (destFormatDetails.IsMippable && newMips.Count == 1 && mipChoice == MipHandling.Default)) { DDSGeneral.BuildMipMaps(newMips); } // KFreon: Resize if asked if (maxDimension != 0 && maxDimension < width && maxDimension < 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 * 1d / (width > height ? width : height); // KFreon: No mip. Resize. newMips[0] = Resize(newMips[0], scale); } } // KFreon: Ensure we have a power of two for dimensions FOR DDS ONLY TestDDSMipSize(newMips, destFormatDetails, width, height, out double fixXScale, out double fixYScale, mipChoice); if (fixXScale != 0 || fixYScale != 0 || mipChoice == MipHandling.KeepTopOnly) { DestroyMipMaps(newMips, mipToSave); } if ((fixXScale != 0 || fixXScale != 0) && destFormatDetails.IsMippable && mipChoice != MipHandling.KeepTopOnly) { DDSGeneral.BuildMipMaps(newMips); } byte[] destination = null; if (destFormatDetails.IsDDS) { destination = DDSGeneral.Save(newMips, destFormatDetails, alphaSetting); } else { // KFreon: Try saving with built in codecs var mip = newMips[0]; // Fix formatting byte[] newPixels = new byte[mip.Width * mip.Height * 4]; for (int i = 0, j = 0; i < newPixels.Length; i++, j += mip.LoadedFormatDetails.ComponentSize) { newPixels[i] = mip.LoadedFormatDetails.ReadByte(mip.Pixels, j); } destination = WIC_Codecs.SaveWithCodecs(newPixels, destFormatDetails.Format, mip.Width, mip.Height, alphaSetting); } return(destination); }