// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageProcessorCore { using System; using System.Diagnostics; /// /// The base class of all images. Encapsulates the basic properties and methods required to manipulate /// images in different pixel formats. /// /// The pixel format. /// The packed format. uint, long, float. [DebuggerDisplay("Image: {Width}x{Height}")] public abstract class ImageBase : IImageBase where TColor : struct, IPackedVector where TPacked : struct { /// /// The image pixels /// private TColor[] pixelBuffer; /// /// Initializes a new instance of the class. /// protected ImageBase() { } /// /// Initializes a new instance of the class. /// /// The width of the image in pixels. /// The height of the image in pixels. /// /// Thrown if either or are less than or equal to 0. /// protected ImageBase(int width, int height) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); this.Width = width; this.Height = height; this.pixelBuffer = new TColor[width * height]; } /// /// Initializes a new instance of the class. /// /// /// The other to create this instance from. /// /// /// Thrown if the given is null. /// protected ImageBase(ImageBase other) { Guard.NotNull(other, nameof(other), "Other image cannot be null."); this.Width = other.Width; this.Height = other.Height; this.CopyProperties(other); // Copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here. this.pixelBuffer = new TColor[this.Width * this.Height]; using (PixelAccessor sourcePixels = other.Lock()) using (PixelAccessor target = this.Lock()) { sourcePixels.CopyImage(target); } } /// public int MaxWidth { get; set; } = int.MaxValue; /// public int MaxHeight { get; set; } = int.MaxValue; /// public TColor[] Pixels => this.pixelBuffer; /// public int Width { get; private set; } /// public int Height { get; private set; } /// public double PixelRatio => (double)this.Width / this.Height; /// public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height); /// public int Quality { get; set; } /// public int FrameDelay { get; set; } /// public void SetPixels(int width, int height, TColor[] pixels) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.NotNull(pixels, nameof(pixels)); if (pixels.Length != width * height) { throw new ArgumentException("Pixel array must have the length of Width * Height."); } this.Width = width; this.Height = height; this.pixelBuffer = pixels; } /// public void ClonePixels(int width, int height, TColor[] pixels) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.NotNull(pixels, nameof(pixels)); if (pixels.Length != width * height) { throw new ArgumentException("Pixel array must have the length of Width * Height."); } this.Width = width; this.Height = height; // Copy the pixels. TODO: use Unsafe.Copy. this.pixelBuffer = new TColor[pixels.Length]; Array.Copy(pixels, this.pixelBuffer, pixels.Length); } /// public PixelAccessor Lock() { return new PixelAccessor(this); } /// /// Copies the properties from the other . /// /// /// The other to copy the properties from. /// protected void CopyProperties(ImageBase other) { this.Quality = other.Quality; this.FrameDelay = other.FrameDelay; } } }