3

Can one create a 9-patch at runtime in Xamarin/Android?

This is the same as this question or this question, but working under Xamarin. A naive translation of the answer given there produces distorted nine-patches.

In the image below, the original image is the top left -- the following code correctly does nothing to it. The remaining ones are supposed to be 9-patches. What appears to be happening is that the top left is stretched, rather than the center as it should be.

enter image description here

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using Android.Graphics;
using Android.Graphics.Drawables;
using Java.IO;
using Android.Content.Res;
using System.IO;
using System.Drawing;

namespace Android9PatchFail
{
  public class ImageCanvas : View
  {
    public ImageCanvas (Context context) :
      base(context)
    {
      Initialize();
    }
    public ImageCanvas (Context context, IAttributeSet attrs) :
      base(context, attrs)
    {
      Initialize();
    }
    public ImageCanvas (Context context, IAttributeSet attrs, int defStyle) :
      base(context, attrs, defStyle)
    {
      Initialize();
    }
    void Initialize () {
      this.SetBackgroundColor(Android.Graphics.Color.White);
    }
    public Bitmap ImageBitmap {
      get {
        AssetManager manager = this.Resources.Assets;
        Stream stream = manager.Open("buttonb.png");
        Bitmap r = BitmapFactory.DecodeStream(stream);
        return r;
      }
    }
    protected override void OnDraw (Canvas canvas) {
      base.OnDraw(canvas);
      Bitmap bitmap = this.ImageBitmap;
      Paint paint = new Paint();
      //      canvas.DrawBitmap(bitmap, 20, 20, paint);
      float bitmapWidth = bitmap.Width;
      float bitmapHeight = bitmap.Height;
//      this.DrawScaledImage(canvas, bitmap, 20, 50, new Size(100, 100));
      Random rand = new Random();

      double growthFactor = 0.5; rand.NextDouble();
        int top = 4; // 4 12 18 14 did give output with growth of 0.174.
        int left = 12;
        int bottom = 18;
        int right = 14;
        System.Diagnostics.Debug.WriteLine("Growth is " + growthFactor);
        System.Diagnostics.Debug.WriteLine("Insets are " + top + " " + left + " " + bottom + " " + right);
        for (int i = 0; i < 9; i++) {
          int row = i / 3;
          int column = i % 3;

          int width = (int) ((1 + column*growthFactor) * bitmapWidth);
          float x = 20;
          switch (column) {
            case 1: x = 200; break;
            case 2: x = 450; break;
            default: break;
          }
          float y = 40 + 160 * row;
          int height = (int) ((1 + row*growthFactor) * bitmapHeight);
          Size size = new Size(width, height);
          //        this.DrawScaledImage(canvas, bitmap, x, y, size);
          this.DrawNinePatchBitmap(canvas, bitmap, x, y, top, left, bottom, right, size);
          //        this.DrawNinePatchBitmap(canvas, bitmap, 200, 100, 1, 1, 5, 5, new SizeF(2 * bitmapWidth, 2 * bitmapHeight));
        }
    }
    public void DrawScaledImage (Canvas canvas, Bitmap bitmapToStretch, float x, float y, Size requestedSize) {
      Android.Graphics.Bitmap b = Android.Graphics.Bitmap.CreateScaledBitmap(bitmapToStretch, requestedSize.Width, requestedSize.Height, false);
      canvas.DrawBitmap(b, x, y, null);
    }

    public void DrawNinePatchBitmap (Canvas canvas, Android.Graphics.Bitmap bitmapToStretch, float x, float y, int top, int left, int right, int bottom, SizeF requestedSize)
    {
      RectF rect = new RectF(x, y, x+requestedSize.Width, y+requestedSize.Height);
//      System.Diagnostics.Debug.WriteLine("Rect is " + x + "  " + y + "  " + requestedSize.Width + "  " + requestedSize.Height);
      NinePatch npBitmap = CreateNinePatch(bitmapToStretch, top, left, bottom, right);
      npBitmap.Draw(canvas, rect);
    }

    private NinePatch CreateNinePatch(Android.Graphics.Bitmap bitmap, int top, int left, int bottom, int right) {
      MemoryStream buffer = GetMemoryStream(top, left, bottom, right);
      NinePatch patch = new NinePatch(bitmap, buffer.ToArray(), "blah");
      return patch;
    }

    private MemoryStream GetMemoryStream(int top, int left, int bottom, int right) {
      //Docs check the NinePatchChunkFile
      MemoryStream buffer = new MemoryStream(new byte[84]);
      using (BinaryWriter writer = new BinaryWriter(buffer)) {
        //was translated
        writer.Write(new byte[] { 0x01 });
        //divx size
        writer.Write(new byte[] { 0x02 });
        //divy size
        writer.Write(new byte[] { 0x02 });
        //color size
        writer.Write(new byte[] { 0x09 });

        //skip
        writer.Write(0);
        writer.Write(0);

        //padding
        writer.Write(0);
        writer.Write(0);
        writer.Write(0);
        writer.Write(0);
        //writer.Write(left);
        //writer.Write(right);
        //writer.Write(top);
        //writer.Write(bottom);

        //skip 4 bytes
        writer.Write(0);

        //offsets
        writer.Write(left);
        writer.Write(right);
        writer.Write(top);
        writer.Write(bottom);
        //No color
        writer.Write(0x00000001);
        writer.Write(0x00000001);
        writer.Write(0x00000001);
        writer.Write(0x00000001);
        writer.Write(0x00000001);
        writer.Write(0x00000001);
        writer.Write(0x00000001);
        writer.Write(0x00000001);
        writer.Write(0x00000001);
      }

      return buffer;
    }
  }
}
Community
  • 1
  • 1
William Jockusch
  • 26,513
  • 49
  • 182
  • 323
  • have you tried to convert the source of this gist? https://gist.github.com/briangriffey/4391807 – Antonio E. Apr 11 '14 at 13:22
  • 6
    @WilliamJockusch - probably if you could provide more information on your question for your specific case, that would help more people to provide you better answers, than just redirecting to previous two posts I guess. – Avanz Apr 13 '14 at 01:32
  • Have you tried XobotOS ? – kAnNaN Apr 15 '14 at 05:45
  • A naive translation should work with Xamarin. However, I have been developing with Xamarin since about a year by now and it happens fairly often that some implementation are incorrect or missing. You should try your luck on the [Xamarin Forum](http://forums.xamarin.com/) as well, but it is most likely that you actually found a bug in Xamarin Android. I would report the detailed problem on [their bug tracker](https://bugzilla.xamarin.com/) anyway. – ForceMagic Apr 15 '14 at 18:50

1 Answers1

0

XobotOS is a semi-automated port of the Android 4.0 source code from Java to C#. The automated parts were ported using an improved version of Sharpen that can compile more advanced Java constructs and supports generics.

You could try using this as directed by @kanzure's answer form this question

Community
  • 1
  • 1
kAnNaN
  • 3,669
  • 4
  • 28
  • 39