Esempio n. 1
0
        /// <summary>
        /// Save an image for reference.
        /// </summary>
        /// <param name="fileName">The image name.</param>
        /// <param name="size">The image size.</param>
        /// <param name="pixels">The image pixels.</param>
        public static void SaveReferenceImage(string fileName, Vector2 size, byte[] pixels)
        {
            if (!_runnerFolderCreated)
            {
                Directory.CreateDirectory(RunnerReferenceImageFolder);
                _runnerFolderCreated = true;
            }

            string filePath = Path.Join(RunnerReferenceImageFolder, fileName);

            byte[] file = PngFormat.Encode(ImageUtil.FlipImageYNoMutate(pixels, (int)size.Y), size, PixelFormat.Rgba);
            File.WriteAllBytes(filePath, file);
        }
Esempio n. 2
0
        private void LoadFile(OtherAsset f)
        {
            _status = "Loading...";

            byte[] data = f.Content;
            if (!PngFormat.IsPng(data))
            {
                _status = $"The provided file {f.Name} is not a PNG file.";
                return;
            }

            byte[] pixels = PngFormat.Decode(data, out PngFileHeader header);
            byte[] output = PngFormat.Encode(pixels, header.Width, header.Height);

            bool saved = Engine.AssetLoader.Save(output, "Player" + "/" + f.Name, false);

            _status = saved ? "Done!" : "Error when saving the file. Check logs.";
        }
Esempio n. 3
0
        private void RenderSaveSection(RenderComposer composer)
        {
            // Saving
            ImGui.InputText("Name", ref _saveName, 100);
            ImGui.SameLine();
            if (string.IsNullOrEmpty(_saveName))
            {
                ImGui.TextDisabled("Save");
                ImGui.SameLine();
                ImGui.TextDisabled("SaveToFile");
            }
            else
            {
                ImGui.SameLine();
                if (ImGui.Button("SaveToFile"))
                {
                    string saveName = _saveName.ToLower();
                    if (!saveName.Contains(".anim")) saveName += ".anim";

                    // Fixups
                    if (AnimController?.MirrorXAnchors != null)
                    {
                        var emptyMirrorAnchors = true;
                        for (var i = 0; i < AnimController.MirrorXAnchors.Length; i++)
                        {
                            if (AnimController.MirrorXAnchors[i] == Vector2.Zero) continue;
                            emptyMirrorAnchors = false;
                            break;
                        }

                        if (emptyMirrorAnchors) AnimController.MirrorXAnchors = null;
                    }

                    try
                    {
                        string saveData;
                        // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
                        if (AnimController != null)
                            saveData = XMLFormat.To(AnimController);
                        else
                            saveData = XMLFormat.To(Animation);

                        Engine.AssetLoader.Save(Encoding.UTF8.GetBytes(saveData), saveName);
                    }
                    catch (Exception ex)
                    {
                        Engine.Log.Error(ex);
                    }
                }

                if (ImGui.Button("Save Packed Texture"))
                {
                    string saveName = _saveName.ToLower();
                    if (!saveName.Contains(".png")) saveName += ".png";
                    Rectangle[] frames = AnimController != null ? AnimController.AnimTex.Frames : Animation.Frames;
                    var preBinnedFrames = new Rectangle[frames.Length];
                    Array.Copy(frames, preBinnedFrames, frames.Length);
                    Texture spriteSheetTexture = Animation.Texture;

                    var spacing = 2;
                    for (var i = 0; i < frames.Length; i++)
                    {
                        Rectangle frame = frames[i];
                        frames[i] = frame.Inflate(spacing, spacing);
                    }

                    Vector2 totalSize = Binning.FitRectangles(frames, true);
                    FrameBuffer texture = new FrameBuffer(totalSize).WithColor();
                    composer.RenderTo(texture);
                    for (var i = 0; i < frames.Length; i++)
                    {
                        composer.RenderSprite(frames[i].Deflate(spacing, spacing), Color.White, spriteSheetTexture, preBinnedFrames[i]);
                    }

                    composer.RenderTo(null);

                    byte[] pixelsDownload = texture.Sample(new Rectangle(0, 0, totalSize), PixelFormat.Rgba);
                    ImageUtil.FlipImageY(pixelsDownload, (int) totalSize.Y);
                    byte[] pngFile = PngFormat.Encode(pixelsDownload, totalSize, PixelFormat.Rgba);
                    Engine.AssetLoader.Save(pngFile, saveName);
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Verify two images.
        /// </summary>
        /// <param name="compareName">
        /// The name of the comparison. Should be unique for all tests. Is used to store information on
        /// the disk about the comparison.
        /// </param>
        /// <param name="originalImage">The original image. Must be in a four component format.</param>
        /// <param name="comparisonImage">The image comparing it to. Must be in a four component format.</param>
        /// <param name="comparisonSize">The size of the second image.</param>
        public static void VerifyImages(string compareName, byte[] originalImage, byte[] comparisonImage, Vector2 comparisonSize)
        {
            // Runner reference image folders should be created only for runners who verify images.
            if (!_runnerFolderCreated)
            {
                Directory.CreateDirectory(RunnerReferenceImageFolder);
                _runnerFolderCreated = true;
            }

            // Invent a name for this comparison and a folder to store data in, in case it is derived.
            string fileName;

            if (_comparisonImageDuplicate.ContainsKey(compareName))
            {
                fileName = $"{compareName}{_comparisonImageDuplicate[compareName]}.png";
                _comparisonImageDuplicate[compareName]++;
            }
            else
            {
                fileName = $"{compareName}.png";
                _comparisonImageDuplicate.Add(compareName, 1);
            }

            // We want to store the comparison image for possible manual comparison.
            SaveReferenceImage(fileName, comparisonSize, comparisonImage);

            // Check if the original image is missing, in which case we just store the comparison image.
            if (originalImage == null)
            {
                return;
            }

            Engine.Log.Info($"      Comparing images {compareName}...", TestRunnerLogger.TestRunnerSrc);

            float derivedPixelPercentage;

            byte[] derivationImage = null;

            // If the size isn't the same, it is all derived.
            if (originalImage.Length == comparisonImage.Length)
            {
                derivedPixelPercentage = CalculateImageDerivation(originalImage, comparisonImage, out derivationImage) * 100;
            }
            else
            {
                derivedPixelPercentage = 100;
            }

            if (derivedPixelPercentage == 0)
            {
                Engine.Log.Info("          No derivation.", TestRunnerLogger.TestRunnerSrc);
                return;
            }

            // Save a derivation image showing the differences.
            if (derivationImage != null)
            {
                string directory = Path.Join(RunnerReferenceImageFolder, $"Comparison_{fileName}");
                Directory.CreateDirectory(directory);
                byte[] derivedFile = PngFormat.Encode(ImageUtil.FlipImageYNoMutate(derivationImage, (int)comparisonSize.Y), comparisonSize, PixelFormat.Rgba);
                File.WriteAllBytes(Path.Join(directory, "derivation.png"), derivedFile);
            }

            // Assert derivation is not higher than tolerable. This is not done using the Emotion.Test assert so it doesn't stop the test from continuing.
            if (derivedPixelPercentage > PixelDerivationTolerance)
            {
                throw new ImageDerivationException($"          Failed derivation check. Derivation is {derivedPixelPercentage}%.");
            }
            Engine.Log.Info($"          Derivation is {derivedPixelPercentage}%.", TestRunnerLogger.TestRunnerSrc);
        }
 public void DebugDump(string fileName)
 {
     byte[] bytes = ImageUtil.AToRgba(Pixels);
     bytes = PngFormat.Encode(bytes, (int)Size.X, (int)Size.Y);
     File.WriteAllBytes(fileName, bytes);
 }
Esempio n. 6
0
        protected override void RenderContent(RenderComposer composer)
        {
            // File selection.
            if (ImGui.Button("Choose Texture File"))
            {
                var explorer = new FileExplorer <TextureAsset>(f =>
                {
                    _file      = f;
                    _pixelData = null;
                });
                Parent.AddWindow(explorer);
            }

            if (_file == null)
            {
                return;
            }

            _previewTexture ??= new Texture(new Vector2(100, 100), _file.Texture.PixelFormat);
            if (_pixelData == null)
            {
                _pixelData = new byte[(int)(_file.Texture.Size.X * _file.Texture.Size.Y * 4)];

                unsafe
                {
                    fixed(void *p = &_pixelData[0])
                    {
                        Texture.EnsureBound(_file.Texture.Pointer);
                        Gl.GetTexImage(TextureTarget.Texture2d, 0, _file.Texture.PixelFormat, PixelType.UnsignedByte, new IntPtr(p));
                    }
                }

                _removedPixelData = new byte[_pixelData.Length];
                DetectRogueAlpha();
                UpdatePreview("normal");
            }

            ImGui.Image(new IntPtr(_file.Texture.Pointer), _file.Texture.Size);
            int thresholdInput = _threshold;

            ImGui.InputInt("Threshold", ref thresholdInput, 1, 5);
            if (thresholdInput != _threshold)
            {
                _threshold = (byte)thresholdInput;
                DetectRogueAlpha();
                UpdatePreview();
            }

            ImGui.Text($"Detected Rogue Alpha: {_rogueAlphaPixels}/{_file.Texture.Size.X * _file.Texture.Size.Y} pixels");

            ImGui.Text("Preview");
            ImGui.Image(new IntPtr(_previewTexture.Pointer), _previewTexture.Size);

            if (ImGui.Button("Normal Preview"))
            {
                UpdatePreview("normal");
            }
            ImGui.SameLine();
            if (ImGui.Button("Alpha Preview"))
            {
                UpdatePreview("alpha");
            }

            if (ImGui.Button("Apply Changes"))
            {
                UpdatePreview("export");
                byte[] pngData = PngFormat.Encode(_removedPixelData, _previewTexture.Size, _file.Texture.PixelFormat);
                Engine.AssetLoader.Save(pngData, _file.Name);
            }
        }
Esempio n. 7
0
        protected override void RenderContent(RenderComposer composer)
        {
            // File selection.
            if (ImGui.Button("Choose Texture File"))
            {
                var explorer = new FileExplorer <TextureAsset>(f => {
                    _file      = f;
                    _pixelData = null;
                });
                Parent.AddWindow(explorer);
            }

            if (_file == null)
            {
                return;
            }

            if (_previewTexture == null)
            {
                _previewTexture = new Texture(new System.Numerics.Vector2(100, 100));
            }

            if (_pixelData == null)
            {
                _pixelData = new byte[(int)(_file.Texture.Size.X * _file.Texture.Size.Y * 4)];

                unsafe
                {
                    fixed(void *p = &_pixelData[0])
                    {
                        Texture.EnsureBound(_file.Texture.Pointer);
                        Gl.GetTexImage(TextureTarget.Texture2d, 0, PixelFormat.Bgra, PixelType.UnsignedByte, new IntPtr(p));
                    }
                }

                _removedPixelData = new byte[_pixelData.Length];
                DetectRogueAlpha();
                UpdatePreview("normal");
            }

            ImGui.Image(new IntPtr(_file.Texture.Pointer), _file.Texture.Size);
            int thresholdInput = _threshold;

            ImGui.InputInt("Threshold", ref thresholdInput, 1, 5);
            if (thresholdInput != _threshold)
            {
                _threshold = (byte)thresholdInput;
                DetectRogueAlpha();
                UpdatePreview();
            }
            ImGui.Text($"Detected Rogue Alpha: {_rogueAlphaPixels}/{_file.Texture.Size.X * _file.Texture.Size.Y} pixels");

            ImGui.Text("Preview");
            ImGui.Image(new IntPtr(_previewTexture.Pointer), _previewTexture.Size);

            if (ImGui.Button("Normal Preview"))
            {
                UpdatePreview("normal");
            }
            ImGui.SameLine();
            if (ImGui.Button("Alpha Preview"))
            {
                UpdatePreview("alpha");
            }

            if (ImGui.Button("Apply Changes"))
            {
                UpdatePreview("export");
                byte[] pngData = PngFormat.Encode(_removedPixelData, (int)_previewTexture.Size.X, (int)_previewTexture.Size.Y);
                System.IO.File.WriteAllBytes(Helpers.CrossPlatformPath($"Assets/rogueAlphaRemoved_{System.IO.Path.GetFileName(_file.Name)}"), pngData);
            }
        }