Draw text to a image

MinneMinne CNMember

I need draw some text to a image, I find object-c code, but I don't know how to translate to C#.

-(UIImage *)addText:(UIImage *)img text:(NSString *)text1

{

//get image width and height

int w = img.size.width;

int h = img.size.height;

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

//create a graphic context with CGBitmapContextCreate

CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);

CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);

CGContextSetRGBFillColor(context, 0.0, 1.0, 1.0, 1);

char* text = (char *)[text1 cStringUsingEncoding:NSASCIIStringEncoding];

CGContextSelectFont(context, "Georgia", 30, kCGEncodingMacRoman);

CGContextSetTextDrawingMode(context, kCGTextFill);

CGContextSetRGBFillColor(context, 255, 0, 0, 1);

CGContextSetTextMatrix(context, CGAffineTransformMakeRotation( -M_PI/4 ));

CGContextShowTextAtPoint(context, 60, 390, text, strlen(text));

//Create image ref from the context

CGImageRef imageMasked = CGBitmapContextCreateImage(context);

CGContextRelease(context);

CGColorSpaceRelease(colorSpace);

return [UIImage imageWithCGImage:imageMasked];

}

Any one can help?

Posts

  • PerryPerry USMember ✭✭
    edited March 2016

    For anyone else looking for this. Should get you close. Not thoroughly tested.

    public static UIImage DrawText(UIImage uiImage, string sText, UIColor textColor, int iFontSize)
            {
                nfloat fWidth = uiImage.Size.Width;
                nfloat fHeight = uiImage.Size.Height;
    
                CGColorSpace colorSpace = CGColorSpace.CreateDeviceRGB();
    
                using (CGBitmapContext ctx = new CGBitmapContext(IntPtr.Zero, (nint)fWidth, (nint)fHeight, 8, 4 * (nint)fWidth, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedFirst))
                {
                    ctx.DrawImage(new CGRect(0, 0, (double)fWidth, (double)fHeight), uiImage.CGImage);
    
                    ctx.SelectFont("Helvetica", iFontSize, CGTextEncoding.MacRoman);
    
                    //Measure the text's width - This involves drawing an invisible string to calculate the X position difference
                    float start, end, textWidth;
    
                    //Get the texts current position
                    start = (float)ctx.TextPosition.X;
                    //Set the drawing mode to invisible
                    ctx.SetTextDrawingMode(CGTextDrawingMode.Invisible);
                    //Draw the text at the current position
                    ctx.ShowText(sText);
                    //Get the end position
                    end = (float)ctx.TextPosition.X;
                    //Subtract start from end to get the text's width
                    textWidth = end - start;
    
                    nfloat fRed;
                    nfloat fGreen;
                    nfloat fBlue;
                    nfloat fAlpha;
                    //Set the fill color to black. This is the text color.
                    textColor.GetRGBA(out fRed, out fGreen, out fBlue, out fAlpha);
                    ctx.SetFillColor(fRed, fGreen, fBlue, fAlpha);
    
                    //Set the drawing mode back to something that will actually draw Fill for example
                    ctx.SetTextDrawingMode(CGTextDrawingMode.Fill);
    
                    //Draw the text at given coords.
                    ctx.ShowTextAtPoint(8, 17, sText);
    
                    return UIImage.FromImage(ctx.ToImage());
                }
            }
    

    Just noticed the comments are not accurate. I took this from something else I had done and changed it real quick.

  • DonCB2BDonCB2B USMember ✭✭✭

    @Perry said:
    For anyone else looking for this. Should get you close. Not thoroughly tested.

    public static UIImage DrawText(UIImage uiImage, string sText, UIColor textColor, int iFontSize)
          {
              nfloat fWidth = uiImage.Size.Width;
              nfloat fHeight = uiImage.Size.Height;
    
              CGColorSpace colorSpace = CGColorSpace.CreateDeviceRGB();
    
              using (CGBitmapContext ctx = new CGBitmapContext(IntPtr.Zero, (nint)fWidth, (nint)fHeight, 8, 4 * (nint)fWidth, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedFirst))
              {
                  ctx.DrawImage(new CGRect(0, 0, (double)fWidth, (double)fHeight), uiImage.CGImage);
    
                  ctx.SelectFont("Helvetica", iFontSize, CGTextEncoding.MacRoman);
    
                  //Measure the text's width - This involves drawing an invisible string to calculate the X position difference
                  float start, end, textWidth;
    
                  //Get the texts current position
                  start = (float)ctx.TextPosition.X;
                  //Set the drawing mode to invisible
                  ctx.SetTextDrawingMode(CGTextDrawingMode.Invisible);
                  //Draw the text at the current position
                  ctx.ShowText(sText);
                  //Get the end position
                  end = (float)ctx.TextPosition.X;
                  //Subtract start from end to get the text's width
                  textWidth = end - start;
    
                  nfloat fRed;
                  nfloat fGreen;
                  nfloat fBlue;
                  nfloat fAlpha;
                  //Set the fill color to black. This is the text color.
                  textColor.GetRGBA(out fRed, out fGreen, out fBlue, out fAlpha);
                  ctx.SetFillColor(fRed, fGreen, fBlue, fAlpha);
    
                  //Set the drawing mode back to something that will actually draw Fill for example
                  ctx.SetTextDrawingMode(CGTextDrawingMode.Fill);
    
                  //Draw the text at given coords.
                  ctx.ShowTextAtPoint(8, 17, sText);
    
                  return UIImage.FromImage(ctx.ToImage());
              }
          }
    

    Just noticed the comments are not accurate. I took this from something else I had done and changed it real quick.

    Hi, Perry . This is for iOS i think, It work great for me iOS.
    I wonder can you provide android one? I try to convert this code to android but i counter some problems.

  • BerayBentesenBerayBentesen TRUniversity ✭✭✭✭

    @DonChen check this post to draw text over bitmap for Xamarin Android.

  • PerryPerry USMember ✭✭

    @DonChen, sorry, don't have an Android version.

  • BerayBentesenBerayBentesen TRUniversity ✭✭✭✭

    @Perry do you have any idea or sample about how to draw shape ( e.g. rectangle, circle ) over UIIMage ?

  • PerryPerry USMember ✭✭

    @BerayBentesen, sorry, text is the only thing I have drawn over an image. But, I would think that you could do something with Core Graphics like draw a shape and then combine the image you draw with another image.

  • DonCB2BDonCB2B USMember ✭✭✭
    edited November 2016

    Is there any sample more relate to just add text on on the image ?

  • DonCB2BDonCB2B USMember ✭✭✭

    @Perry Can you direct some point to make this code to android. I am new with CustomRender.

  • PerryPerry USMember ✭✭

    @DonChen, sorry, I only develop for iOS. I would suggest you ask your question over on the Android forum. Somebody there could probably help you out.

  • PerryPerry USMember ✭✭

    @DonCB2B, your lucky day. Just found this. Hopefully it will help. If this works for you consider posting it over on the Android forum to help others. Disclaimer: I have not checked this to see if it works!

    string sMemberName = this._sFirstName + " " + this._sLastName;
    
                        int iCardLimit = 29;
                        int iNameLimit = 28;
    
                        using (Bitmap bmCard = BitmapFactory.DecodeResource(this._cContext.Resources, iDrawableID).Copy(Bitmap.Config.Argb8888, true))
                        {
                            float fScale = this._cContext.Resources.DisplayMetrics.Density;
    
                            Canvas cCanvas = new Canvas(bmCard);
                            cCanvas.Save();
    
                            float py = bmCard.Height / 2.0f;
                            float px = bmCard.Width / 2.0f;
                            //cCanvas.Rotate(90, px, py);
    
                            //card number
                            Paint pCardNumberPaint = new Paint(PaintFlags.AntiAlias);
                            pCardNumberPaint.SetStyle(Paint.Style.Fill);
                            pCardNumberPaint.Color = Color.Black;
                            pCardNumberPaint.TextSize = 60 * fScale;
    
                            string sCardSpaces = " ";
                            if ((iCardLimit) > this._sVkrNumber.Length)
                            {
                                sCardSpaces = new String(' ', iCardLimit - this._sVkrNumber.Length);
                            }
                            Rect rCardNumberBounds = new Rect();
                            string sCardNumberText = sCardSpaces + this._sVkrNumber;
                            pCardNumberPaint.GetTextBounds(sCardNumberText, 0, sCardNumberText.Length, rCardNumberBounds);
                            int iCardNumberX = (int)((bmCard.Width - rCardNumberBounds.Width()) / 2);
                            int iCardNumberY = (int)((bmCard.Height + rCardNumberBounds.Height()) * .2);
                            cCanvas.DrawText(sCardNumberText, iCardNumberX, iCardNumberY, pCardNumberPaint);
    
                            //member name
                            Paint pMemberNamePaint = new Paint(PaintFlags.AntiAlias);
                            pMemberNamePaint.SetStyle(Paint.Style.Fill);
                            pMemberNamePaint.Color = Color.Black;
                            pMemberNamePaint.TextSize = 40 * fScale;
    
                            if (sMemberName.Length > (iNameLimit - 3))
                            {
                                sMemberName = sMemberName.Substring(0, iNameLimit) + "...";
                            }
    
                            Rect rMemberNameBounds = new Rect();
                            string sMemberNameText = "  " + sMemberName;
                            pCardNumberPaint.GetTextBounds(sMemberNameText, 0, sMemberNameText.Length, rMemberNameBounds);
                            int iMemberNameX = 0;
                            int iMemberNameY = (int)((bmCard.Height + rMemberNameBounds.Height()) * .2);
                            cCanvas.DrawText(sMemberNameText, iMemberNameX, iMemberNameY, pMemberNamePaint);
    
                            if (File.Exists(sCardFileName))
                            {
                                File.Delete(sCardFileName);
                            }
    
                            using (FileStream swStreamWriter = File.Create(sCardFileName))
                            {
                                bmCard.Compress(Android.Graphics.Bitmap.CompressFormat.Jpeg, 80, swStreamWriter);
                                swStreamWriter.Flush();
                            }
    
                            bmCard.Recycle();
                            MemoryCacheImage();
                        }
    
  • DonCB2BDonCB2B USMember ✭✭✭

    @Perry would you mind providing the source of this code?

  • DonCB2BDonCB2B USMember ✭✭✭

    @Perry Thanks, I think code work fine ,but I didn't use all the code that you provide. The main idea is to create a canvas first, then create a paint. After that combine those two together.

  • CeeblajThojCeeblajThoj USMember

    @Perry said:
    @DonCB2B, your lucky day. Just found this. Hopefully it will help. If this works for you consider posting it over on the Android forum to help others. Disclaimer: I have not checked this to see if it works!

    string sMemberName = this._sFirstName + " " + this._sLastName;
    
                        int iCardLimit = 29;
                        int iNameLimit = 28;
    
                        using (Bitmap bmCard = BitmapFactory.DecodeResource(this._cContext.Resources, iDrawableID).Copy(Bitmap.Config.Argb8888, true))
                        {
                            float fScale = this._cContext.Resources.DisplayMetrics.Density;
    
                            Canvas cCanvas = new Canvas(bmCard);
                            cCanvas.Save();
    
                            float py = bmCard.Height / 2.0f;
                            float px = bmCard.Width / 2.0f;
                            //cCanvas.Rotate(90, px, py);
    
                            //card number
                            Paint pCardNumberPaint = new Paint(PaintFlags.AntiAlias);
                            pCardNumberPaint.SetStyle(Paint.Style.Fill);
                            pCardNumberPaint.Color = Color.Black;
                            pCardNumberPaint.TextSize = 60 * fScale;
    
                            string sCardSpaces = " ";
                            if ((iCardLimit) > this._sVkrNumber.Length)
                            {
                                sCardSpaces = new String(' ', iCardLimit - this._sVkrNumber.Length);
                            }
                            Rect rCardNumberBounds = new Rect();
                            string sCardNumberText = sCardSpaces + this._sVkrNumber;
                            pCardNumberPaint.GetTextBounds(sCardNumberText, 0, sCardNumberText.Length, rCardNumberBounds);
                            int iCardNumberX = (int)((bmCard.Width - rCardNumberBounds.Width()) / 2);
                            int iCardNumberY = (int)((bmCard.Height + rCardNumberBounds.Height()) * .2);
                            cCanvas.DrawText(sCardNumberText, iCardNumberX, iCardNumberY, pCardNumberPaint);
    
                            //member name
                            Paint pMemberNamePaint = new Paint(PaintFlags.AntiAlias);
                            pMemberNamePaint.SetStyle(Paint.Style.Fill);
                            pMemberNamePaint.Color = Color.Black;
                            pMemberNamePaint.TextSize = 40 * fScale;
    
                            if (sMemberName.Length > (iNameLimit - 3))
                            {
                                sMemberName = sMemberName.Substring(0, iNameLimit) + "...";
                            }
    
                            Rect rMemberNameBounds = new Rect();
                            string sMemberNameText = "  " + sMemberName;
                            pCardNumberPaint.GetTextBounds(sMemberNameText, 0, sMemberNameText.Length, rMemberNameBounds);
                            int iMemberNameX = 0;
                            int iMemberNameY = (int)((bmCard.Height + rMemberNameBounds.Height()) * .2);
                            cCanvas.DrawText(sMemberNameText, iMemberNameX, iMemberNameY, pMemberNamePaint);
    
                            if (File.Exists(sCardFileName))
                            {
                                File.Delete(sCardFileName);
                            }
    
                            using (FileStream swStreamWriter = File.Create(sCardFileName))
                            {
                                bmCard.Compress(Android.Graphics.Bitmap.CompressFormat.Jpeg, 80, swStreamWriter);
                                swStreamWriter.Flush();
                            }
    
                            bmCard.Recycle();
                            MemoryCacheImage();
                        }
    

    Hi can I have the "sCardFileName" declare variable string path?

    Thanks,

  • PerryPerry USMember ✭✭

    @CeeblajThoj ,

    string sCacheFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
    string sCardFileName = System.IO.Path.Combine(sCacheFolder, "myimage.jpg");
    
  • shortRevoltshortRevolt USMember ✭✭

    I used SkiaSharp library to draw/sketch on image.

    https://developer.xamarin.com/guides/xamarin-forms/advanced/skiasharp/paths/finger-paint/

    Right now, it does not support saving this sketch. I did a workaround by internally taking screenshot once sketch is done.

Sign In or Register to comment.