public void DecompressTest() { TexImage img; int mipmapCount, arraySize, width, height, depth, subImageArrayLenght; // ------------------- Test with BC3 image ------------------- img = texTool.Load(TestTools.InputTestFolder + "TextureArray_WMipMaps_BC3.dds"); Assert.IsTrue(img.Format == PixelFormat.BC3_UNorm); mipmapCount = img.MipmapCount; arraySize = img.ArraySize; width = img.Width; height = img.Height; depth = img.Depth; subImageArrayLenght = img.SubImageArray.Length; texTool.Decompress(img, false); Assert.IsTrue(img.Format == PixelFormat.R8G8B8A8_UNorm); Assert.IsTrue(mipmapCount == img.MipmapCount); Assert.IsTrue(arraySize == img.ArraySize); Assert.IsTrue(width == img.Width); Assert.IsTrue(height == img.Height); Assert.IsTrue(depth == img.Depth); Assert.IsTrue(subImageArrayLenght == img.SubImageArray.Length); Assert.IsTrue(TestTools.ComputeSHA1(img.Data, img.DataSize).Equals(TestTools.GetInstance().Checksum["DecompressTest_TextureArray_WMipMaps_BC3.dds"])); img.Dispose(); // ------------------- Test with uncompress image ------------------- img = texTool.Load(TestTools.InputTestFolder + "stones.png"); texTool.Decompress(img, false); Assert.IsTrue(img.Format == PixelFormat.B8G8R8A8_UNorm); //FITexLibrary loads image in BGRA order... img.Dispose(); }
public static void CreateAndSaveSeparateTextures(TextureTool texTool, TexImage texImage, string originalTextureURL, bool shouldGenerateMipMaps, PixelFormat outputFormat = PixelFormat.ETC1) { var assetManager = new AssetManager(); var alphaTextureURL = GenerateAlphaTextureURL(originalTextureURL); var colorTextureURL = GenerateColorTextureURL(originalTextureURL); // create a new image containing only the alpha component texTool.Decompress(texImage, texImage.Format.IsSRgb()); using (var alphaImage = texTool.CreateImageFromAlphaComponent(texImage)) { // generate the mip-maps for the alpha component if required if (shouldGenerateMipMaps) { texTool.GenerateMipMaps(alphaImage, Filter.MipMapGeneration.Box); } // save the alpha component texTool.Compress(alphaImage, outputFormat); using (var outputImage = texTool.ConvertToXenkoImage(alphaImage)) assetManager.Save(alphaTextureURL, outputImage.ToSerializableVersion()); } // save the color component texTool.Decompress(texImage, texImage.Format.IsSRgb()); texTool.Compress(texImage, outputFormat); using (var outputImage = texTool.ConvertToXenkoImage(texImage)) assetManager.Save(colorTextureURL, outputImage.ToSerializableVersion()); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { // load the sound thumbnail image from the resources using (var imageStream = new MemoryStream(staticImageData)) using (var image = Image.Load(imageStream)) using (var texTool = new TextureTool()) using (var texImage = texTool.Load(image, Parameters.SRgb)) { // Rescale image so that it fits the thumbnail asked resolution texTool.Decompress(texImage, texImage.Format.IsSRgb()); texTool.Resize(texImage, thumbnailSize.X, thumbnailSize.Y, Filter.Rescaling.Lanczos3); // Save using (var outputImageStream = MicrothreadLocalDatabases.DatabaseFileProvider.OpenStream(Url, VirtualFileMode.Create, VirtualFileAccess.Write)) using (var outputImage = texTool.ConvertToStrideImage(texImage)) { ThumbnailBuildHelper.ApplyThumbnailStatus(outputImage, DependencyBuildStatus); outputImage.Save(outputImageStream, ImageFileType.Png); commandContext.Logger.Verbose($"Thumbnail creation successful [{Url}] to ({outputImage.Description.Width}x{outputImage.Description.Height},{outputImage.Description.Format})"); } } return(Task.FromResult(ResultStatus.Successful)); }
/// <summary> /// Loads image from a path with texTool /// </summary> /// <param name="texTool">A tool for loading an image</param> /// <param name="sourcePath">Source path of an image</param> /// <param name="isSRgb">Indicate if the texture to load is sRGB</param> /// <returns></returns> private static Image LoadImage(TextureTool texTool, UFile sourcePath, bool isSRgb) { using (var texImage = texTool.Load(sourcePath, isSRgb)) { texTool.Decompress(texImage, isSRgb); if (texImage.Format == PixelFormat.B8G8R8A8_UNorm || texImage.Format == PixelFormat.B8G8R8A8_UNorm_SRgb) { texTool.SwitchChannel(texImage); } return(texTool.ConvertToXenkoImage(texImage)); } }
private Image LoadImage(TextureTool texTool, UFile sourcePath) { using (var texImage = texTool.Load(sourcePath, false)) { // Decompresses the specified texImage texTool.Decompress(texImage, false); if (texImage.Format == PixelFormat.B8G8R8A8_UNorm) { texTool.SwitchChannel(texImage); } return(texTool.ConvertToStrideImage(texImage)); } }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new AssetManager(); // Load image var image = assetManager.Load <Image>(InputUrl); // Initialize TextureTool library using (var texTool = new TextureTool()) using (var texImage = texTool.Load(image)) { var outputFormat = Format.HasValue ? Format.Value : image.Description.Format; // Apply transformations texTool.Decompress(texImage); if (IsAbsolute) { texTool.Resize(texImage, (int)Width, (int)Height, Filter.Rescaling.Lanczos3); } else { texTool.Rescale(texImage, Width / 100.0f, Height / 100.0f, Filter.Rescaling.Lanczos3); } // Generate mipmaps if (GenerateMipmaps) { texTool.GenerateMipMaps(texImage, Filter.MipMapGeneration.Box); } // Convert/Compress to output format texTool.Compress(texImage, outputFormat); // Save using (var outputImage = texTool.ConvertToParadoxImage(texImage)) { assetManager.Save(OutputUrl, outputImage); commandContext.Logger.Verbose("Compression successful [{3}] to ({0}x{1},{2})", outputImage.Description.Width, outputImage.Description.Height, outputImage.Description.Format, OutputUrl); } } return(Task.FromResult(ResultStatus.Successful)); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); assetManager.Serializer.RegisterSerializer(new ImageTextureSerializer()); // Create atlas texture Dictionary <SpriteInfo, PackedSpriteInfo> spriteToPackedSprite = null; // Generate texture atlas var isPacking = Parameters.SheetAsset.Packing.Enabled; if (isPacking) { var resultStatus = CreateAtlasTextures(commandContext, out spriteToPackedSprite); if (resultStatus != ResultStatus.Successful) { return(Task.FromResult(resultStatus)); } } var imageGroupData = new SpriteSheet(); // add the sprite data to the sprite list. foreach (var image in Parameters.SheetAsset.Sprites) { string textureUrl; RectangleF region; ImageOrientation orientation; var borders = image.Borders; var center = image.Center + (image.CenterFromMiddle ? new Vector2(image.TextureRegion.Width, image.TextureRegion.Height) / 2 : Vector2.Zero); if (isPacking && spriteToPackedSprite.TryGetValue(image, out var packedSprite)) // ensure that unpackable elements (invalid because of null size/texture) are properly added in the sheet using the normal path { var isOriginalSpriteRotated = image.Orientation == ImageOrientation.Rotated90; region = packedSprite.Region; orientation = (packedSprite.IsRotated ^ isOriginalSpriteRotated) ? ImageOrientation.Rotated90 : ImageOrientation.AsIs; textureUrl = SpriteSheetAsset.BuildTextureAtlasUrl(Url, spriteToPackedSprite[image].AtlasTextureIndex); // update the center and border info, if the packer rotated the sprite // note: X->Left, Y->Top, Z->Right, W->Bottom. if (packedSprite.IsRotated) { // turned the sprite CCW if (isOriginalSpriteRotated) { var oldCenterX = center.X; center.X = center.Y; center.Y = region.Height - oldCenterX; var oldBorderW = borders.W; borders.W = borders.X; borders.X = borders.Y; borders.Y = borders.Z; borders.Z = oldBorderW; } else // turned the sprite CW { var oldCenterX = center.X; center.X = region.Width - center.Y; center.Y = oldCenterX; var oldBorderW = borders.W; borders.W = borders.Z; borders.Z = borders.Y; borders.Y = borders.X; borders.X = oldBorderW; } } } else { region = image.TextureRegion; orientation = image.Orientation; Parameters.ImageToTextureUrl.TryGetValue(image, out textureUrl); } // Affect the texture Texture texture = null; if (textureUrl != null) { texture = AttachedReferenceManager.CreateProxyObject <Texture>(AssetId.Empty, textureUrl); } else { commandContext.Logger.Warning($"Image '{image.Name}' has an invalid image source file '{image.Source}', resulting texture will be null."); } imageGroupData.Sprites.Add(new Graphics.Sprite { Name = image.Name, Region = region, Orientation = orientation, Center = center, Borders = borders, PixelsPerUnit = new Vector2(image.PixelsPerUnit), Texture = texture, IsTransparent = false, }); } // set the transparency information to all the sprites if (Parameters.SheetAsset.Alpha != AlphaFormat.None) // Skip the calculation when format is forced without alpha. { var urlToTexImage = new Dictionary <string, Tuple <TexImage, Image> >(); using (var texTool = new TextureTool()) { foreach (var sprite in imageGroupData.Sprites) { if (sprite.Texture == null) // the sprite texture is invalid { continue; } var textureUrl = AttachedReferenceManager.GetOrCreateAttachedReference(sprite.Texture).Url; if (!urlToTexImage.ContainsKey(textureUrl)) { var image = assetManager.Load <Image>(textureUrl); var newTexImage = texTool.Load(image, false); // the sRGB mode does not impact on the alpha level texTool.Decompress(newTexImage, false); // the sRGB mode does not impact on the alpha level urlToTexImage[textureUrl] = Tuple.Create(newTexImage, image); } var texImage = urlToTexImage[textureUrl].Item1; var region = new Rectangle { X = (int)Math.Floor(sprite.Region.X), Y = (int)Math.Floor(sprite.Region.Y) }; region.Width = (int)Math.Ceiling(sprite.Region.Right) - region.X; region.Height = (int)Math.Ceiling(sprite.Region.Bottom) - region.Y; var alphaLevel = texTool.GetAlphaLevels(texImage, region, null, commandContext.Logger); // ignore transparent color key here because the input image has already been processed sprite.IsTransparent = alphaLevel != AlphaLevels.NoAlpha; } // free all the allocated images foreach (var tuple in urlToTexImage.Values) { tuple.Item1.Dispose(); assetManager.Unload(tuple.Item2); } } } // save the imageData into the data base assetManager.Save(Url, imageGroupData); return(Task.FromResult(ResultStatus.Successful)); }
public static ResultStatus ImportTextureImage(TextureTool textureTool, TexImage texImage, ImportParameters parameters, CancellationToken cancellationToken, Logger logger) { var assetManager = new ContentManager(); // Apply transformations textureTool.Decompress(texImage, parameters.IsSRgb); // Special case when the input texture is monochromatic but it is supposed to be a color and we are working in SRGB // In that case, we need to transform it to a supported SRGB format (R8G8B8A8_UNorm_SRgb) // TODO: As part of a conversion phase, this code may be moved to a dedicated method in this class at some point if (parameters.TextureHint == TextureHint.Color && parameters.IsSRgb && (texImage.Format == PixelFormat.R8_UNorm || texImage.Format == PixelFormat.A8_UNorm)) { textureTool.Convert(texImage, PixelFormat.R8G8B8A8_UNorm_SRgb); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } var fromSize = new Size2(texImage.Width, texImage.Height); var targetSize = parameters.DesiredSize; // Resize the image if (parameters.IsSizeInPercentage) { targetSize = new Size2((int)(fromSize.Width * targetSize.Width / 100.0f), (int)(fromSize.Height * targetSize.Height / 100.0f)); } // Find the target size targetSize = FindBestTextureSize(parameters, targetSize, logger); // Resize the image only if needed if (targetSize != fromSize) { textureTool.Resize(texImage, targetSize.Width, targetSize.Height, Filter.Rescaling.Lanczos3); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // texture size is now determined, we can cache it var textureSize = new Int2(texImage.Width, texImage.Height); // determine the alpha format of the texture when set to Auto // Note: this has to be done before the ColorKey transformation in order to be able to take advantage of image file AlphaDepth information if (parameters.DesiredAlpha == AlphaFormat.Auto) { var colorKey = parameters.ColorKeyEnabled? (Color?)parameters.ColorKeyColor : null; var alphaLevel = textureTool.GetAlphaLevels(texImage, new Rectangle(0, 0, textureSize.X, textureSize.Y), colorKey, logger); parameters.DesiredAlpha = alphaLevel.ToAlphaFormat(); } // Apply the color key if (parameters.ColorKeyEnabled) { textureTool.ColorKey(texImage, parameters.ColorKeyColor); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Pre-multiply alpha only for relevant formats if (parameters.PremultiplyAlpha && texImage.Format.HasAlpha32Bits()) { textureTool.PreMultiplyAlpha(texImage); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Generate mipmaps if (parameters.GenerateMipmaps) { var boxFilteringIsSupported = !texImage.Format.IsSRgb() || (MathUtil.IsPow2(textureSize.X) && MathUtil.IsPow2(textureSize.Y)); textureTool.GenerateMipMaps(texImage, boxFilteringIsSupported? Filter.MipMapGeneration.Box: Filter.MipMapGeneration.Linear); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Convert/Compress to output format // TODO: Change alphaFormat depending on actual image content (auto-detection)? var outputFormat = DetermineOutputFormat(parameters, textureSize, texImage.Format); textureTool.Compress(texImage, outputFormat, (TextureConverter.Requests.TextureQuality)parameters.TextureQuality); if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Save the texture using (var outputImage = textureTool.ConvertToXenkoImage(texImage)) { if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } assetManager.Save(parameters.OutputUrl, outputImage.ToSerializableVersion()); logger.Verbose("Compression successful [{3}] to ({0}x{1},{2})", outputImage.Description.Width, outputImage.Description.Height, outputImage.Description.Format, parameters.OutputUrl); } return(ResultStatus.Successful); }
public BitmapImage RetrieveImage(UFile filePath) { if (filePath == null) { return(null); } if (!File.Exists(filePath)) { return(null); } var lastWrite = File.GetLastWriteTime(filePath); var entry = cache.FirstOrDefault(x => x.Item1 == filePath); if (entry != null) { if (lastWrite == entry.Item2) { return(entry.Item4); } // Clear from cache cache.Remove(entry); } try { using (var stream = new MemoryStream()) { TexImage texImage; using (var texTool = new TextureTool()) { texImage = texTool.Load(filePath, false); texTool.Decompress(texImage, texImage.Format.IsSRgb()); if (texImage.Format == PixelFormat.R16G16B16A16_UNorm) { texTool.Convert(texImage, PixelFormat.R8G8B8A8_UNorm); } var image = texTool.ConvertToStrideImage(texImage); image.Save(stream, ImageFileType.Png); } stream.Position = 0; var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = stream; //bitmap.UriSource = new Uri(filePath); bitmap.CacheOption = BitmapCacheOption.OnLoad; // This flag is only used when loaded via UriSource, and make it crash when loaded via StreamSource //bitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache; bitmap.EndInit(); bitmap.Freeze(); // Update the cache cache.Add(Tuple.Create(filePath, lastWrite, texImage, bitmap)); if (cache.Count == CacheSize) { cache.RemoveAt(0); } return(bitmap); } } catch (InvalidOperationException) { return(null); } catch (TextureToolsException) { return(null); } }
public static ResultStatus ImportAndSaveTextureImage(UFile sourcePath, string outputUrl, TextureAsset textureAsset, TextureConvertParameters parameters, bool separateAlpha, CancellationToken cancellationToken, Logger logger) { var assetManager = new AssetManager(); using (var texTool = new TextureTool()) using (var texImage = texTool.Load(sourcePath)) { // Apply transformations texTool.Decompress(texImage); if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Resize the image if (textureAsset.IsSizeInPercentage) { texTool.Rescale(texImage, textureAsset.Width / 100.0f, textureAsset.Height / 100.0f, Filter.Rescaling.Lanczos3); } else { texTool.Resize(texImage, (int)textureAsset.Width, (int)textureAsset.Height, Filter.Rescaling.Lanczos3); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // texture size is now determined, we can cache it var textureSize = new Int2(texImage.Width, texImage.Height); // Check that the resulting texture size is supported by the targeted graphics profile if (!TextureSizeSupported(textureAsset.Format, parameters.GraphicsPlatform, parameters.GraphicsProfile, textureSize, textureAsset.GenerateMipmaps, logger)) { return(ResultStatus.Failed); } // Apply the color key if (textureAsset.ColorKeyEnabled) { texTool.ColorKey(texImage, textureAsset.ColorKeyColor); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Pre-multiply alpha if (textureAsset.PremultiplyAlpha) { texTool.PreMultiplyAlpha(texImage); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Generate mipmaps if (textureAsset.GenerateMipmaps) { texTool.GenerateMipMaps(texImage, Filter.MipMapGeneration.Box); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Convert/Compress to output format // TODO: Change alphaFormat depending on actual image content (auto-detection)? var outputFormat = DetermineOutputFormat(textureAsset.Format, textureAsset.Alpha, parameters.Platform, parameters.GraphicsPlatform, parameters.GraphicsProfile, textureSize, texImage.Format); texTool.Compress(texImage, outputFormat, (TextureConverter.Requests.TextureQuality)parameters.TextureQuality); if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Save the texture if (separateAlpha) { TextureAlphaComponentSplitter.CreateAndSaveSeparateTextures(texTool, texImage, outputUrl, textureAsset.GenerateMipmaps); } else { using (var outputImage = texTool.ConvertToParadoxImage(texImage)) { if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } assetManager.Save(outputUrl, outputImage); logger.Info("Compression successful [{3}] to ({0}x{1},{2})", outputImage.Description.Width, outputImage.Description.Height, outputImage.Description.Format, outputUrl); } } } return(ResultStatus.Successful); }
public static ResultStatus ImportAndSaveTextureImage(UFile sourcePath, string outputUrl, TextureAsset textureAsset, TextureConvertParameters parameters, CancellationToken cancellationToken, Logger logger) { var assetManager = new AssetManager(); using (var texTool = new TextureTool()) using (var texImage = texTool.Load(sourcePath, textureAsset.SRgb)) { // Apply transformations texTool.Decompress(texImage, textureAsset.SRgb); if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } var fromSize = new Size2(texImage.Width, texImage.Height); var targetSize = new Size2((int)textureAsset.Width, (int)textureAsset.Height); // Resize the image if (textureAsset.IsSizeInPercentage) { targetSize = new Size2((int)(fromSize.Width * (float)textureAsset.Width / 100.0f), (int)(fromSize.Height * (float)textureAsset.Height / 100.0f)); } // Find the target size targetSize = FindBestTextureSize(textureAsset.Format, parameters.GraphicsPlatform, parameters.GraphicsProfile, fromSize, targetSize, textureAsset.GenerateMipmaps, logger); // Resize the image only if needed if (targetSize != fromSize) { texTool.Resize(texImage, targetSize.Width, targetSize.Height, Filter.Rescaling.Lanczos3); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // texture size is now determined, we can cache it var textureSize = new Int2(texImage.Width, texImage.Height); // Apply the color key if (textureAsset.ColorKeyEnabled) { texTool.ColorKey(texImage, textureAsset.ColorKeyColor); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Pre-multiply alpha if (textureAsset.PremultiplyAlpha) { texTool.PreMultiplyAlpha(texImage); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Generate mipmaps if (textureAsset.GenerateMipmaps) { var boxFilteringIsSupported = texImage.Format != PixelFormat.B8G8R8A8_UNorm_SRgb || (IsPowerOfTwo(textureSize.X) && IsPowerOfTwo(textureSize.Y)); texTool.GenerateMipMaps(texImage, boxFilteringIsSupported? Filter.MipMapGeneration.Box: Filter.MipMapGeneration.Linear); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Convert/Compress to output format // TODO: Change alphaFormat depending on actual image content (auto-detection)? var outputFormat = DetermineOutputFormat(textureAsset, parameters, textureSize, texImage.Format, parameters.Platform, parameters.GraphicsPlatform, parameters.GraphicsProfile); texTool.Compress(texImage, outputFormat, (TextureConverter.Requests.TextureQuality)parameters.TextureQuality); if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Save the texture if (parameters.SeparateAlpha) { //TextureAlphaComponentSplitter.CreateAndSaveSeparateTextures(texTool, texImage, outputUrl, textureAsset.GenerateMipmaps); } else { using (var outputImage = texTool.ConvertToParadoxImage(texImage)) { if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } assetManager.Save(outputUrl, outputImage.ToSerializableVersion()); logger.Info("Compression successful [{3}] to ({0}x{1},{2})", outputImage.Description.Width, outputImage.Description.Height, outputImage.Description.Format, outputUrl); } } } return(ResultStatus.Successful); }