Save zoomed image in a picturebox? - vb.net

I'm a newbie in vb.net (windows app) programming. How can I save a zoomed image in a picturebox.
See, I have a panel and put a picturebox (set to zoom) inside and set the panel to autoscroll to accomodate the size of the image. I can zoom in and out of the image. I can save the picture as is using a memorystream and save it to the database (access). But the thing I don't know is how to save the current size of the image to the size and current position of the image relative to the size of the panel.
This is what my project looks like. See I can load an image and save the picture as is to the database.
What my project looks like
My question is, how to save the current location and size relative to the panel size of the image if I zoom it?
How to save this image and resize the picturebox to the size of the panel and the current location of the zoomed image and the image itself
I hope you understand my question (sorry if my english is bad, it is not my native language).
------edit------
UPDATE: I was able to save the zoomed image from the picturebox inside the panel. I used #dr.null and #jtxkopt suggestion and it works somehow. BUT the problem is, the output has also drawn the scrollbars on the panel.
Output:
This is my current output
This is my code:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
SaveFileDialog1.Filter = "Image Files|*.jpg; *.png; *.bmp"
Panel3.HorizontalScroll.Visible = False
Panel3.VerticalScroll.Visible = False
If SaveFileDialog1.ShowDialog = DialogResult.OK Then
Dim imageRectangle = New Rectangle(Point.Empty, picUser.Image.Size)
Dim safeCropRectangle = Rectangle.Intersect(imageRectangle, Panel3.DisplayRectangle)
Dim bmp As Bitmap = New Bitmap(Panel3.Width, Panel3.Height, picUser.Image.PixelFormat)
Panel3.DrawToBitmap(bmp, safeCropRectangle)
bmp.Save(SaveFileDialog1.FileName)
End If
End Sub
What can I do to remove the scroll bars? I already used the panel.VerticalScroll.Visible = false before the lines of code but it doesn't work.

You can use the function DrawToBitmap to save modified image inside PictureBox.
Follow the below procedure.
Create a new bitmap with the same size and Pixel Format as the picturebox.
Call the DrawToBitmap function of the picturebox.
For more details, examine the following example program. Using DrawToBitmap, you can set the PictureBox.SizeMode property to whatever you want and save the modified image to a file.
PS: This example code is for giving the idea of how you can save the image of PictureBox in any SizeMode, not for providing a solution to the question with/without its complete details.
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
Imports System.Windows.Forms
Namespace PictureboxZoomSave
Public Class MainForm
Inherits Form
Public Sub New()
InitializeComponent()
End Sub
Private openFileDialog As OpenFileDialog = New OpenFileDialog()
Private saveFileDialog As SaveFileDialog = New SaveFileDialog()
Private image As Image
Private Sub OpenImageButton_click(ByVal sender As Object, ByVal e As EventArgs)
openFileDialog.Filter = "Image Files|*.jpg; *.png"
If openFileDialog.ShowDialog() = DialogResult.OK Then
If image IsNot Nothing Then image.Dispose()
image = Image.FromFile(openFileDialog.FileName)
pictureBox1.Image = image
End If
End Sub
Private Sub SaveImageButton_click(ByVal sender As Object, ByVal e As EventArgs)
saveFileDialog.Filter = "Image Files|*.jpg; *.png"
If saveFileDialog.ShowDialog() = DialogResult.OK Then
Dim bitmap As Bitmap = New Bitmap(pictureBox1.Width, pictureBox1.Height, image.PixelFormat)
pictureBox1.DrawToBitmap(bitmap, New Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height))
bitmap.Save(saveFileDialog.FileName)
End If
End Sub
<STAThread>
Private Shared Sub Main()
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)
Application.Run(New MainForm())
End Sub
Private components As System.ComponentModel.IContainer = Nothing
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso (components IsNot Nothing) Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
Private Sub InitializeComponent()
Me.pictureBox1 = New System.Windows.Forms.PictureBox()
Me.OpenImageButton = New System.Windows.Forms.Button()
Me.SaveImageButton = New System.Windows.Forms.Button()
(CType((Me.pictureBox1), System.ComponentModel.ISupportInitialize)).BeginInit()
Me.SuspendLayout()
Me.pictureBox1.Location = New System.Drawing.Point(12, 12)
Me.pictureBox1.Name = "pictureBox1"
Me.pictureBox1.Size = New System.Drawing.Size(200, 191)
Me.pictureBox1.TabIndex = 0
Me.pictureBox1.TabStop = False
Me.OpenImageButton.Location = New System.Drawing.Point(229, 12)
Me.OpenImageButton.Name = "button1"
Me.OpenImageButton.Size = New System.Drawing.Size(75, 23)
Me.OpenImageButton.TabIndex = 1
Me.OpenImageButton.Text = "Open"
Me.OpenImageButton.UseVisualStyleBackColor = True
AddHandler Me.OpenImageButton.Click, New System.EventHandler(AddressOf Me.OpenImageButton_click)
Me.SaveImageButton.Location = New System.Drawing.Point(229, 42)
Me.SaveImageButton.Name = "button2"
Me.SaveImageButton.Size = New System.Drawing.Size(75, 23)
Me.SaveImageButton.TabIndex = 2
Me.SaveImageButton.Text = "Save"
Me.SaveImageButton.UseVisualStyleBackColor = True
AddHandler Me.SaveImageButton.Click, New System.EventHandler(AddressOf Me.SaveImageButton_click)
Me.AutoScaleDimensions = New System.Drawing.SizeF(6F, 13F)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(800, 450)
Me.Controls.Add(Me.SaveImageButton)
Me.Controls.Add(Me.OpenImageButton)
Me.Controls.Add(Me.pictureBox1)
Me.Name = "PictureBoxZoomSave"
Me.Text = "PictureBoxZoomSave"
(CType((Me.pictureBox1), System.ComponentModel.ISupportInitialize)).EndInit()
Me.ResumeLayout(False)
End Sub
Private pictureBox1 As System.Windows.Forms.PictureBox
Private OpenImageButton As System.Windows.Forms.Button
Private SaveImageButton As System.Windows.Forms.Button
End Class
End Namespace

I understand that you need to crop the displayed region of a zoomed in image. If so, you can achieve that through many ways and techniques, DrawToBitmap is the easiest approach. Please note:
Using the PictureBox draw method and size doesn't output the required result because it's size changes when you apply the zoom/scale factor. In other words, the result is either a smaller or bigger image of the original one according to the zoom factor.
The output image size is the Panel client size (WYSIWYG).
Hence, you just need to do:
Dim imgRect = pnl.ClientRectangle
Dim bmp = New Bitmap(imgRect.Width, imgRect.Height, pbox.Image.PixelFormat)
pnl.DrawToBitmap(bmp, imgRect)
'Save it...
where pbox is the PictureBox and pnl is it's parent Panel.
That's it all if that is what you are after.

Related

System.OutOfMemoryException:Out of memory - MemoryStream

I have been hitting my head against a wall for the last few days. I think I might be missing something very simple?
Ok so here is the trimmed down version which reproduces the error that I am getting. I have tried to include as much detail as possible but if you would like to some other information, simply let me know.
FORM LAYOUT
I have two forms.
Let's call them Form1 and Form2.
Form1 has 2 picture boxes. Let's call them PictureBox1 and PictureBox2. PictureBox1 has a BackgroundImage set as shown below.
Form2 has only 1 picture box called PictureBox1. It has no image. It looks like this
On my Form1, I have this code.
Dim data As Byte() = Nothing
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'~~> I am doing this just for demonstration purpose. The data is actually coming
'~~> from SQL database where the image is stored
Dim _img As Image = PictureBox1.BackgroundImage
Using MS As New MemoryStream()
PictureBox1.BackgroundImage.Save(MS, PictureBox1.BackgroundImage.RawFormat)
data = MS.GetBuffer()
End Using
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If data IsNot Nothing Then
Dim frm As New Form2
With frm
Using ms As New MemoryStream(data, 0, data.Length)
ms.Write(data, 0, data.Length)
'~~> Set the image of picbox#2 in form 1
PictureBox2.BackgroundImage = Image.FromStream(ms, True)
'~~> Set the image of picbox#1 in form 2
.PictureBox1.BackgroundImage = Image.FromStream(ms, True)
End Using
.ShowDialog()
End With
End If
End Sub
Target Framework: 4.8.1
PROBLEM STATEMENT
If I comment out the line .PictureBox1.BackgroundImage = Image.FromStream(ms, True) which sets the image of PictureBox1 in Form2 and if I run this code, everything works fine. The PictureBox2 in Form1 get populated and the Form2 is shown with no image(obviously). However, if I uncomment the line and then run the code, I get System.OutOfMemoryException:Out of memory. as shown below.
THIS WORKS
If I use .PictureBox1.Image = Image.FromStream(ms, True), then it works just fine as shown below.
QUESTION: I would like to understand why am I getting this System.OutOfMemoryException:Out of memory. error.

How to add infinite components when a button is clicked

I have a social media WinForm. I have a function that basically makes a new picture box when a button is clicked
Public Sub NewPost()
picture as new picturebox
picture.Width = 208
picture.Height = 264
picture.Image = Form2.PictureBox1.Image
picture.Location = New Point(258, 60)
End Sub
The thing is it only generates 1 new picture box because I have to make a new variable each time I want to add a picturebox, and eachtime I have to have a new name. I know my question Is a bit confusing but help would be nice thanks
If you want to trap events for your dynamic PictureBoxes, then you'll have to abandon the WithEvents model and move to using AddHandler.
Here's a quick example where the name of the PictureBox is displayed when it is clicked. Note that I am not setting a Location since they are being added to a FlowLayoutPanel which takes care of the placement for you:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
NewPost()
End Sub
Public Sub NewPost()
Dim picture As New PictureBox
picture.Width = 208
picture.Height = 264
picture.BorderStyle = BorderStyle.FixedSingle
' ...etc...
Dim index As Integer = FlowLayoutPanel1.Controls.Count + 1
picture.Name = "pb" & index
AddHandler picture.Click, AddressOf picture_Click
FlowLayoutPanel1.Controls.Add(picture)
End Sub
Private Sub picture_Click(sender As Object, e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
Debug.Print(pb.Name)
End Sub
End Class
because I have to make a new variable each time
Not necessarily. You just want to keep a reference to the object. That reference doesn't need to be its own variable, it can just as easily be an element in a list. For example, suppose on your form you have a list of PictureBox objects as a class-level member:
Dim pictureBoxes As New List(Of PictureBox)()
Then in your method you can just add to that list:
Public Sub NewPost()
Dim pictureBox As New PictureBox
pictureBox.Width = 208
pictureBox.Height = 264
pictureBox.Image = Form2.PictureBox1.Image
pictureBox.Location = New Point(258, 60)
Me.pictureBoxes.Add(pictureBox)
End Sub
In this case the pictureBox variable is local to the NewPost method and gets re-created each time. But pictureBoxes is a class-level member and keeps track of the growing list of PictureBox objects that you're creating.
You can use a for while loop to create n number of objects
You can use the existing ControlCollection
Public Function NewPost() As String
Dim picture As New PictureBox
'your code
picture.Name = "Pb" & Form2.Controls.OfType(Of PictureBox).Count
Form2.Controls.Add(picture)
Return picture.Name
End Function
then you can retrive it
DirectCast(Form2.Controls(NewPost), PictureBox).Image = Form2.PictureBox1.Image
'OR
DirectCast(Form2.Controls("Pb12"), PictureBox).Image = Form2.PictureBox1.Image

Make a png image transparent

I have a PictureBox added to my Panel1 with Panel1.Controls.Add(pb), and I have tried to make my .png picture transparent.
I have tried with Color.Transparent and with System.Drawing.Color.Transparent, but when I add the PictureBox to my Panel, I can not make it transparent.
And also I'm not able to bring to the front of the others images.
This is my code.
Private Function molduraint()
Dim pb As New PictureBox
pb.BringToFront()
pb.ImageLocation = OpenFileDialog1.FileName
pb.SizeMode = PictureBoxSizeMode.StretchImage
Panel1.Controls.Add(pb)
pb.Location = New Point(txtValueX.Text, txtValueY.Text)
If txtValueX.Text = 0 Or txtValueY.Text = 0 Then
pb.Location = New Point(300, 172)
End If
pb.Visible = True
pb.Size = New Size(TrackBar1.Value, TrackBar2.Value)
pb.Image = PictureBox1.Image
End Function
As you probably know, WinForms controls are not exactly designed to support true transparency (except Forms, those can be actually transparent).
Bitmaps, on the other hand, support transparency.
If you create a Bitmap object using an image format that supports an Alpha Channel, like a .png bitmap, you can draw that image preserving its transparency.
The first thing to do is to create an object that can be used to reference each Bitmap we want to draw, so we can keep track of them.
Since you want to be able to specify position and size of these objects, those are two of the properties that the object must have. I'm adding some more that can be helpful here.
Public Class BitmapObject
Public Property Name As String
Public Property Image As Bitmap
Public Property Position As Point
Public Property Size As Size
Public Property Order As Integer
End Class
The property Name will be the name of source file and Order will reference the z-order position of the Bitmap in relation to the other Bitmaps drawn inside a container.
All the Bitmaps will be grouped using a List of Bitmap objects, so we can summon them using the List Index or one of the properties.
Public MyBitmaps As List(Of BitmapObject) = New List(Of BitmapObject)
As for the drawing surface (canvas), we can use the Form itself, a PictureBox or a Panel (because they're - more or less - just surfaces). I prefer a Panel, it's lightweight, it can host other controls and can be moved around if needed.
If you want to draw on a control, you just need to subscribe its Paint() event and raise it calling the control's Invalidate() method.
Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
If MyBitmaps.Count > 0 Then
MyBitmaps.OrderBy(Function(item) item.Order).
Select(Function(item)
e.Graphics.DrawImage(item.Image, New Rectangle(item.Position, item.Size))
Return item
End Function).ToList()
End If
End Sub
To add a Bitmap to the List(Of BitmapObject), since you want to use an OpenFileDialog to let the user select a Bitmap, we assign this functionality to a Button and when the Bitmap is selected, a new BitmapObject is created and appended to the List.
Private Sub btnOpenFile_Click(sender As Object, e As EventArgs) Handles btnOpenFile.Click
Dim fd As OpenFileDialog = New OpenFileDialog()
fd.InitialDirectory = "[Images Path]"
Dim dr As DialogResult = fd.ShowDialog()
If dr = Windows.Forms.DialogResult.OK Then
Dim BitmapName As String = New FileInfo(fd.FileName).Name
Using tmpBitmap As Bitmap = New Bitmap(fd.FileName)
MyBitmaps.Add(New BitmapObject With {
.Image = New Bitmap(tmpBitmap),
.Position = New Point(Integer.Parse(TextBox1.Text), Integer.Parse(TextBox2.Text)),
.Size = New Size(tmpBitmap.Height, tmpBitmap.Width),
.Order = MyBitmaps.Count,
.Name = BitmapName})
ComboBox1.Items.Add(BitmapName)
ComboBox1.SelectedIndex = MyBitmaps.Count - 1
TrackBar1.Value = tmpBitmap.Height
TrackBar2.Value = tmpBitmap.Width
Panel1.Invalidate()
End Using
End If
End Sub
This is the result: (Full source code in PasteBin)

I draw image to form, but it is limited to top left corner of form

I have created a form and imported two square images saved as PNG files in resources. when I run the code below the black box which is drawn will only go about 200 pixels in the x coordinate and 150 pixels in the Y coordinate from where the image is drawn, after that the background remains white, and it seems I am unable to draw anything and anything I do draw stops around this point.
I have tried redrawing the image in a completely different location on the screen and It will not be visible if it is not within the region to the top left of the form, I have also tried drawing other images, but they also cease to exist when not in the top left of my form.
What I want is for the black box/other images to be drawn across the whole form, and not just in the top left corner, which something is preventing me from doing.
Public Class Form1
Dim gameGraphics As System.Drawing.Graphics = Me.CreateGraphics
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Draws black square which I have saved as resource
gameGraphics.DrawImage(My.Resources.black_Background, 0, 80, 1600, 600)
'Draws green square which I have saved as resource
gameGraphics.DrawImage(My.Resources.greenSquare, 2, 82, 40, 40)
End Sub
'makes the form fullscreen
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.FormBorderStyle = FormBorderStyle.None
Me.WindowState = FormWindowState.Maximized
End Sub
'closes form if quitbutton is clicked
Private Sub QuitButton_Click(sender As Object, e As EventArgs) Handles QuitButton.Click
Me.Close()
End Sub
End Class
Thanks for your time!
The Graphics Object cannot be stored. It's Erased/Updated constantly. You'll end up with an invalid one. It's really useless and, you could say, a mistake.
You can use a Graphics Object created with Control.CreateGraphics(), but you have to remember that it's not persistent; it will be erased when the Control you have painted it on needs to re-Paint() itself (e.g. you drag something over it, if it's a Form, when it's minimized etc.).
Those Properties, Me.FormBorderStyle = FormBorderStyle.None and Me.WindowState = FormWindowState.Maximized are better set in the designer. There's no reason to set them on a Form.Load() event. Their state is not even subject to a condition. In general, leave the Load event of a Form as lightweight as possible and avoid setting properties that can cause cascading events.
An example:
Define an object to store your images:
(The DrawBitmaps flag is used to let your Form know when to draw those Bitmaps).
Public Class MyBitmap
Public Property Image As Bitmap
Public Property Position As Point
Public Property Size As Size
End Class
Public MyBitmaps As List(Of MyBitmap)
Public DrawBitmaps As Boolean = False
Somewhere (even in Form.Load()), fill the list with you bitmaps:
(Here, the bitmap size is set to original size, but you can set it to whatever dimension you see fit).
MyBitmaps = New List(Of MyBitmap)
MyBitmaps.Add(New MyBitmap With {.Image = My.Resources.black_Background,
.Position = New Point(0, 80),
.Size = New Size(My.Resources.black_Background.Width,
My.Resources.black_Background.Height)})
MyBitmaps.Add(New MyBitmap With {.Image = My.Resources.greenSquare,
.Position = New Point(2, 82),
.Size = New Size(My.Resources.greenSquare.Width,
My.Resources.greenSquare.Height)})
The Paint() event e.Graphics of the Form performs all the painting:
(Note that it will not paint its surface unless the DrawBitmaps flag is set to True => It will not paint those Bitmaps when it's loading/showing. The other condition is a basic fail-safe.
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint
If DrawBitmaps = True AndAlso MyBitmaps.Count > 0 Then
For Each _Item As MyBitmap In MyBitmaps
e.Graphics.DrawImage(_Item.Image, New Rectangle(_Item.Position, _Item.Size))
Next
End If
End Sub
When Button1 is clicked, the Form will draw your list of Bitmaps:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
DrawBitmaps = True
Me.Invalidate()
End Sub
Somewhere in your code, add a new Bitmap and tell the Form to Invalidate only a region of the size of this new Bitmap:
MyBitmaps.Add(New MyBitmap With {.Image = My.Resources.[AnotherBitmap],
.Position = New Point(50, 50),
.Size = New Size(200, 200)})
Me.Invalidate(New Rectangle(MyBitmaps.Last().Position, MyBitmaps.Last().Size))
Remove a Bitmap from the list and repaint:
MyBitmaps.RemoveAt(0)
Me.Invalidate()

VB.net How to convert image file to pdf file and then save it without using SaveFileDialog?

I already manage to convert the image file to pdf file.. but i want to make it automatically save to specific location and without it asking me where to save it. Please help me, any help would be appreciated. Beginner here. Here is the code that im currently trying.
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Text
Imports System.Windows.Forms
Imports PdfSharp.Pdf
Imports PdfSharp.Drawing
Imports System.IO
Public Class Form1
Private Sub captureScreen()
'Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim graph As Graphics = Nothing
Try
' gets the upper left hand coordinate of the form
Dim frmleft As System.Drawing.Point = Me.Bounds.Location
'use the commented out version for the full screen
'Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
'this version get the size of the form1 The + 8 adds a little to right and bottom of what is captured.
Dim bmp As New Bitmap(Me.Bounds.Width + 8, Me.Bounds.Height + 8)
'creates the grapgic
graph = Graphics.FromImage(bmp)
'Gets the x,y coordinates from the upper left start point
'used below
Dim screenx As Integer = frmleft.X
Dim screeny As Integer = frmleft.Y
' The - 5 here allows more of the form to be shown for the top and left sides.
graph.CopyFromScreen(screenx - 5, screeny - 5, 0, 0, bmp.Size)
' Save the Screenshot to a file
bmp.Save("I:\eQA\temp.png")
bmp.Dispose()
graph.Dispose()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
captureScreen()
' Create new pdf document and page
Dim doc As New PdfDocument()
Dim oPage As New PdfPage()
' Add the page to the pdf document and add the captured image to it
doc.Pages.Add(oPage)
'Dim xgr As XGraphics = XGraphics.FromPdfPage(oPage)
Dim img As XImage = XImage.FromFile("I:\eQA\temp.png")
'xgr.DrawImage(img, 0, 0)
'Create XImage object from file.
Using xImg = PdfSharp.Drawing.XImage.FromFile("I:\eQA\temp.png")
'Resize page Width and Height to fit image size.
oPage.Width = xImg.PixelWidth * 72 / xImg.HorizontalResolution
oPage.Height = xImg.PixelHeight * 72 / xImg.HorizontalResolution
'Draw current image file to page.
Dim xgr = PdfSharp.Drawing.XGraphics.FromPdfPage(oPage)
xgr.DrawImage(xImg, 0, 0, oPage.Width, oPage.Height)
End Using
' instantiate a Bitmap object
Dim filesaveas As New SaveFileDialog
filesaveas.Filter = ("PDF File|*.pdf")
Dim btnSave As DialogResult = filesaveas.ShowDialog()
If btnSave.Equals(DialogResult.OK) Then
doc.Save(filesaveas.FileName)
doc.Close()
End If
' I used the Dispose() function to be able to
' save the same form again, in case some values have changed.
' When I didn't use the function, an GDI+ error occurred.
img.Dispose()
End Sub
End Class