PictureEditorAdvancedForm.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. using FastReport.Utils;
  2. using System;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.Drawing.Imaging;
  7. using System.Windows.Forms;
  8. namespace FastReport.Forms
  9. {
  10. internal partial class PictureEditorAdvancedForm : BaseForm
  11. {
  12. public Image Image
  13. {
  14. get
  15. {
  16. return pictureBox.Image;
  17. }
  18. }
  19. private Image imageOriginal;
  20. private Image imageGrayscale;
  21. private Image imageMonochrome;
  22. private ToolStripLabel lblSize;
  23. private ToolStripRadioButton rbZoomed;
  24. private ToolStripRadioButton rbFullSize;
  25. public PictureEditorAdvancedForm(Image image)
  26. {
  27. InitializeComponent();
  28. this.imageOriginal = image;
  29. pictureBox.Image = image;
  30. setToolbar();
  31. reset();
  32. if (image.Width < panelMiddle.Width && image.Height < panelMiddle.Height)
  33. rbFullSize.PerformClick();
  34. else
  35. rbZoomed.PerformClick();
  36. rbPercentResize.CheckedChanged += rbPercentResize_CheckedChanged;
  37. nudHor.ValueChanged += resize;
  38. nudVer.ValueChanged += resize;
  39. rbPercentCrop.CheckedChanged += rbPercentCrop_CheckedChanged;
  40. nudTop.ValueChanged += crop;
  41. nudLeft.ValueChanged += crop;
  42. nudRight.ValueChanged += crop;
  43. nudBottom.ValueChanged += crop;
  44. this.SizeChanged += delegate (object s, EventArgs e)
  45. {
  46. centerImage();
  47. };
  48. Localize();
  49. UIUtils.CheckRTL(this);
  50. UpdateDpiDependencies();
  51. }
  52. #region Init & Reset
  53. public override void Localize()
  54. {
  55. MyRes res = new MyRes("Forms,PictureEditorAdvanced");
  56. Text = res.Get("");
  57. btnOK.Text = Res.Get("Buttons,Ok");
  58. btnCancel.Text = Res.Get("Buttons,Cancel");
  59. btnReset.Text = res.Get("Reset");
  60. gbResize.Text = res.Get("Resize");
  61. gbCrop.Text = res.Get("Crop");
  62. gbColor.Text = res.Get("Color");
  63. lblChange.Text = res.Get("Change");
  64. lblChange2.Text = res.Get("Change");
  65. rbPercentResize.Text = res.Get("Percentage");
  66. rbPercentCrop.Text = res.Get("Percentage");
  67. rbPixelsResize.Text = res.Get("Pixels");
  68. rbPixelsCrop.Text = res.Get("Pixels");
  69. lblHor.Text = res.Get("Horizontal");
  70. lblVer.Text = res.Get("Vertical");
  71. cbAspectRatio.Text = res.Get("AspectRatio");
  72. rbNone.Text = Res.Get("Misc,None");
  73. rbGrayscale.Text = res.Get("Grayscale");
  74. rbMonochrome.Text = res.Get("Monochrome");
  75. }
  76. public override void UpdateDpiDependencies()
  77. {
  78. base.UpdateDpiDependencies();
  79. rbZoomed.Image = GetImage(235);
  80. rbFullSize.Image = GetImage(236);
  81. }
  82. private void setToolbar()
  83. {
  84. lblSize = new ToolStripLabel();
  85. lblSize.Font = new Font("Segoe UI", 9);
  86. setSizeInfo(pictureBox.Image.Width, pictureBox.Image.Height);
  87. statusBar.Items.Add(lblSize);
  88. rbZoomed = new ToolStripRadioButton();
  89. rbZoomed.Click += delegate (object s, EventArgs e)
  90. {
  91. pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
  92. pictureBox.Dock = DockStyle.Fill;
  93. centerImage();
  94. };
  95. statusBar.Items.Add(rbZoomed);
  96. rbFullSize = new ToolStripRadioButton();
  97. rbFullSize.Click += delegate (object s, EventArgs e)
  98. {
  99. pictureBox.SizeMode = PictureBoxSizeMode.AutoSize;
  100. pictureBox.Dock = DockStyle.None;
  101. centerImage();
  102. };
  103. statusBar.Items.Add(rbFullSize);
  104. }
  105. private void reset()
  106. {
  107. resetResize();
  108. resetCrop();
  109. resetColor();
  110. }
  111. private void resetResize()
  112. {
  113. rbPercentResize.Checked = true;
  114. cbAspectRatio.Checked = true;
  115. nudHor.Minimum = 1;
  116. nudHor.Maximum = 100;
  117. nudHor.Value = 100;
  118. nudVer.Minimum = 1;
  119. nudVer.Maximum = 100;
  120. nudVer.Value = 100;
  121. }
  122. private void resetCrop()
  123. {
  124. rbPercentCrop.Checked = true;
  125. nudTop.Minimum = 0;
  126. nudTop.Maximum = 99;
  127. nudTop.Value = 0;
  128. nudLeft.Minimum = 0;
  129. nudLeft.Maximum = 99;
  130. nudLeft.Value = 0;
  131. nudRight.Minimum = 0;
  132. nudRight.Maximum = 99;
  133. nudRight.Value = 0;
  134. nudBottom.Minimum = 0;
  135. nudBottom.Maximum = 99;
  136. nudBottom.Value = 0;
  137. }
  138. private void resetColor()
  139. {
  140. rbNone.Checked = true;
  141. }
  142. #endregion
  143. #region Resize
  144. void rbPercentResize_CheckedChanged(object sender, EventArgs e)
  145. {
  146. nudHor.ValueChanged -= resize;
  147. nudVer.ValueChanged -= resize;
  148. if (rbPercentResize.Checked)
  149. {
  150. nudHor.Maximum = 100;
  151. nudVer.Maximum = 100;
  152. nudHor.Value = 100;
  153. nudVer.Value = 100;
  154. }
  155. else
  156. {
  157. nudHor.Maximum = imageOriginal.Width;
  158. nudVer.Maximum = imageOriginal.Height;
  159. nudHor.Value = imageOriginal.Width;
  160. nudVer.Value = imageOriginal.Height;
  161. }
  162. nudHor.ValueChanged += resize;
  163. nudVer.ValueChanged += resize;
  164. redraw();
  165. }
  166. private int getWidth()
  167. {
  168. if (rbPercentResize.Checked)
  169. {
  170. return (int)Math.Round((float)nudHor.Value / 100 * imageOriginal.Width);
  171. }
  172. else
  173. {
  174. return (int)nudHor.Value;
  175. }
  176. }
  177. private int getHeight()
  178. {
  179. if (rbPercentResize.Checked)
  180. {
  181. return (int)Math.Round((float)nudVer.Value / 100 * imageOriginal.Height);
  182. }
  183. else
  184. {
  185. return (int)nudVer.Value;
  186. }
  187. }
  188. private void resize(object sender, EventArgs e)
  189. {
  190. if (cbAspectRatio.Checked)
  191. {
  192. float x = (float)getWidth() / (float)imageOriginal.Width;
  193. float y = (float)getHeight() / (float)imageOriginal.Height;
  194. if (sender == nudHor)
  195. {
  196. if (rbPercentResize.Checked)
  197. {
  198. nudVer.Value = (int)Math.Round(x * 100);
  199. }
  200. else
  201. {
  202. nudVer.Value = (int)Math.Round(x * imageOriginal.Height);
  203. }
  204. }
  205. else if (sender == nudVer)
  206. {
  207. if (rbPercentResize.Checked)
  208. {
  209. nudHor.Value = (int)Math.Round(y * 100);
  210. }
  211. else
  212. {
  213. nudHor.Value = (int)Math.Round(y * imageOriginal.Width);
  214. }
  215. }
  216. }
  217. redraw();
  218. }
  219. #endregion
  220. #region Crop
  221. private int cropTop()
  222. {
  223. if (rbPercentCrop.Checked)
  224. {
  225. return (int)Math.Round((float)nudTop.Value / 100 * getHeight());
  226. }
  227. else
  228. {
  229. return (int)nudTop.Value;
  230. }
  231. }
  232. private int cropLeft()
  233. {
  234. if (rbPercentCrop.Checked)
  235. {
  236. return (int)Math.Round((float)nudLeft.Value / 100 * getWidth());
  237. }
  238. else
  239. {
  240. return (int)nudLeft.Value;
  241. }
  242. }
  243. private int cropRight()
  244. {
  245. if (rbPercentCrop.Checked)
  246. {
  247. return (int)Math.Round((float)nudRight.Value / 100 * getWidth());
  248. }
  249. else
  250. {
  251. return (int)nudRight.Value;
  252. }
  253. }
  254. private int cropBottom()
  255. {
  256. if (rbPercentCrop.Checked)
  257. {
  258. return (int)Math.Round((float)nudBottom.Value / 100 * getHeight());
  259. }
  260. else
  261. {
  262. return (int)nudBottom.Value;
  263. }
  264. }
  265. private void rbPercentCrop_CheckedChanged(object sender, EventArgs e)
  266. {
  267. nudTop.ValueChanged -= crop;
  268. nudLeft.ValueChanged -= crop;
  269. nudRight.ValueChanged -= crop;
  270. nudBottom.ValueChanged -= crop;
  271. if (rbPercentCrop.Checked)
  272. {
  273. nudTop.Maximum = 99;
  274. nudBottom.Maximum = 99;
  275. nudLeft.Maximum = 99;
  276. nudRight.Maximum = 99;
  277. nudTop.Value = 0;
  278. nudBottom.Value = 0;
  279. nudLeft.Value = 0;
  280. nudRight.Value = 0;
  281. }
  282. else
  283. {
  284. nudTop.Maximum = getHeight() - 1;
  285. nudBottom.Maximum = getHeight() - 1;
  286. nudLeft.Maximum = getWidth() - 1;
  287. nudRight.Maximum = getWidth() - 1;
  288. nudTop.Value = 0;
  289. nudBottom.Value = 0;
  290. nudLeft.Value = 0;
  291. nudRight.Value = 0;
  292. }
  293. nudTop.ValueChanged += crop;
  294. nudLeft.ValueChanged += crop;
  295. nudRight.ValueChanged += crop;
  296. nudBottom.ValueChanged += crop;
  297. redraw();
  298. }
  299. private void crop(object sender, EventArgs e)
  300. {
  301. if (rbPercentCrop.Checked)
  302. {
  303. nudTop.Maximum = 99 - nudBottom.Value;
  304. nudBottom.Maximum = 99 - nudTop.Value;
  305. nudLeft.Maximum = 99 - nudRight.Value;
  306. nudRight.Maximum = 99 - nudLeft.Value;
  307. }
  308. else
  309. {
  310. nudTop.Maximum = getHeight() - nudBottom.Value - 1;
  311. nudBottom.Maximum = getHeight() - nudTop.Value - 1;
  312. nudLeft.Maximum = getWidth() - nudRight.Value - 1;
  313. nudRight.Maximum = getWidth() - nudLeft.Value - 1;
  314. }
  315. redraw();
  316. }
  317. #endregion
  318. #region Color
  319. private Image monochrome(Image image)
  320. {
  321. Bitmap mono = ((Bitmap)image).Clone(new Rectangle(0, 0, image.Width, image.Height), image.PixelFormat);
  322. for (int x = 0; x < mono.Width; x++)
  323. {
  324. for (int y = 0; y < mono.Height; y++)
  325. {
  326. Color c = mono.GetPixel(x, y);
  327. if (c.GetBrightness() >= 0.5)
  328. {
  329. c = Color.FromArgb(c.A, 255, 255, 255);
  330. }
  331. else
  332. {
  333. c = Color.FromArgb(c.A, 0, 0, 0);
  334. }
  335. mono.SetPixel(x, y, c);
  336. }
  337. }
  338. return mono;
  339. }
  340. private Bitmap __monochrome(Bitmap image)
  341. {
  342. int w = image.Width;
  343. int h = image.Height;
  344. Bitmap bmp = new Bitmap(w, h, PixelFormat.Format1bppIndexed);
  345. BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
  346. for (int y = 0; y < h; y++)
  347. {
  348. byte[] scan = new byte[(w + 7) / 8];
  349. for (int x = 0; x < w; x++)
  350. {
  351. Color c = image.GetPixel(x, y);
  352. if (c.GetBrightness() >= 0.5) scan[x / 8] |= (byte)(0x80 >> (x % 8));
  353. }
  354. System.Runtime.InteropServices.Marshal.Copy(scan, 0, (IntPtr)((int)data.Scan0 + data.Stride * y), scan.Length);
  355. }
  356. bmp.UnlockBits(data);
  357. return bmp;
  358. }
  359. #endregion
  360. #region Main & Etc
  361. private void redraw()
  362. {
  363. pictureBox.Image = update(getWidth(), getHeight());
  364. setSizeInfo(Image.Width, Image.Height);
  365. centerImage();
  366. }
  367. private void centerImage()
  368. {
  369. //if (rbFullSize.Checked)
  370. {
  371. pictureBox.Left = Math.Max(0, (pictureBox.Parent.Width - pictureBox.Width) / 2);
  372. pictureBox.Top = Math.Max(0, (pictureBox.Parent.Height - pictureBox.Height) / 2);
  373. }
  374. }
  375. private void setSizeInfo(int x, int y)
  376. {
  377. lblSize.Text = " " + x + " × " + y + " ";
  378. }
  379. private Image update(int width, int height)
  380. {
  381. Image image = this.imageOriginal;
  382. if (rbGrayscale.Checked)
  383. {
  384. if (imageGrayscale == null)
  385. imageGrayscale = ImageHelper.GetGrayscaleBitmap(image);
  386. image = imageGrayscale;
  387. }
  388. else if (rbMonochrome.Checked)
  389. {
  390. if (imageMonochrome == null)
  391. imageMonochrome = monochrome(image);
  392. image = imageMonochrome;
  393. }
  394. Rectangle destRect = new Rectangle(0, 0, width, height);
  395. Bitmap destImage = new Bitmap(width, height);
  396. destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
  397. using (Graphics graphics = Graphics.FromImage(destImage))
  398. {
  399. graphics.CompositingMode = CompositingMode.SourceCopy;
  400. graphics.CompositingQuality = CompositingQuality.HighQuality;
  401. graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
  402. graphics.SmoothingMode = SmoothingMode.HighQuality;
  403. graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
  404. using (ImageAttributes wrapMode = new ImageAttributes())
  405. {
  406. wrapMode.SetWrapMode(WrapMode.TileFlipXY);
  407. graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
  408. }
  409. }
  410. Rectangle crop = new Rectangle((int)cropLeft(),
  411. (int)cropTop(),
  412. Math.Max(1, width - (int)cropLeft() - (int)cropRight()),
  413. Math.Max(1, height - (int)cropTop() - (int)cropBottom()));
  414. try
  415. {
  416. destImage = destImage.Clone(crop, destImage.PixelFormat);
  417. }
  418. catch
  419. {
  420. resetCrop();
  421. }
  422. return destImage;
  423. }
  424. private void btnReset_Click(object sender, EventArgs e)
  425. {
  426. reset();
  427. redraw();
  428. }
  429. private void rbNone_CheckedChanged(object sender, EventArgs e)
  430. {
  431. RadioButton rb = sender as RadioButton;
  432. if (rb != null && rb.Checked)
  433. {
  434. redraw();
  435. }
  436. }
  437. #endregion
  438. protected override void OnFormClosed(FormClosedEventArgs e)
  439. {
  440. base.OnFormClosed(e);
  441. this.SizeChanged -= delegate (object s, EventArgs ea)
  442. {
  443. centerImage();
  444. };
  445. }
  446. }
  447. internal class ToolStripRadioButton : ToolStripButton
  448. {
  449. private int radioButtonGroupId = 0;
  450. private bool updateButtonGroup = true;
  451. private Color checkedColor1 = Color.FromArgb(150, 200, 230);
  452. private Color checkedColor2 = Color.FromArgb(150, 200, 230);
  453. public ToolStripRadioButton()
  454. {
  455. this.CheckOnClick = true;
  456. }
  457. [Category("Behavior")]
  458. public int RadioButtonGroupId
  459. {
  460. get
  461. {
  462. return radioButtonGroupId;
  463. }
  464. set
  465. {
  466. radioButtonGroupId = value;
  467. // Make sure no two radio buttons are checked at the same time
  468. UpdateGroup();
  469. }
  470. }
  471. [Category("Appearance")]
  472. public Color CheckedColor1
  473. {
  474. get { return checkedColor1; }
  475. set { checkedColor1 = value; }
  476. }
  477. [Category("Appearance")]
  478. public Color CheckedColor2
  479. {
  480. get { return checkedColor2; }
  481. set { checkedColor2 = value; }
  482. }
  483. // Set check value without updating (disabling) other radio buttons in the group
  484. private void SetCheckValue(bool checkValue)
  485. {
  486. updateButtonGroup = false;
  487. this.Checked = checkValue;
  488. updateButtonGroup = true;
  489. }
  490. // To make sure no two radio buttons are checked at the same time
  491. private void UpdateGroup()
  492. {
  493. if (this.Parent != null)
  494. {
  495. // Get number of checked radio buttons in group
  496. int checkedCount = 0;
  497. foreach (ToolStripItem item in Parent.Items)
  498. {
  499. ToolStripRadioButton radio = item as ToolStripRadioButton;
  500. if (radio != null && radio.RadioButtonGroupId == RadioButtonGroupId && radio.Checked)
  501. checkedCount++;
  502. }
  503. if (checkedCount > 1)
  504. {
  505. this.Checked = false;
  506. }
  507. }
  508. }
  509. protected override void OnClick(EventArgs e)
  510. {
  511. base.OnClick(e);
  512. this.Checked = true;
  513. }
  514. protected override void OnCheckedChanged(EventArgs e)
  515. {
  516. if (this.Parent != null && updateButtonGroup)
  517. {
  518. foreach (ToolStripItem item in Parent.Items)
  519. {
  520. ToolStripRadioButton radioButton = item as ToolStripRadioButton;
  521. // Disable all other radio buttons with same group id
  522. if (radioButton != null && radioButton != this && radioButton.RadioButtonGroupId == this.RadioButtonGroupId)
  523. {
  524. radioButton.SetCheckValue(false);
  525. }
  526. }
  527. }
  528. }
  529. protected override void OnPaint(PaintEventArgs e)
  530. {
  531. if (this.Checked)
  532. {
  533. LinearGradientBrush checkedBackgroundBrush = new LinearGradientBrush(new Point(0, 0), new Point(0, this.Height), CheckedColor1, CheckedColor2);
  534. e.Graphics.FillRectangle(checkedBackgroundBrush, new Rectangle(new Point(0, 0), this.Size));
  535. }
  536. base.OnPaint(e);
  537. }
  538. }
  539. }