/// <summary> /// Strech the bitmap without interpolation. /// </summary> public ARGBImageData StretchSimple(int width, int height) { if (height < 0) { height = Height; } if (width < 0) { width = Width; } var result = new ARGBImageData(width, height); int targetIndex = 0; int moveX = (Width << 10) / width; int moveY = ((Height << 10) / height) - 1; int tY = 0; for (int y = 0; y < height; y++) { int tX = 0; for (int x = 0; x < width; x++) { int sourceIndex = PositionToIndex(tX >> 10, tY >> 10); result.Data[targetIndex++] = Data[sourceIndex]; tX += moveX; } tY += moveY; } return(result); }
/// <summary> /// Tile the bitmap. /// </summary> public ARGBImageData TileSimple(int width, int height) { if (height < 0) { height = Height; } if (width < 0) { width = Width; } var result = new ARGBImageData(width, height); int w = Width; int h = Height; int targetIndex = 0; for (int y = 0; y < height; y++) { int tY = y % h; for (int x = 0; x < width; x++) { int tX = x % w; int sourceIndex = PositionToIndex(tX, tY); result.Data[targetIndex++] = Data[sourceIndex]; } } return(result); }
/// <summary> /// Writes all data to a new <see cref="SKBitmap"/> instance /// </summary> /// <returns></returns> /// <exception cref="Exception">Invalid length!</exception> public static SKBitmap ToSKBitmap(this ARGBImageData imageData) { SKImageInfo imgInfo = new SKImageInfo(imageData.Width, imageData.Height, SKColorType.Rgba8888, SKAlphaType.Unpremul); var bitmap = SKBitmap.FromImage(SkiaSharp.SKImage.Create(imgInfo)); IntPtr len; IntPtr ptr = bitmap.GetPixels(out len); int byteLen = imageData.Data.Length * 4; if (len.ToInt32() != byteLen) { throw new Exception("Invalid length!"); } Marshal.Copy(imageData.Data, 0, ptr, imageData.Data.Length); return(bitmap); }
/// <summary>Creates a bitmap instance from the specified data.</summary> public Bitmap32 Create(ARGBImageData data) { return(new GdiBitmap32(data)); }
/// <summary> /// Tiles the outer border of the image and centers it. /// </summary> public ARGBImageData CenterTile(int width, int height) { if (height < 0) { height = Height; } if (width < 0) { width = Width; } bool l_TileY = height != Height; bool l_TileX = width != Width; // only tile one direction at the moment ! maybe later... if (l_TileX && l_TileY) { throw new NotSupportedException(); } var result = new ARGBImageData(width, height); int heightCenterTop = (height - Height) / 2; if (l_TileY) { int heightCenterBottom = (height + Height) / 2; // fill top int sourceIndex = PositionToIndex(0, 0); for (int y = heightCenterTop; y >= 0; y--) { int targetIndex = result.PositionToIndex(0, y); Array.Copy(Data, sourceIndex, result.Data, targetIndex, Width); } // fill bottom sourceIndex = PositionToIndex(0, Height - 1); for (int y = heightCenterBottom; y < height; y++) { int targetIndex = result.PositionToIndex(0, y); Array.Copy(Data, sourceIndex, result.Data, targetIndex, Width); } } int widthCenterLeft = (width - Width) / 2; if (l_TileX) { int widthCenterRight = (width + Width) / 2; // fill left for (int y = 0; y < Height; y++) { int sourceIndex = PositionToIndex(0, y); for (int x = widthCenterLeft; x >= 0; x--) { int targetIndex = result.PositionToIndex(x, y); result.Data[targetIndex] = Data[sourceIndex]; } // fill right sourceIndex = PositionToIndex(0, Height - 1); for (int x = widthCenterRight; x < width; x++) { int targetIndex = result.PositionToIndex(x, y); result.Data[targetIndex] = Data[sourceIndex]; } } } // copy center for (int y = 0; y < Height; y++) { int sourceIndex = PositionToIndex(0, y); int targetIndex = result.PositionToIndex(widthCenterLeft, y + heightCenterTop); Array.Copy(Data, sourceIndex, result.Data, targetIndex, Width); } return(result); }
/// <summary> /// Creates a 32x32 fingerprint for the specified bitmap. /// </summary> /// <param name="bitmap">The bitmap.</param> /// <returns>Returns a fingerprint with 6 bits per pixel (32 px = 6144 bit = 768 byte = 1024 base32 chars).</returns> public static FingerPrint Create(IBitmap32 bitmap) { using (Bitmap32 thumb = bitmap.Resize(32, 32, ResizeMode.TouchFromInside)) { ARGBImageData data = thumb.Data; using (var ms = new MemoryStream()) { // calculate fingerprint and distance matrix var writer = new BitStreamWriter(ms); float[] distanceMatrix = new float[16]; { int x = 0, y = 0; ARGB last = 0; foreach (ARGB pixel in data.Data) { if (++x > 15) { x = 0; ++y; } int r = pixel.Red >> 6; int g = pixel.Green >> 6; int b = pixel.Blue >> 6; writer.WriteBits(r, 2); writer.WriteBits(g, 2); writer.WriteBits(b, 2); unchecked { int i = ((y << 1) & 0xC) + (x >> 2); float distance = Math.Abs(pixel.GetDistance(last)); distanceMatrix[i] += distance; last = pixel; } } } // normalize matrix float maxDistance = distanceMatrix.Max(); for (int i = 0; i < distanceMatrix.Length; i++) { distanceMatrix[i] /= maxDistance; } // calculate blocks uint[] blocks = new uint[4]; int[] index = new int[] { 0, 2, 8, 10 }; for (int i = 0; i < 4; i++) { int idx = index[i]; uint blockValue = (uint)(255 * distanceMatrix[idx]) << 24; blockValue |= (uint)(255 * distanceMatrix[idx + 1]) << 16; blockValue |= (uint)(255 * distanceMatrix[idx + 4]) << 8; blockValue |= (uint)(255 * distanceMatrix[idx + 5]); blocks[i] = blockValue; } /* * uint b1 = (uint)(uint.MaxValue * (distanceMatrix[0] + distanceMatrix[1] + distanceMatrix[4] + distanceMatrix[5]) /4); * uint b2 = (uint)(uint.MaxValue * (distanceMatrix[3] + distanceMatrix[2] + distanceMatrix[7] + distanceMatrix[6]) / 4); * uint b3 = (uint)(uint.MaxValue * (distanceMatrix[12] + distanceMatrix[13] + distanceMatrix[8] + distanceMatrix[9]) / 4); * uint b4 = (uint)(uint.MaxValue * (distanceMatrix[15] + distanceMatrix[14] + distanceMatrix[11] + distanceMatrix[10]) / 4); */ return(new FingerPrint(32, blocks, ms.ToArray())); } } }
/// <summary>Draws the specified image ontop of this one.</summary> /// <param name="other">The image to draw.</param> /// <param name="x">The x position.</param> /// <param name="y">The y position.</param> /// <param name="width">The width.</param> /// <param name="height">The height.</param> /// <param name="translation">The translation.</param> public virtual void Draw(ARGBImageData other, int x, int y, int width, int height, Translation?translation = null) { bitmap.Draw(other, x, y, width, height, translation); }
/// <summary>Creates a bitmap instance from the specified data.</summary> public Bitmap32 Create(ARGBImageData data) => new GdiBitmap32(data);
/// <summary>Draws the specified image ontop of this one.</summary> /// <param name="other">The image to draw.</param> /// <param name="x">The x position.</param> /// <param name="y">The y position.</param> /// <param name="width">The width.</param> /// <param name="height">The height.</param> /// <param name="translation">The translation.</param> public override void Draw(ARGBImageData other, int x, int y, int width, int height, Translation?translation = null) { Draw(other.ToSKBitmap(), x, y, width, height, translation); }
/// <summary> /// Initializes a new instance of the <see cref="SkiaBitmap32"/> class. /// </summary> /// <param name="data">The data.</param> public SkiaBitmap32(ARGBImageData data) { bitmap = data.ToSKBitmap(); }
/// <summary>Initializes a new instance of the <see cref="GdiBitmap32"/> class.</summary> /// <param name="data"></param> public GdiBitmap32(ARGBImageData data) : this(data.ToGdiBitmap()) { }