public static void SetPixelData(this byte[] data, PixelBitmapContent <Color> bmpContent, SurfaceFormat format) { var formatSize = format.Size(); for (int y = 0; y < bmpContent.Height; y++) { for (int x = 0; x < bmpContent.Width; x++) { switch (format) { case SurfaceFormat.Vector4: var startIdx = (y * formatSize) + (x * formatSize); var vec4 = new Vector4(BitConverter.ToSingle(data, startIdx), BitConverter.ToSingle(data, startIdx + 4), BitConverter.ToSingle(data, startIdx + 8), BitConverter.ToSingle(data, startIdx + 12)); bmpContent._pixelData[y][x] = new Color(vec4); break; default: break; } } } }
public static BitmapContent ToXnaBitmap(this Bitmap systemBitmap) { // Any bitmap using this function should use 32bpp ARGB pixel format, since we have to // swizzle the channels later System.Diagnostics.Debug.Assert(systemBitmap.PixelFormat == PixelFormat.Format32bppArgb); var bitmapData = systemBitmap.LockBits(new System.Drawing.Rectangle(0, 0, systemBitmap.Width, systemBitmap.Height), ImageLockMode.ReadOnly, systemBitmap.PixelFormat); var length = bitmapData.Stride * bitmapData.Height; var pixelData = new byte[length]; // Copy bitmap to byte[] Marshal.Copy(bitmapData.Scan0, pixelData, 0, length); systemBitmap.UnlockBits(bitmapData); // NOTE: According to http://msdn.microsoft.com/en-us/library/dd183449%28VS.85%29.aspx // and http://stackoverflow.com/questions/8104461/pixelformat-format32bppargb-seems-to-have-wrong-byte-order // Image data from any GDI based function are stored in memory as BGRA/BGR, even if the format says RGBA. // Because of this we flip the R and B channels. BGRAtoRGBA(pixelData); var xnaBitmap = new PixelBitmapContent <Color>(systemBitmap.Width, systemBitmap.Height); xnaBitmap.SetPixelData(pixelData); return(xnaBitmap); }
/// <summary> /// Copies one bitmap into another. /// The destination bitmap can be in any format and size. If the destination is larger or smaller, the source bitmap is scaled accordingly. /// </summary> /// <param name="sourceBitmap">BitmapContent being copied.</param> /// <param name="sourceRegion">Region of sourceBitmap.</param> /// <param name="destinationBitmap">BitmapContent being overwritten.</param> /// <param name="destinationRegion">Region of bitmap to be overwritten.</param> public static void Copy(BitmapContent sourceBitmap, Rectangle sourceRegion, BitmapContent destinationBitmap, Rectangle destinationRegion) { ValidateCopyArguments(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion); SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) { throw new InvalidOperationException("Could not retrieve surface format of source bitmap"); } SurfaceFormat destinationFormat; if (!destinationBitmap.TryGetFormat(out destinationFormat)) { throw new InvalidOperationException("Could not retrieve surface format of destination bitmap"); } // If the formats are the same and the regions are the full bounds of the bitmaps and they are the same size, do a simpler copy if (sourceFormat == destinationFormat && sourceRegion == destinationRegion && sourceRegion == new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height) && destinationRegion == new Rectangle(0, 0, destinationBitmap.Width, destinationBitmap.Height)) { destinationBitmap.SetPixelData(sourceBitmap.GetPixelData()); return; } // The basic process is // 1. Copy from source bitmap region to a new PixelBitmapContent<Vector4> using sourceBitmap.TryCopyTo() // 2. If source and destination regions are a different size, resize Vector4 version // 3. Copy from Vector4 to destination region using destinationBitmap.TryCopyFrom() // Copy from the source to the intermediate Vector4 format var intermediate = new PixelBitmapContent <Vector4>(sourceRegion.Width, sourceRegion.Height); var intermediateRegion = new Rectangle(0, 0, intermediate.Width, intermediate.Height); if (sourceBitmap.TryCopyTo(intermediate, sourceRegion, intermediateRegion)) { // Resize the intermediate if required if (intermediate.Width != destinationRegion.Width || intermediate.Height != destinationRegion.Height) { intermediate = intermediate.Resize(destinationRegion.Width, destinationRegion.Height) as PixelBitmapContent <Vector4>; } // Copy from the intermediate to the destination if (destinationBitmap.TryCopyFrom(intermediate, new Rectangle(0, 0, intermediate.Width, intermediate.Height), destinationRegion)) { return; } } // If we got here, one of the above steps didn't work throw new InvalidOperationException("Could not copy between " + sourceFormat + " and " + destinationFormat); }
// Once arranging is complete, copies each glyph to its chosen position in the single larger output bitmap. static BitmapContent CopyGlyphsToOutput(List <ArrangedGlyph> glyphs, int width, int height) { var output = new PixelBitmapContent <Color>(width, height); foreach (var glyph in glyphs) { var sourceGlyph = glyph.Source; var sourceRegion = sourceGlyph.Subrect; var destinationRegion = new Rectangle(glyph.X + 1, glyph.Y + 1, sourceRegion.Width, sourceRegion.Height); BitmapContent.Copy(sourceGlyph.Bitmap, sourceRegion, output, destinationRegion); sourceGlyph.Bitmap = output; sourceGlyph.Subrect = destinationRegion; } return(output); }
internal static void Resize(this TextureContent content, int newWidth, int newHeight) { var resizedBmp = new Bitmap(newWidth, newHeight); using (var graphics = System.Drawing.Graphics.FromImage(resizedBmp)) { graphics.DrawImage(content._bitmap, 0, 0, newWidth, newHeight); content._bitmap.Dispose(); content._bitmap = resizedBmp; } var imageData = content._bitmap.GetData(); var bitmapContent = new PixelBitmapContent <Color>(content._bitmap.Width, content._bitmap.Height); bitmapContent.SetPixelData(imageData); content.Faces.Clear(); content.Faces.Add(new MipmapChain(bitmapContent)); }
internal static BitmapContent Resize(this BitmapContent bitmap, int newWidth, int newHeight) { BitmapContent src = bitmap; SurfaceFormat format; src.TryGetFormat(out format); if (format != SurfaceFormat.Vector4) { var v4 = new PixelBitmapContent <Vector4>(src.Width, src.Height); BitmapContent.Copy(src, v4); src = v4; } // Convert to FreeImage bitmap var bytes = src.GetPixelData(); var fi = FreeImage.ConvertFromRawBits(bytes, FREE_IMAGE_TYPE.FIT_RGBAF, src.Width, src.Height, SurfaceFormat.Vector4.GetSize() * src.Width, 128, 0, 0, 0, true); // Resize var newfi = FreeImage.Rescale(fi, newWidth, newHeight, FREE_IMAGE_FILTER.FILTER_BICUBIC); FreeImage.UnloadEx(ref fi); // Convert back to PixelBitmapContent<Vector4> src = new PixelBitmapContent <Vector4>(newWidth, newHeight); bytes = new byte[SurfaceFormat.Vector4.GetSize() * newWidth * newHeight]; FreeImage.ConvertToRawBits(bytes, newfi, SurfaceFormat.Vector4.GetSize() * newWidth, 128, 0, 0, 0, true); src.SetPixelData(bytes); FreeImage.UnloadEx(ref newfi); // Convert back to source type if required if (format != SurfaceFormat.Vector4) { var s = (BitmapContent)Activator.CreateInstance(bitmap.GetType(), new object[] { newWidth, newHeight }); BitmapContent.Copy(src, s); src = s; } return(src); }
public static void SetPixelData <T>(this byte[] data, PixelBitmapContent <T> bmpContent, int startIndex, SurfaceFormat format) where T : struct, IEquatable <T> { }
protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion) { SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) { return(false); } SurfaceFormat format; TryGetFormat(out format); // A shortcut for copying the entire bitmap to another bitmap of the same type and format if (format == sourceFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion) { SetPixelData(sourceBitmap.GetPixelData()); return(true); } // TODO: Add a XNA unit test to see what it does // my guess is that this is invalid for DXT. // // Destination region copy is not yet supported if (destinationRegion != new Rectangle(0, 0, Width, Height)) { return(false); } // If the source is not Vector4 or requires resizing, send it through BitmapContent.Copy if (!(sourceBitmap is PixelBitmapContent <Vector4>) || sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height) { try { BitmapContent.Copy(sourceBitmap, sourceRegion, this, destinationRegion); return(true); } catch (InvalidOperationException) { return(false); } } // NVTT wants 8bit data in BGRA format. var colorBitmap = new PixelBitmapContent <Color>(sourceBitmap.Width, sourceBitmap.Height); BitmapContent.Copy(sourceBitmap, colorBitmap); var sourceData = colorBitmap.GetPixelData(); var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned); AlphaMode alphaMode; Format outputFormat; var alphaDither = false; switch (format) { case SurfaceFormat.Dxt1: case SurfaceFormat.Dxt1SRgb: { bool hasTransparency; PrepareNVTT_DXT1(sourceData, out hasTransparency); outputFormat = hasTransparency ? Format.DXT1a : Format.DXT1; alphaMode = hasTransparency ? AlphaMode.Transparency : AlphaMode.None; alphaDither = true; break; } case SurfaceFormat.Dxt3: case SurfaceFormat.Dxt3SRgb: { PrepareNVTT(sourceData); outputFormat = Format.DXT3; alphaMode = AlphaMode.Transparency; break; } case SurfaceFormat.Dxt5: case SurfaceFormat.Dxt5SRgb: { PrepareNVTT(sourceData); outputFormat = Format.DXT5; alphaMode = AlphaMode.Transparency; break; } default: throw new InvalidOperationException("Invalid DXT surface format!"); } // Do all the calls to the NVTT wrapper within this handler // so we properly clean up if things blow up. try { var dataPtr = dataHandle.AddrOfPinnedObject(); var inputOptions = new InputOptions(); inputOptions.SetTextureLayout(TextureType.Texture2D, colorBitmap.Width, colorBitmap.Height, 1); inputOptions.SetMipmapData(dataPtr, colorBitmap.Width, colorBitmap.Height, 1, 0, 0); inputOptions.SetMipmapGeneration(false); inputOptions.SetGamma(1.0f, 1.0f); inputOptions.SetAlphaMode(alphaMode); var compressionOptions = new CompressionOptions(); compressionOptions.SetFormat(outputFormat); compressionOptions.SetQuality(Quality.Normal); // TODO: This isn't working which keeps us from getting the // same alpha dither behavior on DXT1 as XNA. // // See https://github.com/MonoGame/MonoGame/issues/6259 // //if (alphaDither) //compressionOptions.SetQuantization(false, false, true); var outputOptions = new OutputOptions(); outputOptions.SetOutputHeader(false); outputOptions.SetOutputOptionsOutputHandler(NvttBeginImage, NvttWriteImage, NvttEndImage); var dxtCompressor = new Compressor(); dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions); } finally { dataHandle.Free(); } return(true); }
protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion) { SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) { return(false); } SurfaceFormat format; TryGetFormat(out format); // A shortcut for copying the entire bitmap to another bitmap of the same type and format if (format == sourceFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion) { SetPixelData(sourceBitmap.GetPixelData()); return(true); } // Destination region copy is not yet supported if (destinationRegion != new Rectangle(0, 0, Width, Height)) { return(false); } // If the source is not Vector4 or requires resizing, send it through BitmapContent.Copy if (!(sourceBitmap is PixelBitmapContent <Vector4>) || sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height) { try { BitmapContent.Copy(sourceBitmap, sourceRegion, this, destinationRegion); return(true); } catch (InvalidOperationException) { return(false); } } // Convert to full colour 32-bit format. Floating point would be preferred for processing, but it appears the ATICompressor does not support this var colorBitmap = new PixelBitmapContent <Color>(sourceRegion.Width, sourceRegion.Height); BitmapContent.Copy(sourceBitmap, sourceRegion, colorBitmap, new Rectangle(0, 0, colorBitmap.Width, colorBitmap.Height)); sourceBitmap = colorBitmap; ATICompressor.CompressionFormat targetFormat; switch (format) { case SurfaceFormat.RgbaAtcExplicitAlpha: targetFormat = ATICompressor.CompressionFormat.AtcRgbaExplicitAlpha; break; case SurfaceFormat.RgbaAtcInterpolatedAlpha: targetFormat = ATICompressor.CompressionFormat.AtcRgbaInterpolatedAlpha; break; default: return(false); } var sourceData = sourceBitmap.GetPixelData(); var compressedData = ATICompressor.Compress(sourceData, Width, Height, targetFormat); SetPixelData(compressedData); return(true); }
protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion) { SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) { return(false); } SurfaceFormat format; TryGetFormat(out format); // A shortcut for copying the entire bitmap to another bitmap of the same type and format if (format == sourceFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion) { SetPixelData(sourceBitmap.GetPixelData()); return(true); } // Destination region copy is not yet supported if (destinationRegion != new Rectangle(0, 0, Width, Height)) { return(false); } // If the source is not Vector4 or requires resizing, send it through BitmapContent.Copy if (!(sourceBitmap is PixelBitmapContent <Vector4>) || sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height) { try { BitmapContent.Copy(sourceBitmap, sourceRegion, this, destinationRegion); return(true); } catch (InvalidOperationException) { return(false); } } //SquishFlags targetFormat = SquishFlags.ColourClusterFit; Format outputFormat = Format.DXT1; switch (format) { case SurfaceFormat.Dxt1: outputFormat = Format.DXT1; break; case SurfaceFormat.Dxt1SRgb: outputFormat = Format.DXT1; break; case SurfaceFormat.Dxt3: outputFormat = Format.DXT3; break; case SurfaceFormat.Dxt3SRgb: outputFormat = Format.DXT3; break; case SurfaceFormat.Dxt5: outputFormat = Format.DXT5; break; case SurfaceFormat.Dxt5SRgb: outputFormat = Format.DXT5; break; default: return(false); } // libsquish requires RGBA8888 var colorBitmap = new PixelBitmapContent <Color>(sourceBitmap.Width, sourceBitmap.Height); BitmapContent.Copy(sourceBitmap, colorBitmap); var sourceData = colorBitmap.GetPixelData(); /* * var dataSize = Squish.GetStorageRequirements(colorBitmap.Width, colorBitmap.Height, targetFormat); * var data = new byte[dataSize]; * var metric = new float[] { 1.0f, 1.0f, 1.0f }; * Squish.CompressImage(sourceData, colorBitmap.Width, colorBitmap.Height, data, targetFormat, metric); * SetPixelData(data); */ var dxtCompressor = new Compressor(); var inputOptions = new InputOptions(); if (outputFormat != Format.DXT1) { inputOptions.SetAlphaMode(AlphaMode.Premultiplied); } else { inputOptions.SetAlphaMode(AlphaMode.None); } inputOptions.SetTextureLayout(TextureType.Texture2D, colorBitmap.Width, colorBitmap.Height, 1); // Small hack here. NVTT wants 8bit data in BGRA. Flip the B and R channels // again here. GraphicsUtil.BGRAtoRGBA(sourceData); var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned); try { var dataPtr = dataHandle.AddrOfPinnedObject(); inputOptions.SetMipmapData(dataPtr, colorBitmap.Width, colorBitmap.Height, 1, 0, 0); inputOptions.SetMipmapGeneration(false); inputOptions.SetGamma(1.0f, 1.0f); var outputOptions = new OutputOptions(); outputOptions.SetOutputHeader(false); var handler = new DxtDataHandler(this); outputOptions.SetOutputHandler(handler.BeginImage, handler.WriteData); var compressionOptions = new CompressionOptions(); compressionOptions.SetFormat(outputFormat); compressionOptions.SetQuality(Quality.Normal); dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions); } finally { dataHandle.Free(); } return(true); }
// Rasterizes a single character glyph. private Glyph ImportGlyph(char character, Face face) { uint glyphIndex = face.GetCharIndex(character); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); // Render the character. BitmapContent glyphBitmap = null; if (face.Glyph.Bitmap.Width > 0 && face.Glyph.Bitmap.Rows > 0) { glyphBitmap = new PixelBitmapContent <byte>(face.Glyph.Bitmap.Width, face.Glyph.Bitmap.Rows); byte[] gpixelAlphas = new byte[face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows]; //if the character bitmap has 1bpp we have to expand the buffer data to get the 8bpp pixel data //each byte in bitmap.bufferdata contains the value of to 8 pixels in the row //if bitmap is of width 10, each row has 2 bytes with 10 valid bits, and the last 6 bits of 2nd byte must be discarded if (face.Glyph.Bitmap.PixelMode == PixelMode.Mono) { //variables needed for the expansion, amount of written data, length of the data to write int written = 0, length = face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows; for (int i = 0; written < length; i++) { //width in pixels of each row int width = face.Glyph.Bitmap.Width; while (width > 0) { //valid data in the current byte int stride = MathHelper.Min(8, width); //copy the valid bytes to pixeldata //System.Array.Copy(ExpandByte(face.Glyph.Bitmap.BufferData[i]), 0, gpixelAlphas, written, stride); ExpandByteAndCopy(face.Glyph.Bitmap.BufferData[i], stride, gpixelAlphas, written); written += stride; width -= stride; if (width > 0) { i++; } } } } else { Marshal.Copy(face.Glyph.Bitmap.Buffer, gpixelAlphas, 0, gpixelAlphas.Length); } glyphBitmap.SetPixelData(gpixelAlphas); } if (glyphBitmap == null) { var gHA = face.Glyph.Metrics.HorizontalAdvance >> 6; var gVA = face.Size.Metrics.Height >> 6; gHA = gHA > 0 ? gHA : gVA; gVA = gVA > 0 ? gVA : gHA; glyphBitmap = new PixelBitmapContent <byte>(gHA, gVA); } // not sure about this at all var abc = new ABCFloat(); abc.A = face.Glyph.Metrics.HorizontalBearingX >> 6; abc.B = face.Glyph.Metrics.Width >> 6; abc.C = (face.Glyph.Metrics.HorizontalAdvance >> 6) - (abc.A + abc.B); // Construct the output Glyph object. return(new Glyph(character, glyphBitmap) { XOffset = -(face.Glyph.Advance.X >> 6), XAdvance = face.Glyph.Metrics.HorizontalAdvance >> 6, YOffset = -(face.Glyph.Metrics.HorizontalBearingY >> 6), CharacterWidths = abc }); }