Form1.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // RGB2RGBA
  2. //===========
  3. // P. Poliakoff 2009
  4. //===================
  5. // allows to use a mask to define the alpha layer of a bitmap
  6. // Functionalities
  7. //==================
  8. /* V resizable window
  9. * V Load bitmap
  10. * V Load Mask
  11. * V Display bitmap
  12. * V Display Mask
  13. * V Display masked bitmap
  14. * V allow to disable partial opacity
  15. * V invert mask
  16. * V Allow to use same bitmap for loaded bitmap and mask
  17. * V allow to configure opacity threshold
  18. * V Save masked bitmap
  19. * V adapt the size of displayed images
  20. * V display About box
  21. * V ignore the alpha layer when already already present
  22. * V report error if mask and bitmap have not the same size
  23. * Possible imporvements:
  24. * ======================
  25. * allow to save the save mask as a grayscale bitmap
  26. * display images file names
  27. */
  28. using System;
  29. using System.Collections.Generic;
  30. using System.ComponentModel;
  31. using System.Data;
  32. using System.Drawing;
  33. using System.Drawing.Imaging;
  34. using System.Text;
  35. using System.Windows.Forms;
  36. namespace RGB2RGBA
  37. {
  38. public partial class Form1 : Form
  39. {
  40. Bitmap loadedImage;
  41. Bitmap originalMaskImage;
  42. Bitmap maskImage;
  43. Bitmap maskedImage;
  44. public Form1()
  45. {
  46. InitializeComponent();
  47. MessageBox.Show("Alpha Mask Editor 1.0: P. Poliakoff 2009" + Environment.NewLine + "This progam allows to add an Alpha layer to any bitmap", "About");
  48. }
  49. private Bitmap Create32bppImageAndClearAlpha(Bitmap tmpImage)
  50. {
  51. // declare the new image that will be returned by the function
  52. Bitmap returnedImage = new Bitmap(tmpImage.Width, tmpImage.Height, PixelFormat.Format32bppArgb);
  53. // create a graphics instance to draw the original image in the new one
  54. Rectangle rect = new Rectangle(0, 0, tmpImage.Width, tmpImage.Height);
  55. Graphics g = Graphics.FromImage(returnedImage);
  56. // create an image attribe to force a clearing of the alpha layer
  57. ImageAttributes imageAttributes=new ImageAttributes();
  58. float[][] colorMatrixElements = {
  59. new float[] {1,0,0,0,0},
  60. new float[] {0,1,0,0,0},
  61. new float[] {0,0,1,0,0},
  62. new float[] {0,0,0,0,0},
  63. new float[] {0,0,0,1,1}};
  64. ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
  65. imageAttributes.SetColorMatrix(colorMatrix,ColorMatrixFlag.Default,ColorAdjustType.Bitmap);
  66. // draw the original image
  67. g.DrawImage(tmpImage, rect, 0, 0, tmpImage.Width, tmpImage.Height,GraphicsUnit.Pixel,imageAttributes);
  68. g.Dispose();
  69. return returnedImage;
  70. }
  71. private void PrepareMaskedImage()
  72. {
  73. this.Cursor = Cursors.WaitCursor;
  74. if (this.loadedImage != null && this.maskImage != null)
  75. {
  76. if (this.loadedImage.Width != this.maskImage.Width || this.loadedImage.Height != this.maskImage.Height)
  77. {
  78. MessageBox.Show("Error: mask and image must have the same size", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
  79. this.pictureBox3.Image = null;
  80. }
  81. else
  82. {
  83. //allocate the Masked image in ARGB format
  84. this.maskedImage = Create32bppImageAndClearAlpha(this.loadedImage);
  85. BitmapData bmpData1 = maskedImage.LockBits(new Rectangle(0, 0, maskedImage.Width, maskedImage.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, maskedImage.PixelFormat);
  86. byte[] maskedImageRGBAData = new byte[bmpData1.Stride * bmpData1.Height];
  87. System.Runtime.InteropServices.Marshal.Copy(bmpData1.Scan0, maskedImageRGBAData, 0, maskedImageRGBAData.Length);
  88. BitmapData bmpData2 = maskImage.LockBits(new Rectangle(0, 0, maskImage.Width, maskImage.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, maskImage.PixelFormat);
  89. byte[] maskImageRGBAData = new byte[bmpData2.Stride * bmpData2.Height];
  90. System.Runtime.InteropServices.Marshal.Copy(bmpData2.Scan0, maskImageRGBAData, 0, maskImageRGBAData.Length);
  91. //copy the mask to the Alpha layer
  92. for (int i = 0; i + 2 < maskedImageRGBAData.Length; i += 4)
  93. {
  94. maskedImageRGBAData[i + 3] = maskImageRGBAData[i];
  95. }
  96. System.Runtime.InteropServices.Marshal.Copy(maskedImageRGBAData, 0, bmpData1.Scan0, maskedImageRGBAData.Length);
  97. this.maskedImage.UnlockBits(bmpData1);
  98. this.maskImage.UnlockBits(bmpData2);
  99. this.pictureBox3.Image = maskedImage;
  100. }
  101. this.Cursor = Cursors.Default;
  102. }
  103. }
  104. private void PrepareMaskImage()
  105. {
  106. if (originalMaskImage != null)
  107. {
  108. this.Cursor = Cursors.WaitCursor;
  109. this.maskImage = Create32bppImageAndClearAlpha(originalMaskImage);
  110. BitmapData bmpData = maskImage.LockBits(new Rectangle(0, 0, maskImage.Width, maskImage.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, maskImage.PixelFormat);
  111. byte[] maskImageRGBData = new byte[bmpData.Stride * bmpData.Height];
  112. System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, maskImageRGBData, 0, maskImageRGBData.Length);
  113. byte greyLevel;
  114. bool opaque = this.checkBoxAllowPartialOpacity.Checked == false;
  115. int OpacityThreshold = this.trackBar1.Value;
  116. bool invertedMask = this.checkBoxInvertMask.Checked;
  117. for (int i = 0; i + 2 < maskImageRGBData.Length; i += 4)
  118. {
  119. //convert to gray scale R:0.30 G=0.59 B 0.11
  120. greyLevel = (byte)(0.3 * maskImageRGBData[i + 2] + 0.59 * maskImageRGBData[i + 1] + 0.11 * maskImageRGBData[i]);
  121. if (opaque)
  122. {
  123. greyLevel = (greyLevel < OpacityThreshold) ? byte.MinValue : byte.MaxValue;
  124. }
  125. if (invertedMask)
  126. {
  127. greyLevel = (byte)(255 - (int)greyLevel);
  128. }
  129. maskImageRGBData[i] = greyLevel;
  130. maskImageRGBData[i + 1] = greyLevel;
  131. maskImageRGBData[i + 2] = greyLevel;
  132. }
  133. System.Runtime.InteropServices.Marshal.Copy(maskImageRGBData, 0, bmpData.Scan0, maskImageRGBData.Length);
  134. this.maskImage.UnlockBits(bmpData);
  135. this.pictureBox2.Image = maskImage;
  136. this.Cursor = Cursors.Default;
  137. // if the loaded image is available, we have everything to compute the masked image
  138. if (this.loadedImage != null)
  139. {
  140. PrepareMaskedImage();
  141. }
  142. }
  143. }
  144. private void buttonLoadImage_Click(object sender, EventArgs e)
  145. {
  146. if (openFileDialog1.ShowDialog() == DialogResult.OK)
  147. {
  148. loadedImage = Create32bppImageAndClearAlpha(new Bitmap(openFileDialog1.FileName));
  149. pictureBox1.Image = loadedImage;
  150. if (this.checkBoxLoadedImageAsMask.Checked)
  151. {
  152. originalMaskImage = (Bitmap)loadedImage.Clone();
  153. PrepareMaskImage();
  154. }
  155. else if (this.maskImage != null)
  156. {
  157. PrepareMaskedImage();
  158. }
  159. }
  160. }
  161. private void buttonLoadMask_Click(object sender, EventArgs e)
  162. {
  163. if (openFileDialog1.ShowDialog() == DialogResult.OK)
  164. {
  165. originalMaskImage = Create32bppImageAndClearAlpha(new Bitmap(openFileDialog1.FileName));
  166. PrepareMaskImage();
  167. }
  168. }
  169. private void checkBoxUseLoadedImageAsMask_CheckedChanged(object sender, EventArgs e)
  170. {
  171. if (this.checkBoxLoadedImageAsMask.Checked)
  172. {
  173. this.buttonLoadMask.Enabled = false;
  174. if (this.loadedImage != null)
  175. {
  176. originalMaskImage = (Bitmap)this.loadedImage.Clone();
  177. PrepareMaskImage();
  178. }
  179. }
  180. else
  181. {
  182. this.buttonLoadMask.Enabled = true;
  183. }
  184. }
  185. private void checkBoxInvertMask_CheckedChanged(object sender, EventArgs e)
  186. {
  187. PrepareMaskImage();
  188. }
  189. private void checkBoxPartialOpacity_CheckedChanged(object sender, EventArgs e)
  190. {
  191. if (this.checkBoxAllowPartialOpacity.Checked)
  192. {
  193. this.trackBar1.Enabled = false;
  194. this.textBoxOpacityThreshold.Enabled = false;
  195. }
  196. else
  197. {
  198. this.trackBar1.Enabled = true;
  199. this.textBoxOpacityThreshold.Enabled = true;
  200. }
  201. PrepareMaskImage();
  202. }
  203. private void trackBar1_ValueChanged(object sender, EventArgs e)
  204. {
  205. PrepareMaskImage();
  206. }
  207. private void ButtonSave_Click(object sender, EventArgs e)
  208. {
  209. if (maskedImage != null && this.saveFileDialog1.ShowDialog() == DialogResult.OK)
  210. {
  211. maskedImage.Save(this.saveFileDialog1.FileName);
  212. }
  213. }
  214. private void buttonSaveMask_Click(object sender, EventArgs e)
  215. {
  216. if (maskImage != null && this.saveFileDialog1.ShowDialog() == DialogResult.OK)
  217. {
  218. maskImage.Save(this.saveFileDialog1.FileName);
  219. }
  220. }
  221. }
  222. }