I’m using WinForms for my application. I’m building an image viewer. My application opens image documents (.tif) files. The application has the ability to go to the next page.
The issue is, that every time I try to rotate the image and click next, the image stays on the same page but the page number increments.
Why can’t I see the images when it’s on rotate?
How can I rotate the image and go to the next page?
In the link below I've provided a test tif document for testing purposes:
http://www.filedropper.com/sampletifdocument5pages
My Code:
FileStream _stream;
Image _myImg; // setting the selected tiff
string _fileName;
private int intCurrPage = 0; // defining the current page
private int intTotalPages = 0;
private void Open_Btn_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
lblFile.Text = openFileDialog1.FileName;
// Before loading you should check the file type is an image
if (_myImg == null)
{
_fileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
File.Copy(#lblFile.Text, _fileName);
_stream = new FileStream(_fileName, FileMode.Open, FileAccess.Read);
pictureBox1.Image = Image.FromStream(_stream);
}
//pictureBox1.Image = Image.FromFile(openFileDialog1.FileName);
pictureBox1.Size = new Size(750, 1100);
// Reset the current page when loading a new image.
intCurrPage = 1;
intTotalPages = pictureBox1.Image.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
lblNumPages.Text = intTotalPages.ToString();
lblCurrPage.Text = "1";
}
}
private void NextPage_btn_Click(object sender, EventArgs e)
{
if (intCurrPage <= (intTotalPages - 1))
{
if(Radio_90_Rotate.Checked)
{
pictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
}
if(Radio_180_Rotate.Checked)
{
pictureBox1.Image.RotateFlip(RotateFlipType.Rotate180FlipNone);
}
// Directly increment the active frame within the image already in the PictureBox
pictureBox1.Image.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, intCurrPage);
//page increment (Go to next page)
intCurrPage++;
// Refresh the PictureBox so that it will show the currently active frame
pictureBox1.Refresh();
lblCurrPage.Text = intCurrPage.ToString();
}
}
The RotateFlip function will change the source image and flatten it to only one page. This means we need to make copies each time you view a new page that has rotation applied.
In this solution, I use the source image and simply change pages when no rotation is applied. But when rotation is set, then a Image copy is made for each page and then the rotation is applied to the copy only.
Using your sample image it takes time to load each page. So I implemented a simple label message to let the user know it's working.
Also, you may consider looking into classes prebuilt for tiff files like: https://bitmiracle.github.io/libtiff.net/
private Image _Source = null;
private int _TotalPages = 0;
private int _CurrentPage = 0;
private void Frm_TiffViewer_Load(object sender, EventArgs e)
{
lbl_WaitMessage.Visible = false;
// These two options can be adjusted as needed and probably should be set in the form control properties directly:
pictureBox1.Size = new Size(750, 1100);
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}
private void ShowProcessingImageLabel()
{
lbl_WaitMessage.Visible = true;
Application.DoEvents();
}
private void DisplayPage(int PageNumber, RotateFlipType Change)
{
if (pictureBox1.Image != null && pictureBox1.Image != _Source)
{
// Release memory for old rotated image
pictureBox1.Image.Dispose();
}
// set the variable to null for easy GC cleanup
pictureBox1.Image = null;
_Source.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, PageNumber - 1);
pictureBox1.Image = new Bitmap(_Source);
pictureBox1.Image.RotateFlip(Change);
pictureBox1.Refresh();
}
private void DisplayPage(int PageNumber)
{
ShowProcessingImageLabel();
this.lblCurrPage.Text = PageNumber.ToString();
// You could adjust the PictureBox size here for each frame OR adjust the image to fit the picturebox nicely.
if (Radio_90_Rotate.Checked == true)
{
DisplayPage(PageNumber, RotateFlipType.Rotate90FlipNone);
lbl_WaitMessage.Visible = false;
return;
}
else if (Radio_180_Rotate.Checked == true)
{
DisplayPage(PageNumber, RotateFlipType.Rotate180FlipNone);
lbl_WaitMessage.Visible = false;
return;
}
if (pictureBox1.Image != _Source)
{
if (pictureBox1.Image != null)
{
// Release memory for old copy and set the variable to null for easy GC cleanup
pictureBox1.Image.Dispose();
pictureBox1.Image = null;
}
pictureBox1.Image = _Source;
}
pictureBox1.Image.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, PageNumber-1);
pictureBox1.Refresh();
lbl_WaitMessage.Visible = false;
}
private void Open_Btn_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
// Before loading you should check the file type is an image
this._Source = Image.FromFile(openFileDialog1.FileName);
_TotalPages = _Source.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
_CurrentPage = 1;
lblCurrPage.Text = "1";
lblFile.Text = openFileDialog1.FileName;
this.lblNumPages.Text = _TotalPages.ToString();
DisplayPage(_CurrentPage);
}
}
private void NextPage_btn_Click(object sender, EventArgs e)
{
if (_CurrentPage < _TotalPages)
{
_CurrentPage++;
}
DisplayPage(_CurrentPage);
}
private void b_Previous_Click(object sender, EventArgs e)
{
if (_CurrentPage > 1)
{
_CurrentPage--;
}
DisplayPage(_CurrentPage);
}
private void Radio_90_Rotate_CheckedChanged(object sender, EventArgs e)
{
DisplayPage(_CurrentPage);
}
private void Radio_180_Rotate_CheckedChanged(object sender, EventArgs e)
{
DisplayPage(_CurrentPage);
}
private void Radio_0_Default_CheckedChanged(object sender, EventArgs e)
{
DisplayPage(_CurrentPage);
}
I`m Created Custom Mode v3.1
public Image _Image_v3_1_CustomMode(Image b1, float angle,float dx,float dy,float sx,float sy)
{
Bitmap bitmap = new Bitmap(b1.Width, b1.Height);
using(Graphics ehack = Graphics.FromImage(bitmap))
{
ehack.RotateTransform(angle);
ehack.TranslateTransform(dx, dy);
ehack.ScaleTransform(sx, sy);
ehack.DrawImage(b1, 0, 0);
return bitmap;
}
}
Related
How to make slideshow to automaticly changing pictures in picturebox? currently im using imagelist but it didnt seems to works. I want the timer to change the image every 3 seconds. this is the timer code I'm using. it works well before to click buttons every 3 seconds but not working with imagelist. I'm new with imagelist & slideshows so if have any suggestion about it please tell me. thanks.
private bool _timerEnabled;
private async Task StartTimer()
{
_timerEnabled = true;
int i = 0;
while (_timerEnabled)
{
i++;
if (i > 2) { i = 0; }
pictureBox2.Image = imageList1.Images[i];
bmp = new Bitmap(pictureBox2.Image, pictureBox2.Width, pictureBox2.Height);
pictureBox1.Refresh();
pictureBox2.Refresh();
await Task.Delay(3000);
}
}
private async void timerStartButton_Click(object sender, EventArgs e)
{
timerStopButton.Enabled = true;
timerStartButton.Enabled = false;
if (_timerEnabled)
return;
await StartTimer();
}
private void timerStopButton_Click(object sender, EventArgs e)
{
timerStopButton.Enabled = false;
timerStartButton.Enabled = true;
_timerEnabled = false;
}
the slideshow works fine now but the used image become blurry. How to fix this one?
Original Image
Blurry result
EDIT.
after checking it again the blurry result is from imagelist control that automaticly set the image size to 16,16. it seems cant get it any bigger than 320,320. know how to make it can use bigger resolution size?
Simply move int i out of the while loop.
private async Task StartTimer() {
_timerEnabled = true;
int i = 0; //Move this here
while (_timerEnabled) {
i++;
if (i > 2) { i = 0; }
pictureBox2.Image = imageList1.Images[i];
pictureBox1.Refresh();
pictureBox2.Refresh();
await Task.Delay(3000);
}
}
Or you can use the inbuilt timer control instead of reinventing the wheel.
Timer timer1;
int i = 0;
//Form's constructor
public Form1
{
timer1 = new Timer();
timer1.Interval = 3000;
timer1.Tick += new EventHandler(timer1_tick);
}
private void timer1_tick(object sender, EventArgs e)
{
i++;
if (i > 2) { i = 0; }
pictureBox2.Image = imageList1.Images[i];
pictureBox1.Refresh();
pictureBox2.Refresh();
}
private async void timerStartButton_Click(object sender, EventArgs e) {
timerStopButton.Enabled = true;
timerStartButton.Enabled = false;
if (timer1.Enabled) return;
timer1.Enabled = True;
}
private void timerStopButton_Click(object sender, EventArgs e) {
timerStopButton.Enabled = false;
timerStartButton.Enabled = true;
timer1.Enabled = false;
}
I need to change the image by clicking on pictureBox, but when I click it again I can't return former picture
Here is my code:
private void PictureBox_Click(object sender, EventArgs e)
{
if (pictureBox.Image == Properties.Resources.openeye)
pictureBox.Image = Properties.Resources.closeeye;
else
pictureBox.Image = Properties.Resources.openeye;
}
How can I fix it?
Here's an example that demonstrates it with two images. One of an "x" another of an "o".
As you can see, the form has two instance variables x and o to store each of the Image objects. There is another flag field called isX which the ClickHandle event handler uses to check which image is currently displayed and switch to the other image, the event handler then toggles the isX field so the next click responds properly.
public void Main(string[] args)
{
var f1 = new Form1(); // form instance that holds the PictureBox
Task.Run(() => Application.Run(f1)); //I'm running this from LINQPad, but this would also work in a console application.
}
public class Form1 : Form // Derives from the Form class
{
private bool isX; // private instance variable to indicate which image is diplayed
private Image x; // private instance variable storing the x image
private Image o; // private instance variable storing the o image
// the picture box this form uses
private PictureBox p;
public Form1()
{
// load the images from wherever they are stored.
// I do this at construction time to avoid doing disk IO when clicking
x = Image.FromFile(#"C:\image\path\x.png");
o = Image.FromFile(#"C:\image\path\o.png");
// Initialize the picture box
p = new PictureBox {
Name = "p1",
Size = new Size(100,100),
Location = new Point(100,100),
Image = o //Initialize with the o image
};
// register the click event handler
p.Click += this.ClickHandle;
// set the flag to false, since the o image is what we start with
this.isX = false;
// add PictureBox p to the form
this.Controls.Add(p);
}
// handles the click action, registered to the PictureBox.Click event
private void ClickHandle(object sender, EventArgs e)
{
// use the flag to check which image is shown, and display the other image
if(this.isX) // this might work with your image == check, I didn't test it
{
p.Image = this.o;
}
else
{
p.Image = this.x;
}
// set the flag to the opposite of whatever the flag currently is
this.isX = ! isX;
}
}
You can set value of picturebox image, but you cant get it that way.
U can use global variable out of method and go this way.
int i = 0;
private void PictureBox1_Click(object sender, EventArgs e)
{
if (i == 0)
{
pictureBox1.Image = Properties.Resources.close;
i++;
}
else
{
pictureBox1.Image = Properties.Resources.open;
i--;
}
}
You can use this.
private void pictureBox1_Click(object sender, EventArgs e)
{
if (pictureBox1.Image!=null&& getSignatureLen( pictureBox1.Image) == getSignatureLen(Properties.Resources.openeye))
{
pictureBox1.Image = Properties.Resources.closeeye;
}
else
{
pictureBox1.Image = PProperties.Resources.openeye;
}
}
public long getSignatureLen(Image img)
{
using (System.IO.MemoryStream mStream = new System.IO.MemoryStream())
{
img.Save(mStream, img.RawFormat);
return mStream.Length;
}
}
You can save the value in the un-used Tag property, of the PictureBox object.
pictureBox1.Tag = 1; //Set it to whatever
if (pictureBox1.Tag == "1") { } //Do your check
(Short Screen-Cast explaining the problem)
I'm making a Clipboard program, that allows you to see what's in your clipboard.
It looks like this:
It seems to work fine copying on-the-fly.
The problem is that I want to be able to go back to a previous img/txt in clipboard and use it - that's when I use the check-mark button.
It works, the only problem is that it copies it twice into the list of images / listbox I'm using. It also happens when I initialize the listbox/picturebox.
Here's the code:
namespace Clipboard_Wizard
{
public partial class FormMain : Form
{
//register the program in the clipboard viewer chain
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
private const int WM_DRAWCLIPBOARD = 0x0308; // WM_DRAWCLIPBOARD message
private IntPtr _clipboardViewerNext; // Our variable that will hold the value to identify the next window in the clipboard viewer chain
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
ChangeClipboardChain(this.Handle, _clipboardViewerNext); // Removes our from the chain of clipboard viewers when the form closes.
}
List<Image> img = new List<Image>();
int ImgCount = 0;
int ImgIndex = -1;
Image tmp;
public FormMain()
{
InitializeComponent();
_clipboardViewerNext = SetClipboardViewer(this.Handle); // Adds our form to the chain of clipboard viewers.
//set listbox/picturebox to whatever already on clipboard
if (Clipboard.ContainsImage())
{
tmp = Clipboard.GetImage();
pictureBox1.Image = tmp;
img.Add(tmp);
ImgCount++;
ImgIndex++;
btnSlctImg.Enabled = true;
label3.Text = "Image 1 / 1";
}
else if (Clipboard.ContainsText())
{
listBox1.Items.Add(Clipboard.GetText());
}
}
// clears everything from the form and the clipboard
private void btnClear_Click(object sender, EventArgs e)
{
Clipboard.Clear();
listBox1.Items.Clear();
img.Clear();
pictureBox1.Image = null;
ImgCount = 0;
ImgIndex = -1;
btnSlctImg.Enabled = false;
}
private void btnUpdate_Click(object sender, EventArgs e)
{
/*if (Clipboard.ContainsImage())
{
tmp = Clipboard.GetImage();
pictureBox1.Image = tmp;
img.Add(tmp);
ImgCount++;
ImgIndex = ImgCount - 1;
}
else if (Clipboard.ContainsText())
{
listBox1.Items.Add(Clipboard.GetText());
listBox1.TopIndex = listBox1.Items.Count - 1;
}*/
}
private void btnUp_Click(object sender, EventArgs e)
{
if(ImgIndex == -1)
{
MessageBox.Show("No image.");
}
else if (ImgIndex < ImgCount - 1)
{
ImgIndex++;
pictureBox1.Image = img[ImgIndex];
label3.Text = "Image " + (ImgIndex + 1).ToString() + " / " + ImgCount.ToString() ;
}
else
{
MessageBox.Show("This is the last image.");
}
}
private void btnDown_Click(object sender, EventArgs e)
{
if(ImgIndex == -1)
{
MessageBox.Show("No image.");
}
else if (ImgIndex > 0)
{
ImgIndex--;
pictureBox1.Image = img[ImgIndex];
label3.Text = "Image " + (ImgIndex + 1).ToString() + " / " + ImgCount.ToString();
}
else
{
MessageBox.Show("This is the first image.");
}
}
private void btnDeselect_Click(object sender, EventArgs e)
{
listBox1.SelectedIndex = -1;
}
//sets clipboard to selected txt from listbox
private void btnSlct_Click(object sender, EventArgs e)
{
string slctTxt = listBox1.SelectedItem.ToString();
if (slctTxt != null || slctTxt != "")
{
Clipboard.SetText(slctTxt);
}
}
//sets clipboard to selected image
private void btnSlctImg_Click(object sender, EventArgs e)
{
Image slctImg = pictureBox1.Image;
if (slctImg != null)
{
Clipboard.SetImage(slctImg);
}
}
private void listBox1_SelectedIndexChanged_1(object sender, EventArgs e)
{
if (listBox1.SelectedIndex != -1)
{
btnSlctTxt.Enabled = true;
}
else
{
btnSlctTxt.Enabled = false;
}
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m); // Process the message
if (m.Msg == WM_DRAWCLIPBOARD)
{
//btnUpdate.PerformClick();
IDataObject iData = Clipboard.GetDataObject(); // Clipboard's data
if (iData.GetDataPresent(DataFormats.Text))
{
string text = (string)iData.GetData(DataFormats.Text); // Clipboard text
listBox1.Items.Add(text);
listBox1.TopIndex = listBox1.Items.Count - 1;
}
else if (iData.GetDataPresent(DataFormats.Bitmap))
{
tmp = (Bitmap)iData.GetData(DataFormats.Bitmap); // Clipboard image
pictureBox1.Image = tmp;
img.Add(tmp);
ImgCount++;
ImgIndex = ImgCount - 1;
label3.Text = "Image " + ImgCount.ToString() + " / " + ImgCount.ToString();
btnSlctImg.Enabled = true;
}
}
}
}
}
Update: It seems the problem is whenever I call the Clipboard.SetImage(...) or Clipboard.SetText(...) - it does it twice. Still don't understand why though.
You have defined a WndProc to catch changes to the clipboard and add the contents to lists.
In your btnSlctImg_Click to do just that:
if (slctImg != null) { Clipboard.SetImage(slctImg); }
So, of course the clipboard is changed, the WndProc is triggered and the currently selected image is added once again to the list you have..
To avoid that you may need to test the lists to see if the image or the text are already in the list. For text this is trivial but for images this is anything but simple. You may have to create and store fingerprints to decide if an image is already in the list.
Here is a post that has examples of creating an MD5 hash for an image.
A simpler trick would be a flag you set in the btnSlctImg_Click right before the Clipboard.SetImage and test and clear in the WndProc. You could still get duplicates, but only if the same data are copied by the user outside of the program..
I wrote a Clipboard utility some time ago and posted it on CodeProject ClipSpy+
I think it will help you with what you are doing!
I'm trying to save the contents of a PictureBox to a database. This in itself works well, however once the signature picture box has been drawn on, it is not setting the PictureBox.Image property, meaning I can't continue with the process.
Pen myPen;
bool bMouseDown = false;
Point prevPoint;
Graphics gCust;
Graphics gTech;
private void NewJob_Load(object sender, EventArgs e)
{
myPen = new System.Drawing.Pen(System.Drawing.Color.Black);
gCust = pbCustomerSig.CreateGraphics();
gCust.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
myPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
myPen.SetLineCap(LineCap.Round, LineCap.Round, DashCap.Round);
myPen.Color = Color.Blue;
myPen.Width = 2f;
}
public static byte[] ImageToBinary(Image image)
{
Byte[] buffer = (Byte[])new ImageConverter().ConvertTo(image, typeof(Byte[]));
return buffer;
}
private void pbCustomerSig_MouseDown(object sender, MouseEventArgs e)
{
prevPoint = e.Location;
bMouseDown = true;
}
private void pbCustomerSig_MouseMove(object sender, MouseEventArgs e)
{
if (bMouseDown)
{
Point thisPoint = e.Location;
if (prevPoint.X == 0 && prevPoint.Y == 0)
{
prevPoint = thisPoint;
return;
}
gCust.DrawLine(myPen, thisPoint.X, thisPoint.Y, prevPoint.X, prevPoint.Y);
prevPoint = thisPoint;
}
}
private void pbCustomerSig_MouseUp(object sender, MouseEventArgs e)
{
bMouseDown = false;
}
The error is here -
h.CustomerSignature = ImageToBinary(pbCustomerSig.Image);
Any ideas why the PictureBox.Image property is null?
Many thanks!
You did not assign a value for pbCustomerSig.Image. It's normal to be null.
Instead of doing that try to draw into a bitmap.
Here is a sample for drawing on existing bitmap but you can draw on a empty bitmap with same way and show it on picturebox at the same time.
I am working on a windows form application.
I want a image slider to be displayed at the bottom of my windows application, something like this:
Image slide example
Image paths would be grabbed from a DB. Any idea how to implement this?
Thanks in advance :)
I don't know if you want a slider that shows only one picture at a time or more, but you can adapt the code if you need the latter.
private void showImage(string path)
{
Image imgtemp = Image.FromFile(path);
pictureBox1.Width = imgtemp.Width / 2;
pictureBox1.Height = imgtemp.Height / 2;
pictureBox1.Image = imgtemp;
}
If you want it to work only on an automated mode, use only one method:
private void prevImage()
{
if(selected == 0)
{
selected = folderFile.Length - 1;
showImage(folderFile[selected]);
}
else
{
selected = selected - 1; showImage(folderFile[selected]);
}
}
private void nextImage()
{
if(selected == folderFile.Length - 1)
{
selected = 0;
showImage(folderFile[selected]);
}
else
{
selected = selected + 1; showImage(folderFile[selected]);
}
}
Now the timer and the start slideshow button:
private void timer1_Tick(object sender, System.EventArgs e)
{
nextImage();
}
private void Start_Click(object sender, System.EventArgs e)
{
if(timer1.Enabled == true)
{
timer1.Enabled = false;
Start.Text = "<< START Slide Show >>";
}
else
{
timer1.Enabled = true;
Start.Text = "<< STOP Slide Show >>";
}
}
From here. However, if you need something more than this you can read check ImageSlider from devexpress.