/// <summary> /// Saves fully formatted image in specified format to byte array. /// </summary> /// <param name="destFormatDetails">Details about destination 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="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> /// <returns></returns> public byte[] Save(ImageFormats.ImageEngineFormatDetails destFormatDetails, MipHandling GenerateMips, int desiredMaxDimension = 0, int mipToSave = 0, bool removeAlpha = true) { if (destFormatDetails.Format == ImageEngineFormat.Unknown) { throw new InvalidOperationException("Save format cannot be 'Unknown'"); } AlphaSettings alphaSetting = AlphaSettings.KeepAlpha; if (removeAlpha) { alphaSetting = AlphaSettings.RemoveAlphaChannel; } else if (destFormatDetails.Format == ImageEngineFormat.DDS_DXT2 || destFormatDetails.Format == ImageEngineFormat.DDS_DXT4) { alphaSetting = AlphaSettings.Premultiply; } // If same format and stuff, can just return original data, or chunks of it. if (destFormatDetails.Format == Format) { return(AttemptSaveUsingOriginalData(destFormatDetails, GenerateMips, desiredMaxDimension, mipToSave, alphaSetting)); } else { return(ImageEngine.Save(MipMaps, destFormatDetails, GenerateMips, alphaSetting, desiredMaxDimension, mipToSave)); } }
/// <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)); }
/// <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)); }
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); }