I have code that scan file and save it on my path:
public ImageFile Scan()
{
var device = this._deviceInfo.Connect();
var item = device.Items[1];
var imageFile = (ImageFile)item.Transfer(FormatID.wiaFormatJPEG);
return imageFile;
}
protected void btnscan_Click(object sender, EventArgs e)
{
foreach (Object scanner in scanners)
{
if (ddlSelectDevice.SelectedItem.ToString().Equals(scanner.ToString()))
{
//var d = ddlSelectDevice.SelectedIndex as Scanner;
var device = scanner as Scanner;
if (device == null)
{
return;
}
var image = device.Scan();
var path = "~/Scanner/scan.jpeg";
if (File.Exists(Server.MapPath(path)))
{
File.Delete(Server.MapPath(path));
}
image.SaveFile(Server.MapPath(path));
break;
}
}
}
I save this image in database by convert to byte:
private byte[] image2Byte()
{
string filePath = null;
Byte[] bytes = null;
if (File.Exists(Server.MapPath("~/Scanner/scan.jpeg")))
{
filePath = Server.MapPath("~/Scanner/scan.jpeg");
return bytes = File.ReadAllBytes(filePath);
}
else
{
filePath = Server.MapPath("~/Scanner/None.jpg");
return bytes = File.ReadAllBytes(filePath);
}
}
But my images usually have large size (up 400kB) and makes problem on load. How I can reduce image size?
You can use ImageProcessor to reduce the quality of the JPEG file. A quality of 80% is accaptable for most use cases.
using (ImageFactory imageFactory = new ImageFactory(preserveExifData:true))
{
imageFactory.Load(inStream)
.Quality(80)
.Save(outStream);
}
Related
I use the NTWAIN library, found a good solution for interacting with this library, modified it a little. This is actually it:
public class ScanningTwain
{
List<Image> ImagesScan;
DataSource myDS;
TwainSession session;
public ScanningTwain()
{
ImagesScan = new List<Image>();
}
public List<Image> Scan(decimal dpi)
{
ImagesScan.Clear();
var appId = TWIdentity.CreateFromAssembly(DataGroups.Image, Assembly.GetExecutingAssembly());
session = new TwainSession(appId);
session.TransferReady += session_TransferReady;
session.DataTransferred += session_DataTransferred;
session.SourceDisabled += session_SourceDisable;
session.Open();
IEnumerable<DataSource> lesSources = session.GetSources();
myDS = lesSources.FirstOrDefault();
myDS.Open();
PixelType typeCouleur = PixelType.Gray;
if (myDS.Capabilities.ICapPixelType.CanSet &&
myDS.Capabilities.ICapPixelType.GetValues().Contains(typeCouleur))
{
myDS.Capabilities.ICapPixelType.SetValue(typeCouleur);
}
TWFix32 DPI = (float)dpi;
if (myDS.Capabilities.ICapXResolution.CanSet &&
myDS.Capabilities.ICapXResolution.GetValues().Contains(DPI))
{
myDS.Capabilities.ICapXResolution.SetValue(DPI);
}
if (myDS.Capabilities.ICapYResolution.CanSet &&
myDS.Capabilities.ICapYResolution.GetValues().Contains(DPI))
{
myDS.Capabilities.ICapYResolution.SetValue(DPI);
}
myDS.Enable(SourceEnableMode.ShowUI, false, System.IntPtr.Zero);
EventWaitHandle session_SourceDisable_Wait = new EventWaitHandle(false, EventResetMode.AutoReset);
session_SourceDisable_Wait.WaitOne();
return ImagesScan;
}
void session_DataTransferred(object sender, NTwain.DataTransferredEventArgs e)
{
if (e.NativeData != IntPtr.Zero)
{
Bitmap img = null;
//Need to save out the data.
Stream s = e.GetNativeImageStream();
BitmapSource bitmapsource = s.ConvertToWpfBitmap();
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapsource));
enc.Save(outStream);
img = new Bitmap(outStream);
}
if (img != null)
{
ImagesScan.Add(img);
}
}
}
void session_SourceDisable(object sender, EventArgs e)
{
myDS.Close();
session.Close();
}
void session_TransferReady(object sender, NTwain.TransferReadyEventArgs e)
{
}
}
The error occurs at the line: myDS.Open () ; in the public List <Image> Scan (decimal dpi) method writes that myDS = null , I suppose this is due to the fact that when this line is executed session.Open () ; DSM does not appear so that you can select a scanner. Although I downloaded DSM from the official site. Thank you in advance for your help!
I have an application that allows the users to upload the selected images to the DataGridView and perform operations on their. However, when multiple images are selected, the Form freezes until the image information is uploaded to the DataGridView. I have tried BackgroundWorker for this, but it didn't work either. My codes look like this:
private void button1_Click(object sender, EventArgs e)
{
var file = new OpenFileDialog
{
Filter = #"TIFF |*.tiff| TIF|*.tif",
FilterIndex = 1,
Title = #"Select TIFF file(s)...",
Multiselect = true
};
if (file.ShowDialog() == DialogResult.OK)
{
Listing(file.FileNames);
}
}
private void Listing(string[] files)
{
foreach (var file in files)
{
var pic_name = Path.GetFileName(file);
if (file != null)
{
// Image from file
var img = Image.FromFile(file);
// Get sizes of TIFF image
var pic_sizes = img.Width + " x " + img.Height;
// Get size of TIFF image
var pic_size = new FileInfo(file).Length;
//Create the new row first and get the index of the new row
var rowIndex = dataGridView1.Rows.Add();
//Obtain a reference to the newly created DataGridViewRow
var row = dataGridView1.Rows[rowIndex];
//Now this won't fail since the row and columns exist
row.Cells["name"].Value = pic_name;
row.Cells["sizes"].Value = pic_sizes + " pixels";
row.Cells["size"].Value = pic_size + " bytes";
}
}
}
How can I solve this problem?
EDIT: After Alex's comment, I tried like this:
private void button1_Click(object sender, EventArgs e)
{
var file = new OpenFileDialog
{
Filter = #"TIFF |*.tiff| TIF|*.tif",
FilterIndex = 1,
Title = #"Select TIFF file(s)...",
Multiselect = true
};
if (file.ShowDialog() == DialogResult.OK)
{
_ = Test(file.FileNames);
}
}
private async Task Test(string[] s)
{
await Task.Run(() => Listing(s));
}
private void Listing(string[] files)
{
BeginInvoke((MethodInvoker) delegate
{
foreach (var file in files)
{
var pic_name = Path.GetFileName(file);
if (file != null)
{
// Image from file
var img = Image.FromFile(file);
// Get sizes of TIFF image
var pic_sizes = img.Width + " x " + img.Height;
// Get size of TIFF image
var pic_size = new FileInfo(file).Length;
//Create the new row first and get the index of the new row
var rowIndex = dataGridView1.Rows.Add();
//Obtain a reference to the newly created DataGridViewRow
var row = dataGridView1.Rows[rowIndex];
//Now this won't fail since the row and columns exist
row.Cells["name"].Value = pic_name;
row.Cells["sizes"].Value = pic_sizes + " pixels";
row.Cells["size"].Value = pic_size + " bytes";
}
}
});
}
But unfortunately the result is same.
I think the whole problem is in collecting image datas. Because a ready list will not take longer to load if it will not need extra processing. For this reason, I prepared a scenario like below.
private readonly BindingList<Tiff> _tiffs = new BindingList<Tiff>();
private void button1_Click(object sender, EventArgs e)
{
Listing();
}
private void Listing()
{
foreach (var f in _tiffs)
{
if (f != null)
{
var rowIndex = dataGridView1.Rows.Add();
//Obtain a reference to the newly created DataGridViewRow
var row = dataGridView1.Rows[rowIndex];
//Now this won't fail since the row and columns exist
row.Cells["ColName"].Value = f.ColName;
row.Cells["ColSizes"].Value = f.ColSizes + " pixels";
row.Cells["ColSize"].Value = f.ColSize + " bytes";
}
}
}
public static List<string> Files(string dir, string ext = "*.tiff")
{
var DirInfo = new DirectoryInfo(dir);
return DirInfo.EnumerateFiles(ext, SearchOption.TopDirectoryOnly).Select(x => x.FullName).ToList();
}
public void SetSource()
{
// Source folder of images...
var files = Files(#"___SOURCE_DIR___");
var total = files.Count;
var i = 1;
foreach (var file in files)
{
var pic_name = Path.GetFileName(file);
var img = Image.FromFile(file);
// Get sizes of TIFF image
var pic_sizes = img.Width + " x " + img.Height;
// Get size of TIFF image
var pic_size = new FileInfo(file).Length.ToString();
_tiffs.Add(new Tiff(pic_name, pic_sizes, pic_size));
BeginInvoke((MethodInvoker)delegate
{
label1.Text = $#"{i} of {total} is added to the BindingList.";
});
i++;
}
}
private void button2_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
SetSource();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Set something if you want.
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Set something if you want.
}
public class Tiff
{
public Tiff(string name, string sizes, string size)
{
ColName = name;
ColSizes = sizes;
ColSize = size;
}
public string ColName { get; set; }
public string ColSizes { get; set; }
public string ColSize { get; set; }
}
And here is the result:
I am trying to load about 60 pictures in a list. Each picture is about 1MB. For 20 pictures no problem but above that I get Out of memory exception on the code line below. I have searched vastly of related issues, some stating about "using" key word and stream but since I am a beginner can someone please help me.
Image image = Bitmap.FromFile(Filename);
Here is my code
private void LoadBtn_Click_1(object sender, EventArgs e)
{
OpenFileDialog newDialog = new OpenFileDialog();
if (newDialog.ShowDialog() == DialogResult.OK)
{
images.Clear();
string dirPath = System.IO.Path.GetDirectoryName(newDialog.FileName.ToLower());
DirectoryInfo di = new DirectoryInfo(dirPath);
FileInfo[] finfos = di.GetFiles("*.*");
foreach (FileInfo fi in finfos)
{
string ext = fi.Extension.ToLower();
if ((ext.Equals(".png")) || (ext.Equals(".jpg")) || (ext.Equals(".tif")) || (ext.Equals(".gif")))
{
string Filename = fi.FullName;
Image image = Bitmap.FromFile(Filename); //exception occurs HERE
images.Add(image);
//this.imageList1.Images.Add(image);
//image.Dispose();
}
}
}
pictureBox3.Image = images[0];
}
I am using C#, windows forms. thanks
After taking a look at the software you mentioned, as I told you you don't need to load the whole image in memory if you only need a thumbnail.
So I'd create I class
class ImageAndThumb
{
public Image Thumb;
public Image Big;
private string ImagePath;
public ImageAndThumb(string fileName)
{
ImagePath = fileName;
Image image = Image.FromFile(fileName)
Image thumb = img.GetThumbnailImage(200, 200, ()=>false, IntPtr.Zero);
}
public Image LoadBigImage()
{
Big = Image.FromFile(ImagePath);
return Big;
}
public void UnloadImage()
{
Big = null;
}
}
Now we use that class:
List<ImageAndThumb> Images = new List<ImageAndThumb>();
private void LoadBtn_Click_1(object sender, EventArgs e)
{
OpenFileDialog newDialog = new OpenFileDialog();
if (newDialog.ShowDialog() == DialogResult.OK)
{
Images.Clear();
string dirPath = System.IO.Path.GetDirectoryName(newDialog.FileName.ToLower());
DirectoryInfo di = new DirectoryInfo(dirPath);
FileInfo[] finfos = di.GetFiles("*.*");
foreach (FileInfo fi in finfos)
{
string ext = fi.Extension.ToLower();
if ((ext.Equals(".png")) || (ext.Equals(".jpg")) || (ext.Equals(".tif")) || (ext.Equals(".gif")))
{
string Filename = fi.FullName;
ImageAndThumb image = new ImageAndThumb(Filename);
Images.Add(image);
}
}
}
pictureBox3.Image = Images[0].Thumb; // << Much less memory usage;
}
And now whenever you need to use an image load it first
For example:
void ShowPicture(int index)
{
Images[index].LoadBigImage();
PictureBoxBig.image = Images[index].Big;
}
void ClosePicture(int index)
{
Images[index].UnloadImage();
}
one good idea is to unload an image once you load another:
int currentPictureIndex = -1;
void ShowPicture(int index)
{
Images[index].LoadBigImage();
PictureBoxBig.image = Images[index].Big;
if(CurrentPictureIndex > -1) ClosePicture(CurrentPictureIndex);
currentPictureIndex = index;
}
First of all, are you running out of memory ? Cause if you are then the error is valid.
If you are not running out of memory the first thing you will need to do is wrap the code in your foreach loop in a try/catch block as follows:
foreach (FileInfo fi in finfos)
{
string ext = fi.Extension.ToLower();
if ((ext.Equals(".png")) || (ext.Equals(".jpg")) || (ext.Equals(".tif")) || (ext.Equals(".gif")))
{
try
{
string Filename = fi.FullName;
Image image = Bitmap.FromFile(Filename); //exception occurs HERE
images.Add(image);
//this.imageList1.Images.Add(image);
//image.Dispose();
}
catch {}
}
}
The reason for that is, as Jason Watkins mentioned in the comments it might as well be another form of error that just appears as an out of memory exception because of the lack of error messages in the Class.
i am trying to take screenshot of page and save it as image. The page has several div tags and different contents in each div like one div tag has chart and the other might have gridview. So i am trying to take snapshot of the page ans save it as image. Can someone please help me here as i have googled and could not find any good resources about this. thanks.
The following seems to work. I got this from Convert webpage to image from ASP.NET
use:
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Windows.Forms;
public class WebsiteToImage
{
private Bitmap m_Bitmap;
private string m_Url;
private string m_FileName = string.Empty;
public WebsiteToImage(string url)
{
// Without file
m_Url = url;
}
public WebsiteToImage(string url, string fileName)
{
// With file
m_Url = url;
m_FileName = fileName;
}
public Bitmap Generate()
{
// Thread
var m_thread = new Thread(_Generate);
m_thread.SetApartmentState(ApartmentState.STA);
m_thread.Start();
m_thread.Join();
return m_Bitmap;
}
private void _Generate()
{
var browser = new WebBrowser { ScrollBarsEnabled = false };
browser.Navigate(m_Url);
browser.DocumentCompleted += WebBrowser_DocumentCompleted;
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
browser.Dispose();
}
private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Capture
var browser = (WebBrowser)sender;
browser.ClientSize = new Size(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom);
browser.ScrollBarsEnabled = false;
m_Bitmap = new Bitmap(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom);
browser.BringToFront();
browser.DrawToBitmap(m_Bitmap, browser.Bounds);
// Save as file?
if (m_FileName.Length > 0)
{
// Save
m_Bitmap.SaveJPG100(m_FileName);
}
}
}
public static class BitmapExtensions
{
public static void SaveJPG100(this Bitmap bmp, string filename)
{
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bmp.Save(filename, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static void SaveJPG100(this Bitmap bmp, Stream stream)
{
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bmp.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static ImageCodecInfo GetEncoder(ImageFormat format)
{
var codecs = ImageCodecInfo.GetImageDecoders();
foreach (var codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
// Return
return null;
}
}
To implement:
WebsiteToImage websiteToImage = new WebsiteToImage( "http://www.cnn.com", #"C:\Some Folder\Test.jpg");
websiteToImage.Generate();
I am attempting to populate a secondary tile background with an image saved from the PhotoChooserTask, but for some reason I cannot accomplish this. I have referenced a lot of sites but I have not found the proper implementation. All I do is call PhotoChooserTask, and then on the completed event I save the resulting image to isolated storage to be loaded later. This has worked with a HubTile in my application, but for some reason I cannot append the image to a secondary tile. So far what I have is as follows:
MainPage.xaml.cs
string imageFolder = #"\Shared\ShellContent";
string shareJPEG = "shareImage.jpg";
public MainPage()
{
InitializeComponent();
photoChooserTask = new PhotoChooserTask();
photoChooserTask.Completed += new EventHandler<PhotoResult>(photoChooserTask_Completed);
}
public void changePictureMenuItem_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
try
{
photoChooserTask.Show();
}
catch (System.InvalidOperationException)
{
MessageBox.Show("An error occurred");
}
}
void photoChooserTask_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
//persist the data in isolated storage
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if(!myIsolatedStorage.DirectoryExists(imageFolder))
{
myIsolatedStorage.CreateDirectory(imageFolder);
}
if (myIsolatedStorage.FileExists(shareJPEG))
{
myIsolatedStorage.DeleteFile(shareJPEG);
}
string filePath = System.IO.Path.Combine(imageFolder, shareJPEG);
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(filePath);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(e.ChosenPhoto);
WriteableBitmap wb = new WriteableBitmap(bitmap);
// Encode WriteableBitmap object to a JPEG stream.
Extensions.SaveJpeg(wb, fileStream, 173, 173, 0, 100);
fileStream.Close();
}
}
}
private void CreateLiveTile(TileItem item)
{
//IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
var title = item.Title.ToString();
string tileParameter = "Param=" + item.Title.ToString();
ShellTile Tile = CheckIfTileExist(tileParameter); // Check if Tile's title has been used
if (Tile == null)
{
//this is not working?
background = new Uri(#"isostore:/Shared/ShellContent/shareJPEG.png", UriKind.Absolute);
//background = new Uri("isostore:/Shared/ShellContent/shareJPEG.png", UriKind.Absolute);
try
{
var LiveTile = new StandardTileData
{
Title = item.TileName,
BackgroundImage = background, //not working
BackTitle = item.TileName,
BackBackgroundImage = new Uri("/background.png", UriKind.Relative),
BackContent = item.Message,
};
ShellTile.Create(new Uri("/MainPage.xaml?" + tileParameter, UriKind.Relative), LiveTile);
}
}
Ultimately, the secondary tile is created but there is no image for the BackgroundImage. How would I properly call the isolated strorage path to set the BackgroundImage of the secondary tile accordingly? Or is there something else I should be doing or change?
MainPage.xaml.cs
string imageFolder = #"\Shared\ShellContent";
string shareJPEG = "shareImage.jpg";
...
private void CreateLiveTile(TileItem item)
{
var title = item.Title.ToString();
string tileParameter = "Param=" + item.Title.ToString();
ShellTile Tile = CheckIfTileExist(tileParameter); // Check if Tile's title has been used
if (Tile == null)
{
string filePath = System.IO.Path.Combine(imageFolder, shareJPEG);
background = new Uri(#"isostore" + filePath, UriKind.Absolute); //this worked
...
}
}
Are you sure the image is saved successfully and exists? You save it as jpeg but you reference a png file. Try #"\Shared\ShellContent\shareJPEG.png"
first you should put your image at "\Shared\ShellContent" location. you can use .png or .jpg file
string imageFolder = #"\Shared\ShellContent";
string shareJPEG = "shareImage.jpg";
...
private void CreateLiveTile(TileItem item)
{
var title = item.Title.ToString();
string tileParameter = "Param=" + item.Title.ToString();
ShellTile Tile = CheckIfTileExist(tileParameter);
if (Tile == null)
{
string filePath = System.IO.Path.Combine(imageFolder, shareJPEG);
using (var iso = IsolatedStorageFile.GetUserStoreForApplication())
{
if (iso.FileExists(filePath)) // check file exist or not
background = new Uri(#"isostore:" + filePath, UriKind.Absolute);
}
...
}
}