// Once arranging is complete, copies each glyph to its chosen position in the single larger output bitmap.
        static PixelBitmapContent <Color> 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 PixelBitmapContent <RgbaVector> Resize(
            this BitmapContent bitmap, int newWidth, int newHeight)
        {
            BitmapContent src = bitmap;

            src.TryGetFormat(out SurfaceFormat format);
            if (format != SurfaceFormat.Vector4)
            {
                var v4 = new PixelBitmapContent <RgbaVector>(src.Width, src.Height);
                BitmapContent.Copy(src, v4);
                src = v4;
            }

            using (var image = Image.WrapMemory <RgbaVector>(src.GetPixelData(), new Size(src.Height, src.Width)))
                using (var resized = image.ProcessRows(x => x.Resize(new Size(newWidth, newHeight), 0)))
                {
                    var result = new PixelBitmapContent <RgbaVector>(newWidth, newHeight);
                    result.SetPixelData(resized.GetPixelSpan());
                    return(result);
                }
        }
Example #3
0
        protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
        {
            if (!sourceBitmap.TryGetFormat(out SurfaceFormat sourceFormat))
            {
                return(false);
            }

            TryGetFormat(out SurfaceFormat 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 (sourceBitmap is PixelBitmapContent <RgbaVector> &&
                sourceRegion.Width == destinationRegion.Width &&
                sourceRegion.Height == destinationRegion.Height)
            {
                // NVTT wants 8bit data in BGRA format.
                var colorBitmap = new PixelBitmapContent <Bgra32>(sourceBitmap.Width, sourceBitmap.Height);
                Copy(sourceBitmap, colorBitmap);
                var sourceData = colorBitmap.GetPixelData();

                AlphaMode alphaMode;
                Format    outputFormat;
                bool      alphaDither = false;
                switch (format)
                {
                case SurfaceFormat.Dxt1:
                case SurfaceFormat.Dxt1SRgb:
                {
                    PrepareNVTT_DXT1(sourceData, out bool 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.
                var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned);
                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);
            }

            try
            {
                Copy(sourceBitmap, sourceRegion, this, destinationRegion);
                return(true);
            }
            catch (InvalidOperationException)
            {
                return(false);
            }
        }
Example #4
0
        // Rasterizes a single character glyph.
        private Glyph ImportGlyph(Rune character, Face face)
        {
            uint glyphIndex = face.GetCharIndex((uint)character.Value);

            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 <Alpha8>(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 = Math.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 <Alpha8>(gHA, gVA);
            }

            // not sure about this at all
            var abc = new ABCFloat
            {
                A = face.Glyph.Metrics.HorizontalBearingX >> 6,
                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
            });
        }