I am trying to save an image I have processed in my program. e.g. added pseudocolor to the original image
I have tried a few methods, each time i get an error.
A generic error occurred in GDI+.
Can anyone tell me how to properly implement a save method?
Here is the latest attempt:
using System;
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace IMGPROC
{
public partial class Form1 : Form
{
public Bitmap original_image, proc_image;
public Form1()
{
InitializeComponent();
original_image = null;
proc_image = null;
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void Form1_Paint(object sender, PaintEventArgs e)
{
if (original_image != null)
{
Graphics g = e.Graphics;
Rectangle r = new Rectangle(10, 50, original_image.Width, original_image.Height);
g.DrawImage(original_image, r);
}
}
// OPEN IMAGE FILE
/******************************************************************************************/
private void openToolStripMenuItem_Click_1(object sender, EventArgs e)
{
// show the openFile dialog box
Graphics g = this.CreateGraphics();
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
original_image = new Bitmap(openFileDialog1.FileName);
}
Rectangle r = new Rectangle(10, 50, original_image.Width, original_image.Height);
g.DrawImage(original_image, r);
}
// SAVE IMAGE FILE
/******************************************************************************************/
private void saveAsToolStripMenuItem_Click(object sender, System.EventArgs e)
{
SaveFileDialog save = new SaveFileDialog();
save.Filter = "Bitmap Image (.bmp)|*.bmp|Gif Image (.gif)|*.gif |JPEG Image (.jpeg)|*.jpeg |Png Image (.png)|*.png |Tiff Image (.tiff)|*.tiff |Wmf Image (.wmf)|*.wmf |All files (*.*)|*.*";
save.FilterIndex = 4;
save.InitialDirectory = "C:\\";
save.RestoreDirectory = true;
if (save.ShowDialog() == DialogResult.OK)
{
proc_image.Save(save.InitialDirectory);
}
}
// EXIT APPLICATION
/************************************************************************************/
private void exitToolStripMenuItem_Click_1(object sender, EventArgs e)
{
Dispose();
Application.Exit();
}
private void btnRed_Click(object sender, System.EventArgs e)
{
Graphics g = this.CreateGraphics();
int width = original_image.Width;
int height = original_image.Height;
Color pixel;
Rectangle r = new Rectangle(535, 50, original_image.Width, original_image.Height);
Rectangle r2 = new Rectangle(0, 0, original_image.Width, original_image.Height);
Rectangle r3 = new Rectangle(10, 50, original_image.Width, original_image.Height);
g.DrawImage(original_image, r3);
Bitmap proc_image = new Bitmap(width, height, PixelFormat.Format24bppRgb);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
pixel = original_image.GetPixel(x, y);
proc_image.SetPixel(x, y, Color.FromArgb(pixel.R, 0, 0));
}
} g.DrawImage(proc_image, r);
}
private void btnGreen_Click(object sender, System.EventArgs e)
{
Graphics g = this.CreateGraphics();
int width = original_image.Width;
int height = original_image.Height;
Color pixel;
Rectangle r = new Rectangle(535, 50, original_image.Width, original_image.Height);
Rectangle r2 = new Rectangle(0, 0, original_image.Width, original_image.Height);
Rectangle r3 = new Rectangle(10, 50, original_image.Width, original_image.Height);
g.DrawImage(original_image, r3);
Bitmap bitmap_colour = new Bitmap(width, height, PixelFormat.Format24bppRgb);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
pixel = original_image.GetPixel(x, y);
bitmap_colour.SetPixel(x, y, Color.FromArgb(0, pixel.G, 0));
}
} g.DrawImage(bitmap_colour, r);
}
private void btnBlue_Click(object sender, System.EventArgs e)
{
Graphics g = this.CreateGraphics();
int width = original_image.Width;
int height = original_image.Height;
Color pixel;
Rectangle r = new Rectangle(535, 50, original_image.Width, original_image.Height);
Rectangle r2 = new Rectangle(0, 0, original_image.Width, original_image.Height);
Rectangle r3 = new Rectangle(10, 50, original_image.Width, original_image.Height);
g.DrawImage(original_image, r3);
Bitmap bitmap_colour = new Bitmap(width, height, PixelFormat.Format24bppRgb);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
pixel = original_image.GetPixel(x, y);
bitmap_colour.SetPixel(x, y, Color.FromArgb(0, 0, pixel.B));
}
} g.DrawImage(bitmap_colour, r);
}
private void pseudocolorToolStripMenuItem_Click(object sender, System.EventArgs e)
{
checkImageOpen();
btnRed.Visible = true;
btnGreen.Visible = true;
btnBlue.Visible = true;
Graphics g = this.CreateGraphics();
int width = original_image.Width;
int height = original_image.Height;
Rectangle r = new Rectangle(535, 50, original_image.Width, original_image.Height);
Rectangle r2 = new Rectangle(0, 0, original_image.Width, original_image.Height);
Rectangle r3 = new Rectangle(10, 50, original_image.Width, original_image.Height);
g.DrawImage(original_image, r3);
}
}
}
if (save.ShowDialog() == DialogResult.OK)
{
proc_image.Save(save.FileName);
}
Can't save some thing as a directory, and even if you could you wouldn't want to use the initial directory..
Related
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Doppler_Radar
{
public partial class Form1 : Form
{
int myPiePercent = 15;
float distanceFromCenterPixels;
float distanceFromCenterKm = 200F;
public Form1()
{
InitializeComponent();
pictureBox1.Image = Image.FromFile(#"D:\New folder (4)\Weather Radar\WithClouds.bmp");
timer1.Enabled = true;
distanceFromCenterPixels = (float)(183d * (double)distanceFromCenterKm / 200d);
pictureBox1.Image = CalcDifference(new Bitmap(pictureBox1.Image),
new Bitmap(#"D:\New folder (4)\Weather Radar\WithoutClouds.bmp"));
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
DrawPieOnPicturebox(e.Graphics);
}
public void DrawPieOnPicturebox(Graphics myPieGraphic)
{
Color myPieColors = Color.FromArgb(150, Color.LightGreen);
Size myPieSize = new Size((int)distanceFromCenterPixels, (int)distanceFromCenterPixels);
Point myPieLocation = new Point((pictureBox1.Width - myPieSize.Width) / 2, (pictureBox1.Height - myPieSize.Height) / 2);
DrawMyPie(myPiePercent, myPieColors, myPieGraphic, myPieLocation, myPieSize);
}
public void DrawMyPie(int myPiePerecent, Color myPieColor, Graphics myPieGraphic, Point
myPieLocation, Size myPieSize)
{
using (SolidBrush brush = new SolidBrush(myPieColor))
{
myPieGraphic.FillPie(brush, new Rectangle(myPieLocation, myPieSize), Convert.ToSingle(myPiePerecent * 360 / 100), Convert.ToSingle(15 * 360 / 100));
}
}
private void timer1_Tick(object sender, EventArgs e)
{
myPiePercent++;
pictureBox1.Invalidate();
}
public Bitmap CalcDifference(Bitmap bmp1, Bitmap bmp2)
{
Rectangle rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
BitmapData bitmapdata = bmp1.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
IntPtr source = bitmapdata.Scan0;
BitmapData data2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
IntPtr ptr2 = data2.Scan0;
int length = (bmp1.Width * bmp1.Height) * 4;
byte[] destination = new byte[length];
byte[] buffer2 = new byte[length];
Marshal.Copy(source, destination, 0, length);
Marshal.Copy(ptr2, buffer2, 0, length);
for (int i = 0; i < length; i += 4)
{
if (((destination[i] == buffer2[i]) && (destination[i + 1] == buffer2[i + 1])) && (destination[i + 2] == buffer2[i + 2]))
{
destination[i] = 0xff;
destination[i + 1] = 0xff;
destination[i + 2] = 0xff;
destination[i + 3] = 0;
}
else
{
destination[i] = 0;
destination[i + 1] = 255;
destination[i + 2] = 255;
}
}
Marshal.Copy(destination, 0, source, length);
bmp1.UnlockBits(bitmapdata);
bmp2.UnlockBits(data2);
return bmp1;
}
}
}
this color in the yellow the diffrenet pixels all the time because i'm calling the method CalcDifference in the constructor. but what i want is that only when the rotating pie is over/above this diffrenet pixels then color this diffrenet pixels that are under the pie and not all the diffrenet pixels.
on the left side is when coloring the diffrenet pixels with the method CalcDifference.
on the right side the image at it's original.
the goal is to make a doppler radar effect that detect the clouds when the pie is rotating abvoe them.
Yes, you can use a little trick to change the colors of the clouds under the pie and skip the others.
To optimize your CalcDifference method and speed things up, get from each image only the pie region to process. The rest of the image does not change and you don't need to traverse the data of that region.
Pass the clipped images to the CalcDifference method and change the colors of the clouds in that region. All of them. Note, I have changed the method to convert the original images to 32bppArgb images if needed so you can pass images of different formats that the LockBits supports to process.
Assign the full-size image with clouds to the .Image property of the PictureBox.
Here's the trick. Handle the PictureBox.Paint event and create a GraphicsPath object, add the pie and pass it to Graphics.SetClip method. Draw the yellow clouds image then reset the clip (Graphics.ResetClip) to draw the pie.
public partial class SomeForm : Form
{
private float startAngle;
private readonly SolidBrush brPie;
private Rectangle pieRect;
private Bitmap imgWithYellowClouds;
public SomeForm()
{
InitializeComponent();
brPie = new SolidBrush(Color.FromArgb(150, Color.LightGreen));
picWithoutClouds.Image = Image.FromFile(#"...");
picWithClouds.Image = picCanvas.Image = Image.FromFile(#"...");
CreateYellowCloudsImage();
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
brPie.Dispose();
imgWithYellowClouds?.Dispose();
}
private void picCanvas_Resize(object sender, EventArgs e) =>
CreateYellowCloudsImage();
private void picCanvas_Paint(object sender, PaintEventArgs e)
{
if (pieRect.Width < 1 || pieRect.Height < 1 ||
imgWithYellowClouds == null) return;
var g = e.Graphics;
using (var gp = new GraphicsPath())
{
gp.AddPie(pieRect, startAngle, 360f / 8);
g.SetClip(gp);
g.DrawImage(imgWithYellowClouds, pieRect);
g.ResetClip();
g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillPath(brPie, gp);
}
}
private void SomeButton(object sender, EventArgs e)
{
timer1.Enabled = !timer1.Enabled;
}
private void timer1_Tick(object sender, EventArgs e)
{
// Change as needed...
startAngle = (startAngle + 10) % 360;
picCanvas.Invalidate();
}
public Bitmap CalcDifference(Bitmap bmp1, Bitmap bmp2)
{
var disImg1 = !Is32bppArgbFormat(bmp1);
var disImg2 = !Is32bppArgbFormat(bmp2);
var img1 = disImg1 ? To32bppArgbFormat(bmp1) : new Bitmap(bmp1);
var img2 = disImg2 ? To32bppArgbFormat(bmp2) : bmp2;
var img1Data = img1.LockBits(
new Rectangle(Point.Empty, img1.Size),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
var img2Data = img2.LockBits(
new Rectangle(Point.Empty, img2.Size),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
var img1Buffer = new byte[img1Data.Stride * img1Data.Height];
var img2Buffer = new byte[img2Data.Stride * img2Data.Height];
Marshal.Copy(img1Data.Scan0, img1Buffer, 0, img1Buffer.Length);
Marshal.Copy(img2Data.Scan0, img2Buffer, 0, img2Buffer.Length);
img2.UnlockBits(img2Data);
for (int i = 0; i + 4 < img1Buffer.Length; i += 4)
{
if (img1Buffer[i] == img2Buffer[i] &&
img1Buffer[i + 1] == img2Buffer[i + 1] &&
img1Buffer[i + 2] == img2Buffer[i + 2])
{
img1Buffer[i] = 0;
img1Buffer[i + 1] = 0;
img1Buffer[i + 2] = 0;
img1Buffer[i + 3] = 0;
}
else
{
img1Buffer[i] = 0;
img1Buffer[i + 1] = 255;
img1Buffer[i + 2] = 255;
}
}
Marshal.Copy(img1Buffer, 0, img1Data.Scan0, img1Buffer.Length);
img1.UnlockBits(img1Data);
if (disImg2) img2.Dispose();
return img1;
}
private bool Is32bppArgbFormat(Bitmap bmp) =>
Image.GetPixelFormatSize(bmp.PixelFormat) == 32 &&
bmp.PixelFormat != PixelFormat.Indexed;
private Bitmap To32bppArgbFormat(Bitmap src)
{
var bmp = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);
using (var g = Graphics.FromImage(bmp))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(src, new Rectangle(0, 0, bmp.Width, bmp.Height),
0, 0, src.Width, src.Height, GraphicsUnit.Pixel);
return bmp;
}
}
private void CreateYellowCloudsImage()
{
var cs = picCanvas.ClientSize;
// Change as needed...
var sz = new Size(128, 128);
pieRect = new Rectangle(
(cs.Width - sz.Width) / 2,
(cs.Height - sz.Height) / 2,
sz.Width, sz.Height);
// To get the image rectangle regardless of the SizeMode property
// so we can get the pie's region to process...
var method = typeof(PictureBox).GetMethod("ImageRectangleFromSizeMode",
BindingFlags.NonPublic | BindingFlags.Instance);
var imageRect = (Rectangle)method.Invoke(picCanvas,
new object[] { picCanvas.SizeMode });
var cx = picCanvas.Image.Width / (float)imageRect.Width;
var cy = picCanvas.Image.Height / (float)imageRect.Height;
var r2 = RectangleF.Intersect(imageRect, pieRect);
r2.Offset(-imageRect.X, -imageRect.Y);
var cloneRect = new RectangleF(
r2.X * cx,
r2.Y * cy,
r2.Width * cx,
r2.Height * cy);
imgWithYellowClouds?.Dispose();
imgWithYellowClouds = null;
using (var cloulds = (picWithClouds.Image as Bitmap)
.Clone(cloneRect, picWithClouds.Image.PixelFormat))
using (var noClouds = (picWithoutClouds.Image as Bitmap)
.Clone(cloneRect, picWithoutClouds.Image.PixelFormat))
{
// The yellow clouds image...
imgWithYellowClouds = CalcDifference(cloulds, noClouds);
}
}
}
Taken from your previous questions for this demo.
Similar to Photoshop, where you can type in a ratio or in my case a certain dimention such as 800x600, I want to be able to force a Rectangle to be a fixed ratio/size when dragging the mouse..
At the moment I have this:
Which will crop an image using the Rectangle created from clicking and dragging on the PictureBox. The bounding box selects the area without any constraints. I want to be able to force the rectangle to be a certain ratio (prefereably from a set resolution) similar to the way Photoshop's cropping tool works.
My source if anyone needs more detail:
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CropResize
{
public partial class Form1 : Form
{
private static string path;
public Form1(string filePath)
{
InitializeComponent();
path = filePath;
}
private Image _originalImage;
private Image _newImage;
private bool _selecting;
private Rectangle _selection;
private void Form1_Load(object sender, System.EventArgs e)
{
pictureBox1.Image = Image.FromFile(path);
if (pictureBox1.Image.Height > Screen.PrimaryScreen.Bounds.Height - 50 || pictureBox1.Image.Width > Screen.PrimaryScreen.Bounds.Width - 50)
{
if (pictureBox1.Image.Height > Screen.PrimaryScreen.Bounds.Height - 50)
{
Height = Screen.PrimaryScreen.Bounds.Height - 50;
panel1.Height = Size.Height - statusStrip1.Height - buttonSave.Height - 60;
}
if (pictureBox1.Image.Width > Screen.PrimaryScreen.Bounds.Width - 50)
{
Size = new Size(Screen.PrimaryScreen.Bounds.Width - 50, Screen.PrimaryScreen.Bounds.Height - 50);
panel1.Width = Size.Width - statusStrip1.Height - buttonSave.Height - 60;
}
pictureBox1.Image = pictureBox1.Image.Fit2PictureBox(pictureBox1);
panel1.Size = new Size(pictureBox1.Image.Width, pictureBox1.Image.Height);
}
Size = new Size(panel1.Size.Width + 50, panel1.Size.Height + buttonSave.Height + statusStrip1.Height + 80);
// Create a copy of the original image for later use
_originalImage = pictureBox1.Image.Clone() as Image;
_newImage = pictureBox1.Image.Clone() as Image;
}
private void buttonOrig_Click(object sender, System.EventArgs e)
{
pictureBox1.Image = _originalImage.Clone() as Image;
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
// Starting point of the selection:
if (e.Button == MouseButtons.Left)
{
pictureBox1.Image.Dispose();
pictureBox1.Image = _originalImage.Clone() as Image;
_selecting = true;
_selection = new Rectangle(new Point(e.X, e.Y), new Size());
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
// Update the actual size of the selection:
if (_selecting)
{
_selection.Width = (e.X - _selection.X);
_selection.Height = (e.Y - _selection.Y);
//int nGCD = GetGreatestCommonDivisor(1920, 1080);
//_selection.Width = _selection.Width / nGCD;
//_selection.Height = _selection.Height / nGCD;
int widthRatio = 16;
int heightRatio = 9;
if (_selection.Height * widthRatio <= _selection.Width)
{
_selection.Width = _selection.Height * widthRatio;
}
else if (_selection.Width * heightRatio <= _selection.Width)
{
_selection.Height = _selection.Width * heightRatio;
}
// Redraw the picturebox:
pictureBox1.Refresh();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_selecting && _selection.Height != 0)
{
// Draw a rectangle displaying the current selection
e.Graphics.DrawRectangle(Pens.WhiteSmoke, _selection);
//e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(50, Color.Gray)), 0, pictureBox1.Height - pictureBox1.Image.Height, pictureBox1.Image.Width, pictureBox1.Image.Height);
e.Graphics.SetClip(_selection, CombineMode.Exclude);
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Black)), 0, 0, pictureBox1.Width, pictureBox1.Height);
int nGCD = GetGreatestCommonDivisor(_selection.Width, _selection.Height);
string str = string.Format("{0}:{1}", _selection.Width / nGCD, _selection.Height / nGCD);
toolStripStatusLabel1.Text = "Image Size: " + _selection.Width + "x" + _selection.Height + "px. Aspect Ratio: " + str;
}
}
public static int GetGreatestCommonDivisor(int height, int width)
{
return width == 0 ? height : GetGreatestCommonDivisor(width, height % width);
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left &&
_selecting &&
_selection.Size != new Size())
{
// Create cropped image:
_newImage = pictureBox1.Image.Crop(_selection);
_selecting = false;
try
{
// Set new image to the picturebox:
//pictureBox1.Image = _newImage.Fit2PictureBox(pictureBox1);
pictureBox1.Image = _newImage;
//toolStripStatusLabel1.Text = "Image Cropped.";
}
catch (Exception)
{ }
}
else
{
_selecting = false;
}
}
private void buttonResize_Click(object sender, EventArgs e)
{
pictureBox1.Image = ResizeImage(pictureBox1.Image, new Size(800, 600));
int nGCD = GetGreatestCommonDivisor(pictureBox1.Image.Width, pictureBox1.Image.Height);
string str = string.Format("{0}:{1}", pictureBox1.Image.Width / nGCD, pictureBox1.Image.Height / nGCD);
toolStripStatusLabel1.Text = "Image Resized to " + pictureBox1.Image.Width + "x" + pictureBox1.Image.Height + "px. Aspect Ratio: " + str;
}
public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = true)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = size.Width / originalWidth;
float percentHeight = size.Height / originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}
private void buttonSave_Click(object sender, EventArgs e)
{
string filename = path.Substring(path.LastIndexOf("\\") + 1);
string newPath = path.Substring(0, path.LastIndexOf(".") - 1) + "NEW.png";
toolStripStatusLabel1.Text = "Saving " + filename + " to " + newPath;
pictureBox1.Image.Save(newPath, ImageFormat.Png);
toolStripStatusLabel1.Text = filename + " saved to " + newPath;
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CropResize
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args[0]));
}
public static Image SetImageWithinResolution(this Image image, PictureBox pictureBox)
{
//Bitmap bitmap = null;
if (image.Height > Screen.PrimaryScreen.Bounds.Height)
{
//ActiveForm.Size = new Size(100, 100);
Form.ActiveForm.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
image = image.Fit2PictureBox(pictureBox);
//Bitmap bitmap = new Bitmap(image, );
}
if (image.Width > Screen.PrimaryScreen.Bounds.Width)
{
//ActiveForm.Size = new Size(100, 100);
Form.ActiveForm.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
image = image.Fit2PictureBox(pictureBox);
//Bitmap bitmap = new Bitmap();
}
return image;
}
public static Image Crop(this Image image, Rectangle selection)
{
Bitmap bmp = image as Bitmap;
try
{
// Check if it is a bitmap:
if (bmp == null)
throw new ArgumentException("No valid bitmap");
// Crop the image:
Bitmap cropBmp = bmp.Clone(selection, bmp.PixelFormat);
// Release the resources:
image.Dispose();
return cropBmp;
}
catch (Exception)
{
return bmp;
}
}
public static Image Fit2PictureBox(this Image image, PictureBox picBox)
{
Bitmap bmp = null;
Graphics g;
// Scale:
double scaleY = (double)image.Width / picBox.Width;
double scaleX = (double)image.Height / picBox.Height;
double scale = scaleY < scaleX ? scaleX : scaleY;
// Create new bitmap:
bmp = new Bitmap(
(int)((double)image.Width / scale),
(int)((double)image.Height / scale));
// Set resolution of the new image:
bmp.SetResolution(
image.HorizontalResolution,
image.VerticalResolution);
// Create graphics:
g = Graphics.FromImage(bmp);
// Set interpolation mode:
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Draw the new image:
g.DrawImage(
image,
new Rectangle( // Destination
0, 0,
bmp.Width, bmp.Height),
new Rectangle( // Source
0, 0,
image.Width, image.Height),
GraphicsUnit.Pixel);
// Release the resources of the graphics:
g.Dispose();
// Release the resources of the origin image:
image.Dispose();
return bmp;
}
}
Maybe this example will help; is shows how to restrict a drawn rectangle to a given ratio:
float ratio = 0.33f;
Rectangle setRect()
{
int x = Math.Min(mDown.X, currPt.X);
int y = Math.Min(mDown.Y, currPt.Y);
int w = Math.Max(mDown.X, currPt.X) - x;
int h = Math.Max(mDown.Y, currPt.Y) - y;
if (ratio > 1) h = (int)(1f * w / ratio);
else w = (int)(1f * h * ratio);
return new Rectangle(x, y, w, h);
}
It uses two Points, one set in the MouseDown and one updated in the MouseMove.
It is up to you to integrate it with you programm; instead of painting all those pixels during MouseMove I would simply draw a rubberband rectangle on the surface of the control using the Paint event..
If you are scaling things you may want to switch to using all floats.
I have drawn an image in pictureBox, now i want to save it in the folder. I have tried so many ways nothing worked. I am drawing image using the fallowing code. I am drawing the image based on Textbox values.
private void btnTransferBottleRegenerate_Click(object sender, EventArgs e)
{
float[] volumetransfer = new float[1];
volumetransfer[0] = float.Parse(txtTransferVolume.Text);
int[] percentages = new int[6];
percentages[0] = int.Parse(txtTransferNotIdentified.Text);
percentages[1] = int.Parse(txtTransferWaterBasedMud.Text);
percentages[2] = int.Parse(txtTransferOilBasedMud.Text);
percentages[3] = int.Parse(txtTransferWater.Text);
percentages[4] = int.Parse(txtTransferHydrocarbonLiq.Text);
percentages[5] = int.Parse(txtTransferGas.Text);
Color[] colors = new Color[6];
colors[0] = Color.Gray;
colors[1] = Color.Chocolate;
colors[2] = Color.SaddleBrown;
colors[3] = Color.Blue;
colors[4] = Color.Red;
colors[5] = Color.Lime;
// Finally, call the method
DrawPercentages(percentages, colors, volumetransfer);
//string filename = Application.StartupPath + "\\volumetransfer.jpg";
// pictureBox1.Image.Save(Application.StartupPath + "\\Image\\picture1.jpg");
// pictureBox1.Refresh();
// if (pictureBox1 != null)
// {
pictureBox1.Image.Save(Application.StartupPath + "\\test.bmp");
// }
}
private void DrawPercentages(int[] percentages, Color[] colors, float[] volumetransfer)
{
// Create a Graphics object to draw on the picturebox
Graphics G = pictureBox1.CreateGraphics();
// Calculate the number of pixels per 1 percent
float pixelsPerPercent = pictureBox1.Height / volumetransfer[0];
// Keep track of the height at which to start drawing (starting from the bottom going up)
int drawHeight = pictureBox1.Height;
// Loop through all percentages and draw a rectangle for each
for (int i = 0; i < percentages.Length; i++)
{
// Create a brush with the current color
SolidBrush brush = new SolidBrush(colors[i]);
// Update the height at which the next rectangle is drawn.
drawHeight -= (int)(pixelsPerPercent * percentages[i]);
// Draw a filled rectangle
G.FillRectangle(brush, 0, drawHeight, pictureBox1.Width, pixelsPerPercent * percentages[i]);
}
}
}
}
when I click "Regenerate" button then it is going to draw the image in pictureBox after that i want to save it in a folder. I have the design like this.
A solution is draw on a bitmap, set it as the image of the PictureBox and then save it:
private void DrawPercentages(int[] percentages, Color[] colors, float[] volumetransfer){
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using(Graphics G = Graphics.FromImage(bmp)){
//...
}
pictureBox1.Image = bmp;
}
And then your code should work perfectly without any problem.
First, you should paint within the correct event PictureBox1_Paint so that your drawn image stays visible (better: got repaint) even if your window gets eg: resized.
Afterwards you could make use of a snippet posted by #Hans Passant - How to save Graphics object to save your drawn image to disk.
// global to be accesible within paint
float[] volumetransfer = new float[1];
int[] percentages = new int[6];
Color[] colors = new Color[6];
private void btnTransferBottleRegenerate_Click(object sender, EventArgs e)
{
/// initialization goes here
// force pictureBox to be redrawn
// so resizing your window won't let your rectangles disapear
pictureBox1.Invalidate();
using (var bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height))
{
pictureBox1.DrawToBitmap(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
bmp.Save(#"e:\temp\test.png"); //Application.StartupPath + "\\Image\\picture1.jpg"
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
// use GraphicsObject of PaintEventArgs
Graphics G = e.Graphics;
float pixelsPerPercent = pictureBox1.Height / volumetransfer[0];
int drawHeight = pictureBox1.Height;
for (int i = 0; i < percentages.Length; i++)
{
SolidBrush brush = new SolidBrush(colors[i]);
drawHeight -= (int)(pixelsPerPercent * percentages[i]);
G.FillRectangle(brush, 0, drawHeight, pictureBox1.Width, pixelsPerPercent * percentages[i]);
}
}
On the other hand your DrawPercentage(..) could return a new Image - which you could afterwards assign to the pictureBox and save it with pictureBox1.Image.Save(...)
private void button1_Click(object sender, EventArgs e)
{
float[] volumetransfer = new float[1];
int[] percentages = new int[6];
Color[] colors = new Color[6];
/// initialization goes here
pictureBox1.Image = CreateImage(volumetransfer, percentages, colors);
pictureBox1.Image.Save(#"e:\temp\test.png");
}
private Image CreateImage(float[] volumetransfer, int[] percentages, Color[] colors)
{
Image img = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(img);
float pixelsPerPercent = pictureBox1.Height / volumetransfer[0];
int drawHeight = pictureBox1.Height;
for (int i = 0; i < percentages.Length; i++)
{
SolidBrush brush = new SolidBrush(colors[i]);
drawHeight -= (int)(pixelsPerPercent * percentages[i]);
g.FillRectangle(brush, 0, drawHeight, pictureBox1.Width, pixelsPerPercent * percentages[i]);
}
return img;
}
I want to print one tall (long) image in many pages. So in every page, I take a suitable part from the image and I draw it in the page.
the problem is that I have got the image shrunk (its shape is compressed) in the page,so I added an scale that its value is 1500 .
I think that I can solve the problem if I knew the height of the page (e.Graphics) in pixels.
to convert Inches to Pixel, Do I have to multiply by (e.Graphics.DpiX = 600) or multiply by 96 .
void printdocument_PrintPage(object sender, PrintPageEventArgs e)
{
if (pageImage == null)
return;
e.Graphics.PageUnit = GraphicsUnit.Pixel;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
float a = (e.MarginBounds.Width / 100) * e.Graphics.DpiX;
float b = ((e.MarginBounds.Height / 100) * e.Graphics.DpiY);
int scale = 1500;
scale = 0; //try to comment this
RectangleF srcRect = new RectangleF(0, startY, pageImage.Width, b - scale);
RectangleF destRect = new RectangleF(0, 0, a, b);
e.Graphics.DrawImage(pageImage, destRect, srcRect, GraphicsUnit.Pixel);
startY = Convert.ToInt32(startY + b - scale);
e.HasMorePages = (startY < pageImage.Height);
}
could you please make it works correctly.
you can download the source code from (here).
thanks in advanced.
I tried to complete your task.
Here you go. Hope it helps.
This method prints the image on several pages (or one if image is small).
private void printImage_Btn_Click(object sender, EventArgs e)
{
list = new List<Image>();
Graphics g = Graphics.FromImage(image_PctrBx.Image);
Brush redBrush = new SolidBrush(Color.Red);
Pen pen = new Pen(redBrush, 3);
decimal xdivider = image_PctrBx.Image.Width / 595m;
int xdiv = Convert.ToInt32(Math.Ceiling(xdivider));
decimal ydivider = image_PctrBx.Image.Height / 841m;
int ydiv = Convert.ToInt32(Math.Ceiling(ydivider));
/*int xdiv = image_PctrBx.Image.Width / 595; //This is the xsize in pt (A4)
int ydiv = image_PctrBx.Image.Height / 841; //This is the ysize in pt (A4)
// # 72 dots-per-inch - taken from Adobe Illustrator
if (xdiv >= 1 && ydiv >= 1)
{*/
for (int i = 0; i < xdiv; i++)
{
for (int y = 0; y < ydiv; y++)
{
Rectangle r;
try
{
r = new Rectangle(i * Convert.ToInt32(image_PctrBx.Image.Width / xdiv),
y * Convert.ToInt32(image_PctrBx.Image.Height / ydiv),
image_PctrBx.Image.Width / xdiv,
image_PctrBx.Image.Height / ydiv);
}
catch (Exception)
{
r = new Rectangle(i * Convert.ToInt32(image_PctrBx.Image.Width / xdiv),
y * Convert.ToInt32(image_PctrBx.Image.Height),
image_PctrBx.Image.Width / xdiv,
image_PctrBx.Image.Height);
}
g.DrawRectangle(pen, r);
list.Add(cropImage(image_PctrBx.Image, r));
}
}
g.Dispose();
image_PctrBx.Invalidate();
image_PctrBx.Image = list[0];
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += PrintDocument_PrintPage;
PrintPreviewDialog previewDialog = new PrintPreviewDialog();
previewDialog.Document = printDocument;
pageIndex = 0;
previewDialog.ShowDialog();
// don't forget to detach the event handler when you are done
printDocument.PrintPage -= PrintDocument_PrintPage;
}
This method prints every picture in the List in the needed dimensions (A4 size):
private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
// Draw the image for the current page index
e.Graphics.DrawImageUnscaled(list[pageIndex],
e.PageBounds.X,
e.PageBounds.Y);
// increment page index
pageIndex++;
// indicate whether there are more pages or not
e.HasMorePages = (pageIndex < list.Count);
}
This method crops the image and returns every part of the image:
private static Image cropImage(Image img, Rectangle cropArea)
{
Bitmap bmpImage = new Bitmap(img);
Bitmap bmpCrop = bmpImage.Clone(cropArea, System.Drawing.Imaging.PixelFormat.DontCare);
return (Image)(bmpCrop);
}
The Image gets loaded from the PictureBox, so make sure the image is loaded. (No exception handling yet).
internal string tempPath { get; set; }
private int pageIndex = 0;
internal List<Image> list { get; set; }
These variables are defined as global variables.
You can download a sample project here:
http://www.abouchleih.de/projects/PrintImage_multiplePages.zip // OLD Version
http://www.abouchleih.de/projects/PrintImage_multiplePages_v2.zip // NEW
I have Created a Class file for multiple page print a single large image.
Cls_PanelPrinting.Print Print =new Cls_PanelPrinting.Print(PnlContent/Image);
You have to Pass the panel or image.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Printing;
namespace Cls_PanelPrinting
{
public class Print
{
readonly PrintDocument printdoc1 = new PrintDocument();
readonly PrintPreviewDialog previewdlg = new PrintPreviewDialog();
public int page = 1;
internal string tempPath { get; set; }
private int pageIndex = 0;
internal List<Image> list { get; set; }
private int _Line = 0;
private readonly Panel panel_;
public Print(Panel pnl)
{
panel_ = pnl;
printdoc1.PrintPage += (printdoc1_PrintPage);
PrintDoc();
}
private void printdoc1_PrintPage(object sender, PrintPageEventArgs e)
{
Font myFont = new Font("Cambria", 10, FontStyle.Italic, GraphicsUnit.Point);
float lineHeight = myFont.GetHeight(e.Graphics) + 4;
float yLineTop = 1000;
int x = e.MarginBounds.Left;
int y = 25; //e.MarginBounds.Top;
e.Graphics.DrawImageUnscaled(list[pageIndex],
x,y);
pageIndex++;
e.HasMorePages = (pageIndex < list.Count);
e.Graphics.DrawString("Page No: " + pageIndex, myFont, Brushes.Black,
new PointF(e.MarginBounds.Right, yLineTop));
}
public void PrintDoc()
{
try
{
Panel grd = panel_;
Bitmap bmp = new Bitmap(grd.Width, grd.Height, grd.CreateGraphics());
grd.DrawToBitmap(bmp, new Rectangle(0, 0, grd.Width, grd.Height));
Image objImage = (Image)bmp;
Bitmap objBitmap = new Bitmap(objImage, new Size(700, objImage.Height));
Image PrintImage = (Image)objBitmap;
list = new List<Image>();
Graphics g = Graphics.FromImage(PrintImage);
Brush redBrush = new SolidBrush(Color.Red);
Pen pen = new Pen(redBrush, 3);
decimal xdivider = panel_.Width / 595m;
// int xdiv = Convert.ToInt32(Math.Ceiling(xdivider));
decimal ydivider = panel_.Height / 900m;
int ydiv = Convert.ToInt32(Math.Ceiling(ydivider));
int xdiv = panel_.Width / 595; //This is the xsize in pt (A4)
for (int i = 0; i < xdiv; i++)
{
for (int y = 0; y < ydiv; y++)
{
Rectangle r;
if (panel_.Height > 900)
{
try
{
if (list.Count > 0)
{
r = new Rectangle(0, (900 * list.Count), PrintImage.Width, PrintImage.Height - (900 * list.Count));
}
else
{
r = new Rectangle(0, 0, PrintImage.Width, 900);
}
list.Add(cropImage(PrintImage, r));
}
catch (Exception)
{
list.Add(PrintImage);
}
}
else { list.Add(PrintImage); }
}
}
g.Dispose();
PrintImage = list[0];
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += printdoc1_PrintPage;
PrintPreviewDialog previewDialog = new PrintPreviewDialog();
previewDialog.Document = printDocument;
pageIndex = 0;
printDocument.DefaultPageSettings.PrinterSettings.PrintToFile = true;
string path = "d:\\BillIng.xps";
if (File.Exists(path))
File.Delete(path);
printDocument.DefaultPageSettings.PrinterSettings.PrintFileName = "d:\\BillIng.xps";
printDocument.PrintController = new StandardPrintController();
printDocument.Print();
printDocument.PrintPage -= printdoc1_PrintPage;
}
catch { }
}
private static Image cropImage(Image img, Rectangle cropArea)
{
Bitmap bmpImage = new Bitmap(img);
Bitmap bmpCrop = bmpImage.Clone(cropArea, System.Drawing.Imaging.PixelFormat.DontCare);
return (Image)(bmpCrop);
}
}
}
I'm trying to draw Right-Aligned text in a custom control, however, it seems for some reason it doesn't align to my target horizontal position and there's a difference between strings.
I can live with the fact that it doesn't exactly matches my target horizontal position, but the difference between strings is visually awful!
Any pointers?
The isolated code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace RightAlignTest {
class RightControlTest : UserControl {
public RightControlTest() {
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
public static void DrawString(Graphics g, string s, Font f, RectangleF r, Color c) {
float locx = r.Left;
float locy = r.Top;
SizeF txts = g.MeasureString(s, f);
locx = (locx + r.Width - txts.Width);
g.DrawString(s, f, new SolidBrush(c), locx, locy);
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
int rightTarget = Width - 20;
Font f = new Font("Arial Unicode MS", 13f, FontStyle.Regular);
int i = 0;
string[] strings = { "Current Limit 1:", "Current Limit 2:", "Temperature Center 1:", "Temperature Center 2:" };
foreach (var s in strings) {
Rectangle r1 = new Rectangle(0, 30 * i++, rightTarget, Height);
DrawString(e.Graphics, s, f, r1, Color.Black);
}
e.Graphics.DrawLine(new Pen(new SolidBrush(Color.Blue)), rightTarget, 0, rightTarget, Height);
}
}
public partial class Form1 : Form {
public Form1() {
RightControlTest t = new RightControlTest();
t.Dock = DockStyle.Fill;
Controls.Add(t);
}
}
}
Try if this works:
public static void DrawString(
Graphics g, string s, Font f,
RectangleF r, Color c)
{
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Far;
stringFormat.LineAlignment = StringAlignment.Center; // Not necessary here
g.DrawString(s, f, new SolidBrush(c), r, stringFormat);
}
using StringFormat example taken from http://msdn.microsoft.com/en-us/library/332kzs7c.aspx
Use StringFormat.SetTabStop(int,float[]), like this:
private void PrintPage_Print(object sender, PrintPageEventArgs e)
{
using (Font f = new Font("Segoe UI", 10f, FontStyle.Regular, GraphicsUnit.Point))
{
using (Brush b = new SolidBrush(Color.Black))
{
using (Graphics g = e.Graphics)
{
float y = 5;
string headLine = "Article\tUnit\tNet\tGross";
Pen pen = new Pen(b);
SizeF measure = g.MeasureString(headLine, f);
StringFormat format = new StringFormat();
float[] tabs = new float[] { 200, 100, 55, 55};
Rectangle rect = new Rectangle(5, (int)y, (int)(tabs.Sum()+5), (int)measure.Height);
format.SetTabStops(0, tabs);
g.DrawString(headLine, f, b, rect, format);
g.DrawRectangle(pen, rect);
y += rect.Height + 3f;
format.LineAlignment = StringAlignment.Far;
foreach (var product in Bill.ListPositions())
{
measure = g.MeasureString(product.PositionString, f);
rect = new Rectangle(5, (int)y, (int)(tabs.Sum()+5), (int)measure.Height);
g.DrawString(product.PositionString, f, b, rect, format);
y += measure.Height + 2f;
}
g.DrawLine(pen, new Point(0, (int)y), new Point((int)(tabs.Sum()), (int)y));
tabs = new float[] { 300, 110 };
format.LineAlignment = StringAlignment.Near;
format.SetTabStops(0, tabs);
foreach (var line in DrawTotalSummaryLines())
{
measure = g.MeasureString(line, f);
rect = new Rectangle(5, (int)y, (int)(tabs.Sum()+5), (int)measure.Height);
g.DrawString(line, f, b, rect, format);
y += measure.Height + 2f;
if (line.Contains("Gross:") ||line.Contains("CHANGE:"))
{
g.DrawLine(pen, new Point(0, (int)y), new Point((int)(tabs.Sum()), (int)y));
y += measure.Height + 2f;
}
}
g.Dispose();
pen.Dispose();
}
b.Dispose();
}
f.Dispose();
}
The result should look like this: