/// <summary> /// Function to transfer a 24 bit rgb image into a <see cref="IGorgonImageBuffer"/>. /// </summary> /// <param name="bitmapLock">The lock on the bitmap to transfer from.</param> /// <param name="buffer">The buffer to transfer into.</param> private static void Transfer24Rgb(BitmapData bitmapLock, IGorgonImageBuffer buffer) { unsafe { byte *pixels = (byte *)bitmapLock.Scan0.ToPointer(); for (int y = 0; y < bitmapLock.Height; y++) { // We only need the width here, as our pointer will handle the stride by virtue of being an int. byte *offset = pixels + (y * bitmapLock.Stride); int destOffset = y * buffer.PitchInformation.RowPitch; for (int x = 0; x < bitmapLock.Width; x++) { // The DXGI format nomenclature is a little confusing as we tend to think of the layout as being highest to // lowest, but in fact, it is lowest to highest. // So, we must convert to ABGR even though the DXGI format is RGBA. The memory layout is from lowest // (R at byte 0) to the highest byte (A at byte 3). // Thus, R is the lowest byte, and A is the highest: A(24), B(16), G(8), R(0). byte b = *offset++; byte g = *offset++; byte r = *offset++; var color = new GorgonColor(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f); int *destBuffer = (int *)(Unsafe.AsPointer(ref buffer.Data[destOffset])); * destBuffer = color.ToABGR(); destOffset += 4; } } } }
/// <summary> /// Function to convert the image data into a premultiplied format. /// </summary> /// <param name="baseImage">The image to convert.</param> /// <returns>A <see cref="IGorgonImage"/> containing the image data with the premultiplied alpha pixel data.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="baseImage"/> is <b>null</b>.</exception> /// <exception cref="ArgumentException">Thrown when the original format could not be converted to <see cref="BufferFormat.R8G8B8A8_UNorm"/>.</exception> /// <remarks> /// <para> /// Use this to convert an image to a premultiplied format. This takes each Red, Green and Blue element and multiplies them by the Alpha element. /// </para> /// <para> /// Because this method will only operate on <see cref="BufferFormat.R8G8B8A8_UNorm"/> formattted image data, the image will be converted to that format and converted back to its original format /// after the alpha is premultiplied. This may cause color fidelity issues. If the image cannot be converted, then an exception will be thrown. /// </para> /// </remarks> public static IGorgonImage ConvertToPremultipliedAlpha(this IGorgonImage baseImage) { IGorgonImage newImage = null; if (baseImage == null) { throw new ArgumentNullException(nameof(baseImage)); } try { // Worker image. var cloneImageInfo = new GorgonImageInfo(baseImage) { HasPreMultipliedAlpha = true }; newImage = new GorgonImage(cloneImageInfo); baseImage.CopyTo(newImage); if (newImage.Format != BufferFormat.R8G8B8A8_UNorm) { if (!newImage.CanConvertToFormat(BufferFormat.R8G8B8A8_UNorm)) { throw new ArgumentException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, BufferFormat.R8G8B8A8_UNorm), nameof(baseImage)); } // Clone the image so we can convert it to the correct format. newImage.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm); } unsafe { int *imagePtr = (int *)(newImage.ImageData); for (int i = 0; i < newImage.SizeInBytes; i += newImage.FormatInfo.SizeInBytes) { var color = GorgonColor.FromABGR(*imagePtr); color = new GorgonColor(color.Red * color.Alpha, color.Green * color.Alpha, color.Blue * color.Alpha, color.Alpha); *(imagePtr++) = color.ToABGR(); } } if (newImage.Format != baseImage.Format) { newImage.ConvertToFormat(baseImage.Format); } newImage.CopyTo(baseImage); return(baseImage); } finally { newImage?.Dispose(); } }
/// <summary> /// Function to detect if a sprite has no pixel data. /// </summary> /// <param name="bounds">The bounds of the sprite on the texture.</param> /// <param name="imageData">The system memory representation of the texture.</param> /// <param name="skipMask">The color used to mask which pixels are considered empty.</param> /// <returns><b>true</b> if sprite is empty, <b>false</b> if not.</returns> private bool IsEmpty(DX.Rectangle bounds, IGorgonImageBuffer imageData, GorgonColor skipMask) { int pixelSize = imageData.FormatInformation.SizeInBytes; int color = skipMask.ToABGR(); for (int y = bounds.Y; y < bounds.Bottom; ++y) { for (int x = bounds.X; x < bounds.Right; ++x) { // The last byte of the pixel should be the alpha (we force conversion to R8G8B8A8). int value = imageData.Data.ReadAs <int>((y * imageData.PitchInformation.RowPitch) + (x * pixelSize)); if (color != value) { return(false); } } } return(true); }