By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,906 Members | 1,715 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,906 IT Pros & Developers. It's quick & easy.

Writing and moving text on Bitmaps of various resolutions

P: 20
I'm writing a program that displays a user-supplied Bitmap and then writes text fields to it. These "text fields" are things that the user can move around on the image, but to render them efficiently, I draw the text directly to the image. It's faster that way.

The problem is that right now I have to redraw the original (unwritten-to) bitmap and redraw the text whenever the user moves the text because I haven't figured out how to properly erase just the text that moved or changed.

I'm now working to try to solve this and I'm having some trouble. My plan is to get a Bitmap for each field that contains the contents of the main bitmap before the text was drawn. Then, when the text is moved, I first draw that little bitmap to the big bitmap to erase the text, replace that little bitmap with one taken from the text's new home, and then draw the text.

The sample code below is what I'm using to flesh out the implementation of this. It's not working quite right. It gets the little background bitmap (which I call the mask), but always gets it from position 0, 0. The other problem is that it doesn't draw the mask bitmap to the right spot, so it ends up mucking up the image. I'm wondering if it has to do with the resolution of the image being loaded.

NOTE: All my sample tries to do is draw the bitmap in a PictureBox and then draw the word "Hello". When you click on the PictureBox, it tries to move the text to the right and down some.

Here's my code:

Expand|Select|Wrap|Line Numbers
  1. public partial class Form1 : Form
  2. {
  3.     private Bitmap image = null;
  4.     private Font font = new Font("Times New Roman", 14.0F, FontStyle.Regular);
  5.     private int left = 10;
  6.     private int top = 10;
  7.     private int width = 200;
  8.     private int height = 50;
  9.     private Bitmap mask = null;
  10.  
  11.     public Form1()
  12.     {
  13.         InitializeComponent();
  14.     }
  15.  
  16.     private void Form1_Load(object sender, EventArgs e)
  17.     {
  18.         image = new Bitmap("MyBitmap.jpg");
  19.         pictureBox1.Image = image;
  20.     }
  21.  
  22.     private Bitmap DrawMaskImage()
  23.     {
  24.         if (image == null || mask == null)
  25.             return null;
  26.  
  27.         Graphics g = null;
  28.         try
  29.         {
  30.             g = Graphics.FromImage(image);
  31.             g.SmoothingMode = SmoothingMode.HighQuality;
  32.             g.PixelOffsetMode = PixelOffsetMode.HighQuality;
  33.             g.CompositingQuality = CompositingQuality.HighQuality;
  34.             g.InterpolationMode = InterpolationMode.HighQualityBicubic;
  35.             g.DrawImage(image, 0, 0);
  36.  
  37.             Rectangle rect = (Rectangle)mask.Tag;
  38.             int x = ((Rectangle)mask.Tag).Left;
  39.             int y = ((Rectangle)mask.Tag).Top;
  40.             g.DrawImage(mask, rect);
  41.  
  42.             return image;
  43.         }
  44.         finally
  45.         {
  46.             g.Dispose();
  47.         }
  48.     }
  49.  
  50.     private Bitmap DrawImage()
  51.     {
  52.         if (image == null)
  53.             return null;
  54.  
  55.         Graphics g = null;
  56.         try
  57.         {
  58.             g = Graphics.FromImage(image);
  59.             g.SmoothingMode = SmoothingMode.HighQuality;
  60.             g.PixelOffsetMode = PixelOffsetMode.HighQuality;
  61.             g.CompositingQuality = CompositingQuality.HighQuality;
  62.             g.InterpolationMode = InterpolationMode.HighQualityBicubic;
  63.             g.DrawImage(image, 0, 0);
  64.  
  65.             string text = "Hello";
  66.             DrawString(text, font, g);
  67.  
  68.             return image;
  69.         }
  70.         finally
  71.         {
  72.             g.Dispose();
  73.         }
  74.     }
  75.  
  76.     public void DrawString(string drawString, Font drawFont, Graphics formGraphics)
  77.     {
  78.         formGraphics.PageUnit = GraphicsUnit.Inch;
  79.  
  80.         System.Drawing.SolidBrush drawBrush = new System.Drawing.SolidBrush(Color.Red);
  81.         float x = (float)left / 96.0F;
  82.         float y = (float)top / 96.0F;
  83.         System.Drawing.StringFormat drawFormat = new System.Drawing.StringFormat();
  84.         drawFormat.Alignment = StringAlignment.Near;
  85.         RectangleF rect = new RectangleF(x, y, width / 96.0F, height / 96.0F);
  86.         formGraphics.DrawString(drawString, drawFont, drawBrush, rect, drawFormat);
  87.         drawBrush.Dispose();
  88.         drawFormat.Dispose();
  89.     }
  90.  
  91.     private void OnClick(object sender, EventArgs e)
  92.     {
  93.         top += 10;
  94.         left += 10;
  95.         pictureBox1.Image = DrawMaskImage();
  96.         pictureBox2.Image = MakeMask();
  97.         pictureBox1.Image = DrawImage();
  98.     }
  99.  
  100.     private Bitmap MakeMask()
  101.     {
  102.         Rectangle maskRect = new Rectangle(left, top, width, height);
  103.         mask = Copy(image, maskRect);
  104.         mask.Tag = maskRect;
  105.         return mask;
  106.     }
  107.  
  108.     private Bitmap Copy(Bitmap srcBitmap, Rectangle section)
  109.     {
  110.         // Create the new bitmap and associated graphics object
  111.         Bitmap bmp = new Bitmap((int)section.Width, (int)section.Height);
  112.         bmp.SetResolution(srcBitmap.HorizontalResolution, srcBitmap.VerticalResolution);
  113.         Graphics g = Graphics.FromImage(bmp);
  114.         g.PageUnit = GraphicsUnit.Inch;
  115.  
  116.         // Draw the specified section of the source bitmap to the new one
  117.         g.DrawImage(srcBitmap, new Rectangle(0, 0, section.Width, section.Height), section, GraphicsUnit.Pixel);
  118.         //g.DrawImage(srcBitmap, 0, 0, section, GraphicsUnit.Pixel);
  119.  
  120.         // Clean up
  121.         g.Dispose();
  122.  
  123.         // Return the bitmap
  124.         return bmp;
  125.     }
  126.  
Jun 4 '09 #1
Share this Question
Share on Google+
6 Replies


tlhintoq
Expert 2.5K+
P: 3,525
I'm writing a program that displays a user-supplied Bitmap and then writes text fields to it. These "text fields" are things that the user can move around on the image, but to render them efficiently, I draw the text directly to the image. It's faster that way.
Faster than what? What was your other alternative?

How about writing your text to a bitmap with a TRANSPARENT background? That way you can move it all you want without having all this mess of trying to copy the background from the main bitmap? Just seems you're making more work than you need to.
Jun 4 '09 #2

P: 20
How about writing your text to a bitmap with a TRANSPARENT background? That way you can move it all you want without having all this mess of trying to copy the background from the main bitmap? Just seems you're making more work than you need to.
But on a Form, I would need to put that transparent bitmap onto a control, like a PictureBox and then have that PictureBox sitting on top of the one that has the big image. I found that to appear rather clunky. Is there a way to lay Bitmaps on top of each other without using PictureBox controls?
Jun 4 '09 #3

tlhintoq
Expert 2.5K+
P: 3,525
@bradyounie
It shouldn't 'appear' as anything... clunky or otherwise. If the top PictureBox (the one with transparancy and text only) has no border, and has a transparent background then how would it appear as anything other than text on top of your background? Can you supply a screenshot of how this appears so I can see what you see?

You said that the text items were meant to be movable. This would let you click on the top PictureBoxes and drag them as you like. All you have to do is monitor the mousedown and move the PictureBox.Location along with the mouse. No extra computing of images.
Jun 4 '09 #4

P: 20
@tlhintoq
I think the main problem is that I haven't been able to figure out how to make the PictureBox transparent. Any Bitmap I put on it will always have the standard gray background because that's the BackColor of the PictureBox. I've tried the following, but it did nothing:

pictureBox2.BackColor = Color.Transparent;
Jun 4 '09 #5

tlhintoq
Expert 2.5K+
P: 3,525
I didn't catch that you were doing that. My bad.

This sounds a little counter-intuitive at first, but trust me it works.
Don't use a PictureBox for your overlaying picture. Make your overlaying picture the background image of a new form. Show that form with no border. Set the transparancy to whatever color you are using for the transparent color of the text graphic. Yellow text on black - make the transparency color black for example.

So instead of making a new picturebox programmatically and adding a graphic to it, make a new form, no border, and add your graphic as it's background image.
Jun 4 '09 #6

P: 20
I solved it! I have a PictureBox holding my overlaying picture, and I use a custom Panel-derived class with special code to make the transparency work. It works like a charm and I was able to delete a lot of the code I was using to do the refreshes of the image.

Thanks for your help!
Jun 11 '09 #7

Post your reply

Sign in to post your reply or Sign up for a free account.