Пример #1
0
        /// <summary>
        ///  Calculates the bitmap dimensions and creates a new bitmap (if requested) with text drawn to
        ///  according to the settings applied to this text renderer.
        /// </summary>
        /// <param name="isRequestingBitmapInfoOnly">
        ///  <para>Set to true to not produce a bitmap and measure what the bitmap size will be instead.</para>
        ///  <para>Set to false to create a bitmap with text rendered to it.</para>
        /// </param>
        /// <returns>
        ///  <para>
        ///   Returns a result object with the requested bitmap data if flagged successful.
        ///   If the "isRequestingBitmapInfoOnly" argument was set true, then the result object will only provide
        ///   BitmapInfo and its Bitmap property will be null.
        ///  </para>
        ///  <para>
        ///   Returns a failure result object if there was an error, in which case the the result's Message property
        ///   would provide details as to what went wrong.
        ///  </para>
        /// </returns>
        private TextBitmapDataResult AcquireBitmapData(bool isRequestingBitmapInfoOnly)
        {
            // Do not continue if there is no text to render.
            if (fSettings.Text.Length <= 0)
            {
                return(new TextBitmapDataResult("No text to render."));
            }

            // Do not continue if not called on the main UI thread.
            // Note: Microsoft's WriteableBitmap.render() method used below can only be called on the main UI thread.
            if (System.Windows.Deployment.Current.Dispatcher.CheckAccess() == false)
            {
                return(new TextBitmapDataResult("Text can only be rendered on the main UI thread."));
            }

            // Do not continue if Corona is currently synchronized with the rendering thread.
            // Note: Calling the WriteableBitmap.render() while the rendering thread is blocked will cause deadlock.
            if (Direct3DSurfaceAdapter.IsSynchronizedWithRenderingThread)
            {
                return(new TextBitmapDataResult("Cannot render text while Corona is synchronized with the rendering thread."));
            }

            // Create a Xaml text control to be used to render text to a bitmap.
            var textBlock = new System.Windows.Controls.TextBlock();

            textBlock.Foreground        = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.White);
            textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            textBlock.Text = fSettings.Text;

            // Set up the font.
            if (string.IsNullOrEmpty(fSettings.FontSettings.FamilyName) == false)
            {
                if (string.IsNullOrEmpty(fSettings.FontSettings.FilePath) == false)
                {
                    System.IO.FileStream stream = null;
                    try
                    {
                        stream = System.IO.File.OpenRead(fSettings.FontSettings.FilePath);
                        textBlock.FontSource = new System.Windows.Documents.FontSource(stream);
                    }
                    catch (Exception) { }
                    finally
                    {
                        if (stream != null)
                        {
                            try
                            {
                                stream.Close();
                                stream.Dispose();
                            }
                            catch (Exception) { }
                        }
                    }
                }
                textBlock.FontFamily = new System.Windows.Media.FontFamily(fSettings.FontSettings.FamilyName);
            }
            textBlock.FontSize   = fSettings.FontSettings.PointSize;
            textBlock.FontWeight =
                fSettings.FontSettings.IsBold ? System.Windows.FontWeights.Bold : System.Windows.FontWeights.Normal;
            textBlock.FontStyle =
                fSettings.FontSettings.IsItalic ? System.Windows.FontStyles.Italic : System.Windows.FontStyles.Normal;

            // Set up the horizontal alignment of the text.
            if (fSettings.HorizontalAlignment == WinRT.Interop.Graphics.HorizontalAlignment.Center)
            {
                textBlock.TextAlignment = System.Windows.TextAlignment.Center;
            }
            else if (fSettings.HorizontalAlignment == WinRT.Interop.Graphics.HorizontalAlignment.Right)
            {
                textBlock.TextAlignment = System.Windows.TextAlignment.Right;
            }
            else
            {
                textBlock.TextAlignment = System.Windows.TextAlignment.Left;
            }

            // Set up multiline text wrapping if enabled.
            if (fSettings.BlockWidth > 0)
            {
                // Enable text wrapping at the given pixel width.
                textBlock.TextWrapping = System.Windows.TextWrapping.Wrap;
                textBlock.MaxWidth     = (double)fSettings.BlockWidth;
                textBlock.Width        = (double)fSettings.BlockWidth;
            }
            else
            {
                // Disable text wrapping.
                textBlock.TextWrapping = System.Windows.TextWrapping.NoWrap;
            }
            if (fSettings.BlockHeight > 0)
            {
                textBlock.MaxHeight = (double)fSettings.BlockHeight;
                textBlock.Height    = (double)fSettings.BlockHeight;
            }

            // Calculate a pixel width and height for the bitmap to render text to.
            int bitmapWidth = fSettings.BlockWidth;

            if (bitmapWidth <= 0)
            {
                bitmapWidth = (int)(Math.Ceiling(textBlock.ActualWidth) + 0.1);
            }
            if ((fSettings.ClipWidth > 0) && (bitmapWidth > fSettings.ClipWidth))
            {
                bitmapWidth = fSettings.ClipWidth;
            }
            int bitmapHeight = fSettings.BlockHeight;

            if (bitmapHeight <= 0)
            {
                bitmapHeight = (int)(Math.Ceiling(textBlock.ActualHeight) + 0.1);
            }
            if ((fSettings.ClipHeight > 0) && (bitmapHeight > fSettings.ClipHeight))
            {
                bitmapHeight = fSettings.ClipHeight;
            }

            // Stop here if the caller is only requesting the resulting bitmap's measurements.
            if (isRequestingBitmapInfoOnly)
            {
                var bitmapSettings = new WinRT.Interop.Graphics.BitmapSettings();
                bitmapSettings.PixelFormat = WinRT.Interop.Graphics.PixelFormat.Grayscale;
                bitmapSettings.PremultipliedAlphaApplied = true;
                bitmapSettings.PixelWidth  = bitmapWidth;
                bitmapSettings.PixelHeight = bitmapHeight;
                return(new TextBitmapDataResult(new WinRT.Interop.Graphics.BitmapInfo(bitmapSettings)));
            }

            // Determine if the text contains any visible/printable characters.
            bool hasPrintableCharacters = false;

            foreach (char nextCharacter in textBlock.Text.ToCharArray())
            {
                if ((System.Char.IsWhiteSpace(nextCharacter) == false) && (System.Char.IsControl(nextCharacter) == false))
                {
                    hasPrintableCharacters = true;
                    break;
                }
            }

            // If there is no text to render, then stop here and return an empty bitmap.
            // Note: This is a huge optimization. No point in rendering text below if you can't see the characters.
            if (hasPrintableCharacters == false)
            {
                var bitmapSettings = new WinRT.Interop.Graphics.BitmapSettings();
                bitmapSettings.PixelFormat = WinRT.Interop.Graphics.PixelFormat.Grayscale;
                bitmapSettings.PremultipliedAlphaApplied = true;
                bitmapSettings.PixelWidth  = bitmapWidth;
                bitmapSettings.PixelHeight = bitmapHeight;
                var emptyGrayscaleBitmap = new WinRT.Interop.Graphics.Bitmap();
                emptyGrayscaleBitmap.FormatUsing(new WinRT.Interop.Graphics.BitmapInfo(bitmapSettings));
                return(new TextBitmapDataResult(emptyGrayscaleBitmap));
            }

            // If the text has been clipped, then shift the text within the bounds of the bitmap.
            System.Windows.Media.TranslateTransform transform = null;
            if (textBlock.ActualWidth > (double)bitmapWidth)
            {
                transform = new System.Windows.Media.TranslateTransform();
                if (textBlock.TextAlignment == System.Windows.TextAlignment.Right)
                {
                    transform.X = bitmapWidth - textBlock.ActualWidth;
                }
                else if (textBlock.TextAlignment == System.Windows.TextAlignment.Center)
                {
                    transform.X = (bitmapWidth - textBlock.ActualWidth) / 2.0;
                }
            }

            // Render the text to a 32-bit color bitmap.
            System.Windows.Media.Imaging.WriteableBitmap writeableBitmap = null;
            try
            {
                // Create the bitmap.
                writeableBitmap = new System.Windows.Media.Imaging.WriteableBitmap(bitmapWidth, bitmapHeight);

                // Create a rectangle used to render a black background.
                var backgroundColor     = System.Windows.Media.Colors.Black;
                var backgroundRectangle = new System.Windows.Shapes.Rectangle();
                backgroundRectangle.Width  = bitmapWidth;
                backgroundRectangle.Height = bitmapHeight;
                backgroundRectangle.Fill   = new System.Windows.Media.SolidColorBrush(backgroundColor);

                // Convert the background color object to a 32-bit integer.
                // To be compared with the bitmap's integer pixel array below.
                int backgroundColorAsInt32 =
                    ((int)backgroundColor.B) |
                    ((int)backgroundColor.G << 8) |
                    ((int)backgroundColor.R << 16) |
                    ((int)backgroundColor.A << 24);

                // Attempt to render text to the bitmap.
                // Note: There is a bug on Windows Phone where WriteableBitmap sometimes fails to render/inavlidate
                //       content if a Xaml DrawingSurfaceBackgroundGrid is being used by the application.
                //       If this happens, then we must attempt to render again. There is no other known work-around.
                bool wasDrawn = false;
                for (int renderAttempt = 1; renderAttempt <= 3; renderAttempt++)
                {
                    // Notify the owner(s) that we're about to render to the bitmap.
                    if (this.Rendering != null)
                    {
                        this.Rendering.Invoke(this, new DotNetWriteableBitmapEventArgs(writeableBitmap));
                    }

                    // Render the text and its black background to the bitmap.
                    writeableBitmap.Render(backgroundRectangle, null);
                    writeableBitmap.Render(textBlock, transform);
                    writeableBitmap.Invalidate();

                    // --- Verify that the above text was successfully drawn to the bitmap. ---

                    // First, check that the black rectangle was drawn to the bitmap.
                    // This is a fast check because we only need to read one pixel in the bitmap's top-left corner.
                    if (writeableBitmap.Pixels[0] != backgroundColorAsInt32)
                    {
                        continue;
                    }

                    // Next, check that text was drawn to the bitmap.
                    if (hasPrintableCharacters)
                    {
                        // Traverse all pixels in the bitmap until we find 1 pixel that does not match the background color.
                        for (int pixelIndex = writeableBitmap.Pixels.Length - 1; pixelIndex >= 0; pixelIndex--)
                        {
                            if (writeableBitmap.Pixels[pixelIndex] != backgroundColorAsInt32)
                            {
                                wasDrawn = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        // The given text does not contain any visible characters. So, we're done.
                        wasDrawn = true;
                    }

                    // Stop now if we've successfully drawn to the bitmap.
                    if (wasDrawn)
                    {
                        break;
                    }
                }

                // Log a failure if we were unable to render text.
                // Note: This still returns a bitmap. Should we?
                if (wasDrawn == false)
                {
                    String message = "Failed to create a bitmap for text: \"" + textBlock.Text + "\"\r\n";
                    Corona.WinRT.Interop.Logging.LoggingServices.Log(message);
                }
            }
            catch (Exception ex)
            {
                return(new TextBitmapDataResult(ex.Message));
            }

            // Convert the 32-bit color bitmap to 8-bit grayscale.
            var rgbaBitmap     = DotNetBitmap.From(writeableBitmap);
            var bitmapConveter = new WinRT.Interop.Graphics.BitmapConverter();

            bitmapConveter.PixelFormat = WinRT.Interop.Graphics.PixelFormat.Grayscale;
            var grayscaleBitmap = bitmapConveter.CreateBitmapFrom(rgbaBitmap);

            rgbaBitmap.ReleaseByteBuffer();
            if (grayscaleBitmap == null)
            {
                return(new TextBitmapDataResult("Failed to convert the 32-bit color text to a grayscale bitmap."));
            }

            // Return the text as a grayscaled bitmap.
            return(new TextBitmapDataResult(grayscaleBitmap));
        }
Пример #2
0
        /// <summary>Decodes the given image file and returns an uncompressed bitmap.</summary>
        /// <param name="filePath">The name and path of the image file to be decoded.</param>
        /// <returns>
        ///  <para>Returns the result of the image decoding operation.</para>
        ///  <para>
        ///   If the result object's HasSucceeded property is set true, then this decoder succeeded in decoding
        ///   the given image file and the result object's Bitmap property would provide the bitmap that was produced.
        ///  </para>
        ///  <para>
        ///   If the result object's HasSucceeded property is false, then this decoder failed to decode the
        ///   given image file. The reason why would then be provided by the result object's Message property.
        ///  </para>
        /// </returns>
        public WinRT.Interop.Graphics.BitmapResult DecodeFromFile(string filePath)
        {
            // Validate the given image file path.
            if (String.IsNullOrEmpty(filePath))
            {
                return(WinRT.Interop.Graphics.BitmapResult.FailedWith("Image decoder given a null or empty string."));
            }

            // Check that the given file exists and if its an external or embedded resource file.
            bool isExternalFile   = true;
            var  resourceServices = Corona.WinRT.Interop.Storage.DotNetResourceServices.Instance;

            if (System.IO.File.Exists(filePath) == false)
            {
                if (resourceServices.ContainsFile(filePath) == false)
                {
                    String message = String.Format("Image file '{0}' not found.", filePath);
                    return(WinRT.Interop.Graphics.BitmapResult.FailedWith(message));
                }
                isExternalFile = false;
            }

            // Ensure that the preferred pixel format is in the supported pixel format set.
            fSettings.SupportedPixelFormats.Add(fSettings.PreferredPixelFormat);

            Corona.WinRT.Interop.Graphics.IBitmap bitmap = null;
            System.IO.Stream stream = null;
            try
            {
                if (isExternalFile)
                {
                    stream = System.IO.File.OpenRead(filePath);
                }
                else
                {
                    stream = resourceServices.OpenFile(filePath);
                }
                var writeableBitmap = new System.Windows.Media.Imaging.WriteableBitmap(0, 0);
                writeableBitmap.SetSource(stream);
                bitmap          = DotNetBitmap.From(writeableBitmap);
                writeableBitmap = null;

                // Convert the loaded bitmap if it does not meet the decoder's requirements.
                if ((fSettings.SupportedPixelFormats.Contains(bitmap.Info.PixelFormat) == false) ||
                    (bitmap.Info.PixelWidth > fSettings.MaxPixelWidth) ||
                    (bitmap.Info.PixelHeight > fSettings.MaxPixelHeight))
                {
                    var converter = new WinRT.Interop.Graphics.BitmapConverter();
                    converter.CopySettingsFrom(this);
//					if (converter.CanConvert(bitmap))
//					{
//						converter.Convert(bitmap);
//					}
//					else
//					{
                    var convertedBitmap = converter.CreateBitmapFrom(bitmap);
                    bitmap.ReleaseByteBuffer();
                    bitmap = convertedBitmap;
//					}
                }
            }
            catch (Exception ex)
            {
                if (bitmap != null)
                {
                    try { bitmap.ReleaseByteBuffer(); }
                    catch (Exception) { }
                }
                return(WinRT.Interop.Graphics.BitmapResult.FailedWith(ex.Message));
            }
            finally
            {
                if (stream != null)
                {
                    try
                    {
                        stream.Close();
                        stream.Dispose();
                    }
                    catch (Exception) { }
                }
            }
            if (bitmap == null)
            {
                return(WinRT.Interop.Graphics.BitmapResult.FailedWith("Failed to load bitmap"));
            }

            return(WinRT.Interop.Graphics.BitmapResult.SucceededWith(bitmap));
        }