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.ConvertToXenkoImage(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> /// Applies the build status on top of a thumbnail image (using overlay icons). /// </summary> /// <param name="thumbnailImage">The thumbnail image.</param> /// <param name="dependencyBuildStatus">The dependency build status.</param> public static void ApplyThumbnailStatus(Image thumbnailImage, LogMessageType dependencyBuildStatus) { // No warning or error, nothing to do (or maybe we should display a logo for "info"?) if (dependencyBuildStatus < LogMessageType.Warning) { return; } using (var thumbnailBuilderHelper = new ThumbnailBuildHelper()) { if (errorTexture == null) { // Load status textures errorTexture = TextureExtensions.FromFileData(thumbnailBuilderHelper.GraphicsDevice, DefaultThumbnails.ThumbnailDependencyError); warningTexture = TextureExtensions.FromFileData(thumbnailBuilderHelper.GraphicsDevice, DefaultThumbnails.ThumbnailDependencyWarning); } var texture = dependencyBuildStatus == LogMessageType.Warning ? warningTexture : errorTexture; using (var thumbnailTexture = Texture.New(thumbnailBuilderHelper.GraphicsDevice, thumbnailImage)) { thumbnailBuilderHelper.CombineTextures(thumbnailTexture, texture, thumbnailImage.Description.Width - texture.Width - 4, thumbnailImage.Description.Height - texture.Height - 4); } // Read back result to image thumbnailBuilderHelper.RenderTarget.GetData(thumbnailBuilderHelper.GraphicsContext.CommandList, thumbnailBuilderHelper.RenderTargetStaging, new DataPointer(thumbnailImage.PixelBuffer[0].DataPointer, thumbnailImage.PixelBuffer[0].BufferStride)); thumbnailImage.Description.Format = thumbnailBuilderHelper.RenderTarget.Format; // In case channels are swapped } }
public static byte[] HandleBrokenThumbnail() { // Load broken asset thumbnail var assetBrokenThumbnail = Image.Load(DefaultThumbnails.AssetBrokenThumbnail); // Apply thumbnail status in corner ThumbnailBuildHelper.ApplyThumbnailStatus(assetBrokenThumbnail, LogMessageType.Error); var memoryStream = new MemoryStream(); assetBrokenThumbnail.Save(memoryStream, ImageFileType.Png); return(memoryStream.ToArray()); }
/// <summary> /// The micro-thread in charge of processing the thumbnail build requests and creating the thumbnails. /// </summary> private ResultStatus ProcessThumbnailRequests(ThumbnailBuildRequest request) { var status = ResultStatus.Successful; // Global lock so that only one rendering happens at the same time lock (lockObject) { try { lock (AssetBuilderService.OutOfMicrothreadDatabaseLock) { MicrothreadLocalDatabases.MountCommonDatabase(); // set the master output var renderTarget = GraphicsContext.Allocator.GetTemporaryTexture2D(request.Size.X, request.Size.Y, request.ColorSpace == ColorSpace.Linear ? PixelFormat.R8G8B8A8_UNorm_SRgb : PixelFormat.R8G8B8A8_UNorm, TextureFlags.ShaderResource | TextureFlags.RenderTarget); var depthStencil = GraphicsContext.Allocator.GetTemporaryTexture2D(request.Size.X, request.Size.Y, PixelFormat.D24_UNorm_S8_UInt, TextureFlags.DepthStencil); try { // Fake presenter // TODO GRAPHICS REFACTOR: Try to remove that GraphicsDevice.Presenter = new RenderTargetGraphicsPresenter(GraphicsDevice, renderTarget, depthStencil.ViewFormat); // Always clear the state of the GraphicsDevice to make sure a scene doesn't start with a wrong setup GraphicsCommandList.ClearState(); // Setup the color space when rendering a thumbnail GraphicsDevice.ColorSpace = request.ColorSpace; // render the thumbnail thumbnailScene.Children.Add(request.Scene); // Store the graphics compositor to use, so we can dispose it when disposing this ThumbnailGenerator thumbnailGraphicsCompositors.Add(request.GraphicsCompositor); sceneSystem.GraphicsCompositor = request.GraphicsCompositor; // Render once to setup render processors // TODO GRAPHICS REFACTOR: Should not require two rendering GraphicsContext.ResourceGroupAllocator.Reset(GraphicsContext.CommandList); gameSystems.Draw(nullGameTime); // Draw gameSystems.Update(nullGameTime); GraphicsContext.ResourceGroupAllocator.Reset(GraphicsContext.CommandList); gameSystems.Draw(nullGameTime); // write the thumbnail to the file using (var thumbnailImage = renderTarget.GetDataAsImage(GraphicsCommandList)) using (var outputImageStream = request.FileProvider.OpenStream(request.Url, VirtualFileMode.Create, VirtualFileAccess.Write)) { request.PostProcessThumbnail?.Invoke(thumbnailImage); ThumbnailBuildHelper.ApplyThumbnailStatus(thumbnailImage, request.DependencyBuildStatus); thumbnailImage.Save(outputImageStream, ImageFileType.Png); request.Logger.Info($"Thumbnail creation successful [{request.Url}] to ({thumbnailImage.Description.Width}x{thumbnailImage.Description.Height},{thumbnailImage.Description.Format})"); } } finally { // Cleanup the scene thumbnailScene.Children.Clear(); sceneSystem.GraphicsCompositor = null; GraphicsContext.Allocator.ReleaseReference(depthStencil); GraphicsContext.Allocator.ReleaseReference(renderTarget); } MicrothreadLocalDatabases.UnmountDatabase(); } } catch (Exception e) { status = ResultStatus.Failed; request.Logger.Error("An exception occurred while processing thumbnail request.", e); } } return(status); }