Get form size of PARENT of current Panel - c#

I'm running this code to create a BMP over my app when a dialog opens to reduce confusion for users on what cannot be accessed (until dialog is closed).
Bitmap bmp = new Bitmap(DisplayRectangle.Width, DisplayRectangle.Height);
using (Graphics G = Graphics.FromImage(bmp))
{
G.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
G.CopyFromScreen(this.PointToScreen(new Point(0, 0)), new Point(0, 0), this.DisplayRectangle.Size);
double percent = 0.60;
Color darken = Color.FromArgb((int)(255 * percent), Color.Black);
using (Brush brsh = new SolidBrush(darken))
{
G.FillRectangle(brsh, this.DisplayRectangle);
}
}
// put the darkened screenshot into a Panel and bring it to the front:
using (Panel p = new Panel())
{
p.Location = new Point(0, 0);
p.Size = this.ClientRectangle.Size;
p.BackgroundImage = bmp;
this.Controls.Add(p);
p.BringToFront();
// display your dialog somehow:
frmcollecting frmcollecting = new frmcollecting(pxid);
frmcollecting.ShowDialog();
The issue is that it creates the bmp over the Panel (pnlActive), however I want it over the whole app. How can I get the dimenions and change the DisplayRectangle to "frmMainPage"?

Related

Cyotek ImageBox get zoomed part of image

I am using Cyotek ImageBox to zoom a image, now if I zoom to a part of image and that part is visible in the ImageBox how can I save that part of image which is visible in ImageBox.
The GetSourceImageRegion method allows you to get a RectangleF that describes the part of the image that is visible in the current state of an ImageBox.
The example code below will create a new Bitmap based on the visible part of the image. This example is not zoomed.
Rectangle visibleImageRegion;
Bitmap result;
visibleImageRegion = Rectangle.Round(imageBox.GetSourceImageRegion());
result = new Bitmap(visibleImageRegion.Width, visibleImageRegion.Height);
using (Graphics g = Graphics.FromImage(result))
{
g.DrawImage(imageBox.Image, new Rectangle(Point.Empty, visibleImageRegion.Size), visibleImageRegion, GraphicsUnit.Pixel);
}
This next example does the same as above, but also scales the new image to match the ImageBox
RectangleF visibleImageRegion;
Bitmap result;
double zoomFactor;
int w;
int h;
visibleImageRegion = imageBox.GetSourceImageRegion();
zoomFactor = imageBox.ZoomFactor;
w = Convert.ToInt32(visibleImageRegion.Width * zoomFactor);
h = Convert.ToInt32(visibleImageRegion.Height * zoomFactor);
result = new Bitmap(w, h);
using (Graphics g = Graphics.FromImage(result))
{
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imageBox.Image, new Rectangle(0, 0, w, h), visibleImageRegion, GraphicsUnit.Pixel);
}
You could hook into the Scroll or Zoomed events of the control to detect when you need to update the image based on user activity.

Confirmation, Printing Graphic location C#

I have created the code below to help me print the admin form as a "report" like document showing the date and graph needed for documentation.
try
{
Graphics g = this.CreateGraphics();
AdminPage = new Bitmap(Size.Width, Size.Height, g);
Graphics Printed = Graphics.FromImage(AdminPage);
Printed.CopyFromScreen(519, 340, 0,0,this.Size);//519,340 this.Location.Y,this.Location.X
printPreviewAdminDialogue.ShowDialog();
}
catch(Exception )
{
MessageBox.Show("Please check printer connection!");
}
I have used the coordinate data of the screen as:
Printed.CopyFromScreen(519, 340, 0,0,this.Size);
Will this still work on any size screen or will this result in some formatting problems on other devices rather than just my laptop?
So far it looks fine Print Preview of what i want with the current code
This method takes a Control (SourceControl) reference and returns a Bitmap resulting from a screen capture of the Control's Window.
Parameters:
SourceControl: The control to be printed. It can be a TopLevel Window (a Form) or a Child Control.
Dpi: The DPI resolution of the resulting Bitmap.
ScaleToDpi: if set to true, the size of the Bitmap will be scaled to match the Dpi parameter, defining a scale factor relative to current screen resolution. E.g.: If parameter Dpi = 300 and the current screen resolution is 96 Dpi, the resulting Bitmap size will be scaled with a factor of 3.125
ClientAreaOnly: If true, captures the SourceControl client area, otherwise the full window bounds.
InterpolationMode: Defines the resulting quality of a scaled bitmap. For enlargements, Bicubic or HighQualityBicubic gives better results. Bicubic may render a shaper image. The usefulness of this parameter depends on how the image is used. The perceived visual quality may not be the same when the image is printed on paper. When printing, sharper images give a better result.
The results can be tested using a PrintPreviewControl to see the difference between a scaled and a non-scaled Bitmap.
Print the a Form including its borders with a resolution of 300 DPI but not scaled to the new resolution (modifies the resulting Bitmap resolution only):
Bitmap FullSize300Dpi = PrintControlFromScreen(this, false, 300, false, InterpolationMode.Default);
Print the a Form ClientArea with a resolution of 300 DPI and scale its dimensions to the new resolution using a HighQualityBicubic Interpolation:
Bitmap ClientArea300DpiScaled = PrintControlFromScreen(this, true, 300, true, InterpolationMode.HighQualityBicubic);
The same, but it prints the client area of a button1 control with a resolution of 96 DPI with a Bilinear Interpolation:
Bitmap Child96DpiUnscaled = PrintControlFromScreen(this.button1, true, 96, false, InterpolationMode.Bilinear);
public Bitmap PrintControlFromScreen(Control SourceControl, bool ClientAreaOnly, float Dpi, bool ScaleToDpi, InterpolationMode Interpolation)
{
using (Graphics graphics = SourceControl.CreateGraphics())
{
SizeF ScaleFactor = new SizeF((Dpi / graphics.DpiX), (Dpi / graphics.DpiY));
SizeF BitmapSize;
if (ScaleToDpi)
{
BitmapSize = ClientAreaOnly ? new SizeF((SourceControl.ClientRectangle.Size.Width * ScaleFactor.Width),
(SourceControl.ClientRectangle.Size.Height * ScaleFactor.Height))
: new SizeF((SourceControl.Bounds.Size.Width * ScaleFactor.Width),
(SourceControl.Bounds.Size.Height * ScaleFactor.Height));
}
else
{
BitmapSize = ClientAreaOnly ? SourceControl.ClientRectangle.Size : SourceControl.Bounds.Size;
}
using (Bitmap bitmap = new Bitmap((int)BitmapSize.Width, (int)BitmapSize.Height))
{
bitmap.SetResolution(ScaleFactor.Width * graphics.DpiX, ScaleFactor.Height * graphics.DpiY);
using (Graphics ImageGraph = Graphics.FromImage(bitmap))
{
ImageGraph.CompositingQuality = CompositingQuality.HighQuality;
ImageGraph.CompositingMode = CompositingMode.SourceCopy;
ImageGraph.SmoothingMode = SmoothingMode.HighQuality;
ImageGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
ImageGraph.InterpolationMode = Interpolation;
if (ClientAreaOnly)
{
ImageGraph.CopyFromScreen(SourceControl.PointToScreen(SourceControl.ClientRectangle.Location),
new Point(0, 0), SourceControl.ClientRectangle.Size);
}
else
{
if (SourceControl.TopLevelControl == SourceControl)
{
ImageGraph.CopyFromScreen(SourceControl.Bounds.Location,
new Point(0, 0), SourceControl.Bounds.Size);
}
else
{
ImageGraph.CopyFromScreen(SourceControl.PointToScreen(SourceControl.ClientRectangle.Location),
new Point(0, 0), SourceControl.Size);
}
}
if (ScaleToDpi) ImageGraph.ScaleTransform(ScaleFactor.Width, ScaleFactor.Height);
ImageGraph.DrawImage(bitmap, new Point(0, 0));
return (Bitmap)bitmap.Clone();
};
};
};
}
UPDATE1 (Example of Print Preview):
This is one possible way to show a PrintPreview of the Bitmap. It should of course be adapted to an actual Printer. This is for general use.
A Bitmap is created in a Button event handler and a PrintPreview Dialog is shown to seee the result.
This creates a ScreenShot of a PictureBox control in the current Form
(this), takes the ClientArea only, sets the resuluton to 300Dpi, does
not scale the image (keeps the screen original size), using a Bicubic
Interpolation for rendering.
Bitmap screenCapture = PrintControlFromScreen(this.pictureBox1, true, 300, false, InterpolationMode.Bicubic);
This is the Button click handler from where you can call the PrintControlFromScreen() method:
private void button1_Click(object sender, EventArgs e)
{
Bitmap screenCapture = PrintControlFromScreen(this.pictureBox1, true, 300, false, InterpolationMode.Bicubic);
PrintDocument PrintDoc = new PrintDocument();
PrintDoc.DocumentName = "ScreenShot";
PrintDoc.DefaultPageSettings.PrinterResolution = new PrinterResolution() { X = 300, Y = 300 };
PrintDoc.DefaultPageSettings.Landscape = PrintDoc.DefaultPageSettings.PaperSize.Width < screenCapture.Width;
PrintDoc.OriginAtMargins = true;
PrintDoc.PrintPage += (s, ppe) =>
{
Rectangle BitmapSize = new Rectangle(new Point(0, 0),
new Size(screenCapture.Width, screenCapture.Height));
Graphics _imagegraph = Graphics.FromImage(screenCapture);
_imagegraph.CompositingMode = CompositingMode.SourceCopy;
_imagegraph.CompositingQuality = CompositingQuality.HighQuality;
_imagegraph.SmoothingMode = SmoothingMode.HighQuality;
_imagegraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
_imagegraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
ImageAttributes ImageAttr = new ImageAttributes();
ImageAttr.ClearThreshold(ColorAdjustType.Bitmap);
ppe.Graphics.DrawImage(screenCapture, BitmapSize, 0F, 0F,
BitmapSize.Width, BitmapSize.Height, GraphicsUnit.Pixel, ImageAttr);
};
PrintPreviewDialog pPreviewDiag = new PrintPreviewDialog();
pPreviewDiag.Document = PrintDoc;
pPreviewDiag.AutoScaleDimensions = new SizeF(Screen.PrimaryScreen.BitsPerPixel * 1.5F,
Screen.PrimaryScreen.BitsPerPixel * 1.5F);
pPreviewDiag.AutoScaleMode = AutoScaleMode.Dpi;
pPreviewDiag.StartPosition = FormStartPosition.CenterScreen;
pPreviewDiag.ShowDialog();
}

Print Text with DrawString() next to an existing bitmap

Greetings fellow users,
A virgin post on my end since its the first time i am abusing stack overflow with a question! I have been trying to get a bitmap print along with a String to print. Basically the view i want to achieve is the Image and the text to the right of the image as we see the printout. Below is the code I am using
Bitmap qrCodeImage = qrCode.GetGraphic(20);
senderQR = qrCodeImage;
PrintDocument pd = new PrintDocument();
Margins margins = new Margins(10, 10, 10, 10);
pd.DefaultPageSettings.Margins = margins;
pd.PrintPage += PrintPage;
pd.Print();
Here is the PrintPage method
private void PrintPage(object sender, PrintPageEventArgs e)
{
System.Drawing.Image img = senderQR;
Bitmap batchCode = new Bitmap(80, 700);
Rectangle m = e.MarginBounds;
RectangleF batch1 = new RectangleF(80, 700, 650, 1000);
m.Width = img.Width / 5;
m.Height = img.Height / 5;
Graphics g = Graphics.FromImage(batchCode);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.DrawString(batch, new Font("Arial", 40), Brushes.Black, batch1);
g.Flush();
e.Graphics.DrawImage(img, m);
}
What am i doing wrong? what seems to be the issue? I have been struggling a whole lot to achieve this but no luck!
Additional Notes:
I want the text on the right to Wrap under itself and not under or on top of the existing bitmap within a size of 3,5 x 2 (inches) (label printing).
This is the printout i get with the existing code;
https://prnt.sc/h1ecb0
https://prnt.sc/h1edex
The image you're drawing on (batchCode) is 80 pixels wide and 700 high. When you write your text over it, you set the top-left point of your writing to 80,700 - exactly to the bottom-right corner of your picture. Basically, you write your text outside of the picture.
Update
I've created a small example to make it reproducible, below is a form class for a basic WinForms application:
public partial class Form1 : Form
{
private PictureBox pictureBox2;
public Form1()
{
InitializeComponent();
pictureBox2 = new PictureBox();
pictureBox2.Size = ClientSize;
pictureBox2.SizeMode = PictureBoxSizeMode.AutoSize;
this.Click += Form1_Click;
pictureBox2.Click += Form1_Click;
Controls.Add(pictureBox2);
}
private void Form1_Click(object sender, EventArgs e)
{
var batch = "hello there!";
Bitmap batchCode = new Bitmap(1000, 1000);
var batch1 = new RectangleF(150, 150, 850, 850);
using (Graphics g = Graphics.FromImage(batchCode))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.DrawString(batch, new Font("Arial", 40), Brushes.Black, batch1);
}
pictureBox2.Image = batchCode;
}
}

Winforms label drawing over a button with custom drawing

So I have this little app that has a button and a label. The button has a custom OnPaint methods to make it look unique. The label currently does not. However the label seems to be drawing inside the button for no apparent reason. Look at this:
For clarities sake I've disabled rendering the fill rectangle since it mostly covers the problem. Here's my button's OnPaint code:
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
Pen p = new Pen (Color.Black, 2);
Rectangle fillRect = new Rectangle (e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width - 2, e.ClipRectangle.Height - 2);
Brush b;
if (MouseHovering)
{
b = new SolidBrush (Color.DarkSlateGray);
}
else
{
b = new SolidBrush (Color.Gray);
}
//g.FillRectangle (b, fillRect);
g.DrawRectangle (p, e.ClipRectangle);
//g.DrawString (Text, new Font ("Arial", 8), new SolidBrush (Color.Black), new Point (4, 4));
}
And here is the code that creates the label and button in the main form class:
label = new Label ();
label.Text = "Hello World";
label.Top = 15;
label.Left = 180;
label.AutoSize = true;
Controls.Add (label);
CButton b = new CButton ();
b.Text = "Click me for a new sentence";
b.AutoSize = true;
b.Top = 10; b.Left = 10;
Controls.Add (b);
The above is called in the constructor. And then when the button is pressed the label text is set like this:
label.Text = Specifier + " " + Verb + " a " + CommonNoun;
So what's happening here and how do I fix it? If you require any other code to understand the problem don't hesitate to ask.
There are some things missing. g.Clear(BackColor); will clear the contents of the buffer that the Graphics object is painting on.
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(BackColor);
g.SmoothingMode = SmoothingMode.HighQuality;
Pen p = new Pen (Color.Black, 2);
Rectangle fillRect = new Rectangle (e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width - 2, e.ClipRectangle.Height - 2);
Brush b;
if (MouseHovering)
{
b = new SolidBrush (Color.DarkSlateGray);
}
else
{
b = new SolidBrush (Color.Gray);
}
//g.FillRectangle (b, fillRect);
g.DrawRectangle (p, e.ClipRectangle);
//g.DrawString (Text, new Font ("Arial", 8), new SolidBrush (Color.Black), new Point (4, 4));
b.Dispose(); //ADD THIS
p.Dispose(); //ADD THIS TOO
}
Also remember that its very important to dispose of any GDI resources that you are using. These might be .NET constructs, but they really are unmanaged objects in the background. Disposing them properly will prevent memory leaks and hard-to-understand crashes.
Also, you shouldn't be using the clip rectangle, use the actual bounds of the control.
The best option is to wrap them in using statements:
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
Color fillColor = MouseHovering ? Color.DarkSlateGray : Color.Gray;
using (Pen p = new Pen(Color.Black, 2))
using (Brush b = new SolidBrush(fillColor))
{
Rectangle fillRect = new Rectangle (0, 0, this.Width, this.Height);
g.DrawRectangle (p, e.ClipRectangle);
}
}
Using the using statement has the added benefit of if there is an exception inside the using, the objects will still be disposed correctly. The other option is to wrap them in a try..catch..finally, but unless you need to do something with the exception, this is a lot cleaner.

Drawing to a new "layer" in C#

Building a little paint program and am trying to incorporate the concept of layers.
I'm using a PictureBox control to display the image, and getting the Graphics object from the image being displayed by the PictureBox and drawing to that.
My problem is I'm trying to figure out how to draw to a new Graphics object that is overlayed on top of the picture box, and be able to get the newly drawn image without the original image absorbed into the graphic.
If I do something like:
Graphics gr = Graphics.FromImage(myPictureBox.image);
gr.DrawRectangle(blah blah)
...I am editing the original image in the picture box. I want a way to only capture the new stuff being drawn as a separate image, but still have it displayed as an overlay over top of what was already there.
Anyone able to point me in the right direction? Thanks!
I would reckon to use the transparent control and do some modification so it can be used as image layers:
http://www.codeproject.com/Articles/26878/Making-Transparent-Controls-No-Flickering
Probably something like this (make any modification as necessary).
class LayerControl : UserControl
{
private Image image;
private Graphics graphics;
public LayerControl(int width, int height)
{
this.Width = width;
this.Height = height;
image = new Bitmap(width, height);
graphics = Graphics.FromImage(image);
// Set style for control
SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint, true);
}
// this function will draw your image
protected override void OnPaint(PaintEventArgs e)
{
var bitMap = new Bitmap(image);
// by default the background color for bitmap is white
// you can modify this to follow your image background
// or create a new Property so it can dynamically assigned
bitMap.MakeTransparent(Color.White);
image = bitMap;
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.GammaCorrected;
float[][] mtxItens = {
new float[] {1,0,0,0,0},
new float[] {0,1,0,0,0},
new float[] {0,0,1,0,0},
new float[] {0,0,0,1,0},
new float[] {0,0,0,0,1}};
ColorMatrix colorMatrix = new ColorMatrix(mtxItens);
ImageAttributes imgAtb = new ImageAttributes();
imgAtb.SetColorMatrix(
colorMatrix,
ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
g.DrawImage(image,
ClientRectangle,
0.0f,
0.0f,
image.Width,
image.Height,
GraphicsUnit.Pixel,
imgAtb);
}
// this function will grab the background image to the control it self
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
Graphics g = e.Graphics;
if (Parent != null)
{
BackColor = Color.Transparent;
int index = Parent.Controls.GetChildIndex(this);
for (int i = Parent.Controls.Count - 1; i > index; i--)
{
Control c = Parent.Controls[i];
if (c.Bounds.IntersectsWith(Bounds) && c.Visible)
{
Bitmap bmp = new Bitmap(c.Width, c.Height, g);
c.DrawToBitmap(bmp, c.ClientRectangle);
g.TranslateTransform(c.Left - Left, c.Top - Top);
g.DrawImageUnscaled(bmp, Point.Empty);
g.TranslateTransform(Left - c.Left, Top - c.Top);
bmp.Dispose();
}
}
}
else
{
g.Clear(Parent.BackColor);
g.FillRectangle(new SolidBrush(Color.FromArgb(255, Color.Transparent)), this.ClientRectangle);
}
}
// simple drawing circle function
public void DrawCircles()
{
using (Brush b = new SolidBrush(Color.Red))
{
using (Pen p = new Pen(Color.Green, 3))
{
this.graphics.DrawEllipse(p, 25, 25, 20, 20);
}
}
}
// simple drawing rectable function
public void DrawRectangle()
{
using (Brush b = new SolidBrush(Color.Red))
{
using (Pen p = new Pen(Color.Red, 3))
{
this.graphics.DrawRectangle(p, 50, 50, 40, 40);
}
}
}
// Layer control image property
public Image Image
{
get
{
return image;
}
set
{
image = value;
// this will make the control to be redrawn
this.Invalidate();
}
}
}
Example how to use it:
LayerControl lc = new LayerControl(100, 100);
lc.Location = new Point(0, 0);
lc.DrawRectangle();
LayerControl lc2 = new LayerControl(100, 100);
lc2.Location = new Point(0, 0);
lc2.DrawCircles();
LayerControl lc3 = new LayerControl(100, 100);
lc3.Location = new Point(0, 0);
lc3.Image = new Bitmap(#"<Image Path>");
// adding control
this.Controls.Add(dc);
this.Controls.Add(dc2);
this.Controls.Add(dc3);
With this method you can have multiple layers that can put overlapping each other (due to the transparency feature it has).
If you want to add it in top of your PictureBox make sure to re-order the control. The Layer Control should be added before your PictureBox control.
// adding control
this.Controls.Clear();
this.Controls.Add(dc);
this.Controls.Add(dc2);
this.Controls.Add(dc3);
this.Controls.Add(PictureBox1);
Hopefully it help.
example code which working fine - take dummy image and layered the original image with custom text
public void LayerImage(System.Drawing.Image Current, int LayerOpacity)
{
Bitmap bitmap = new Bitmap(Current);
int h = bitmap.Height;
int w = bitmap.Width;
Bitmap backg = new Bitmap(w, h + 20);
Graphics g = null;
try
{
g = Graphics.FromImage(backg);
g.Clear(Color.White);
Font font = new Font("Arial", 12, FontStyle.Bold, GraphicsUnit.Pixel);
RectangleF rectf = new RectangleF(70, 90, 90, 50);
Color color = Color.FromArgb(255, 128, 128, 128);
Point atpoint = new Point(backg.Width / 2, backg.Height - 10);
SolidBrush brush = new SolidBrush(color);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
g.DrawString("BRAND AMBASSADOR", font, brush, atpoint, sf);
g.Dispose();
MemoryStream m = new MemoryStream();
backg.Save(m, System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch { }
Color pixel = new Color();
for (int x = 0; x < bitmap.Width; x++)
{
for (int y = 0; y < bitmap.Height; y++)
{
pixel = bitmap.GetPixel(x, y);
backg.SetPixel(x, y, Color.FromArgb(LayerOpacity, pixel));
}
}
MemoryStream m1 = new MemoryStream();
backg.Save(m1, System.Drawing.Imaging.ImageFormat.Jpeg);
m1.WriteTo(Response.OutputStream);
m1.Dispose();
base.Dispose();
}
Got it working, perhaps I wasn't clear enough in my original question.
Essentially what I ended up doing was storing each layer as a separate Image object, then just hooking into the OnPaint method of my control and manually drawing the graphics in order, instead of just drawing to PictureBox.Image. Works like a charm!
The graphics capabilities of .NET drawing libraries are simple. Their main purpose is direct drawing of GUI. If you want to have layering, alpha transparency or advanced filters, then you should either use 3rd party library or roll your own drawing code.

Categories