How to Reduce Size of Image in windows phone - c#

I am trying to port my app in windows phone . i have to upload an image on server So it is in small Size For uploading i have done this thing in Widows Successfully but problem is when i failed in it .. here is my code for windows App
public void CompressImage(int i, int j)
{
bmp1.SetPixel(j, i, Color.FromArgb(bmp.GetPixel(j, i).R, bmp.GetPixel(j, i).G, bmp.GetPixel(j, i).B));
}
private void bLoadImage_Click(object sender, EventArgs e)
{
OpenFileDialog file = new OpenFileDialog();
if (file.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = new Bitmap(file.FileName);
}
}
private void bCompression_Click(object sender, EventArgs e)
{
bmp = new Bitmap(pictureBox1.Image);
bmp1 = new Bitmap(bmp.Width, bmp.Height);
for (int i = 1; i < bmp.Height; i++)
for (int j = 1; j < bmp.Width; j++)
{
CompressImage(i, j);
}
pictureBox2.Image = bmp1;
bmp1.Save("Picture.jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
After Searching on google i found out that windows Phone does not support Bitmap .. any idea how i can do the same thing in windows phone or any other alternative for doing this

You should use WriteablBitmap to reduce size of image. WriteablBitmap has number of methods for images in windows phone Here is more about writeablebitmapex.

Try to load your original image to WriteableBitmap object, then you can use SaveJpeg() extension method from System.Windows.Media.Imaging namespace, to save new image with reduced size. For example :
.......
WriteableBitmap wb = new WriteableBitmap(bitmapImageObject);
wb.SaveJpeg(stream, 120, 160, 0, 100);
.......

When you are taking picture you can choose the resolution with which the picture will be taken. This can be done by
PhotoCamera cam;
After camera initizalition.
Following code when image is capturing (in the method that captures the image)
IEnumerable<Size> resList = cam.AvailableResolutions;
Size res;
if (resList.Count() > 0)
{
res = resList.ElementAt<Size>(0);
cam.Resolution = res;
}
This sample chooses the first resolution

You can try this. It worked for me. It reduced my 9.70MB file into 270KB.
WriteableBitmap cameraCapturedImage = PictureDecoder.DecodeJpeg(e.ChosenPhoto, 1024, 1024);
using (IsolatedStorageFileStream myFileStream = myStore.CreateFile(fileName))
{
System.Windows.Media.Imaging.Extensions.SaveJpeg(cameraCapturedImage, myFileStream, cameraCapturedImage.PixelWidth, cameraCapturedImage.PixelHeight, 0, 85);
myFileStream.Close();
}
N.B: fileName is the name of file to save size reduced image.

Related

Trying to read pixel color from PictureBox in C# WinForms

I am having an odd issue whereby when I then try to iterate over the pixels of the PictureBox or save the bmp it is just all black.
The intention of the tool is that you select a font, size, and style, and then it loops over the ASCII chars of that font and shows each character in the picture box, and converts the pixel data into a HEX array so I can use them on LCD displays.
The main part of the tool works whereby it is correctly looping through the ASCII chars and displaying them in the picture box but after each char is drawn to the picture box and I then try to iterate over the pixels of the PictureBox every pixel is returned as 0,0,0 RGB "black" and if I save the bmp which was drawn to the PictureBox that too is all black, but again I can see the bmp of that char correct drawn in the PictureBox yet the PictureBox data and bmp data does not match what I see in the PictureBox itself, I am truly lost as to why I am unable to correctly iterate or save the bmp or PictureBox.
I have tried not using async functions which is not ideal as I want the UI to be free, and I have tried various means to read the pixels and save the bmp but the result is the same. I hope to ask if anyone knows why I am getting this odd behavior and the solution to the issue.
Regards from Ed.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace generateFonts
{
public partial class Form1 : Form
{
string font = "";
float fontSize = 0;
FontStyle fontStyle = FontStyle.Regular;
public Form1()
{
InitializeComponent();
comboBox1.SelectedIndex = 0;
comboBox2.SelectedIndex = 0;
comboBox3.SelectedIndex = 0;
font = comboBox1.SelectedItem.ToString();
fontSize = Convert.ToInt32(comboBox2.SelectedItem);
fontStyle = FontStyle.Regular;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
font = comboBox1.SelectedItem.ToString();
}
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
fontSize = Convert.ToInt32(comboBox2.SelectedItem);
}
private void comboBox3_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox3.SelectedIndex == 0)
fontStyle = FontStyle.Regular;
else if (comboBox3.SelectedIndex == 1)
fontStyle = FontStyle.Italic;
else if(comboBox3.SelectedIndex == 2)
fontStyle = FontStyle.Bold;
}
private async void button1_Click(object sender, EventArgs e)
{
await Task.Run(() => StartProcess(1));
}
private void StartProcess(int runs)
{
// Font
Font myFont = new Font(font, fontSize, fontStyle);
List<string> bytes = new List<string>();
string[] bits = { "0", "0", "0", "0", "0", "0", "0", "0" };
byte bitPos = 0;
for (byte i = 32; i < 126; i++)
{
//Create a Image-Object on which we can paint
Image bmp = new Bitmap(200, 200);
//Create the Graphics-Object to paint on the Bitmap
Graphics g = Graphics.FromImage(bmp);
string c = Convert.ToChar(i).ToString();
//Get the perfect Image-Size so that Image-Size = String-Size
SizeF size = g.MeasureString(c, myFont);
//Use this to become better Text-Quality on Bitmap.
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
//Here we draw the string on the Bitmap
g.DrawString(c, myFont, new SolidBrush(Color.Black), 0, 0);
if (!Directory.Exists("FontBmps"))
Directory.CreateDirectory("FontBmps");
this.Invoke((MethodInvoker)delegate ()
{
pictureBox2.Width = Convert.ToInt32(size.Width);
pictureBox2.Height = Convert.ToInt32(size.Height);
pictureBox2.Image = bmp; // <--- this is working and the picturebox shows the bmp correctly
bmp.Save("FontBmps/" + i + "_" + font + "_" + fontSize + "px_" + fontStyle + ".bmp", ImageFormat.Bmp); // <--- error here: this saves a black square instead of the bmp i see displayed in the picturebox GUI ??
// Even if i save the picturebox itself that too is just a black square instead of the correct image shown in the GUI ??
// now convert the bmp to a HEX array of pixels
for (int h = 0; h < pictureBox2.Height; h++)
{
for (int w = 0; w < pictureBox2.Width; w++)
{
Color colour = (pictureBox2.Image as Bitmap).GetPixel(w, h);
if (colour.R == 0 && colour.G == 0 && colour.B == 0)
{
bits[bitPos] = "1";
}
else
{
bits[bitPos] = "0"; // <-- never hits me, again for some reason the bmp or picturebox is all black pixels data but i see it correctly show in the picturebox GUI ??
}
if (bitPos < 7)
bitPos++;
else
{
//string bitStr = bits.ToString();
//string hex = Convert.ToByte(bitStr, 2).ToString("x2");
//bytes.Add(hex);
bitPos = 0;
for(byte n = 0; n < 8; n++)
{
bits[n] = "0";
}
}
}
}
if (bitPos != 0)
{
// TO DO...
}
});
Thread.Sleep(500); // <--- i have this just to see it displaying the chars but i have removed it with no effect to the issue
}
// now add List to a file in the correct format
foreach (string str in bytes)
{
Console.WriteLine(str);
// TO DO...
}
}
}
}
I believe the image is black, but some parts have transparency. That is, you would need to check Alpha (Color.A). What you see in the picture box, would be the background color of the picture box where it is transparent.
You won't see the transparency in the saved file, given that the ImageFormat.Bmp does not support transparency. Try Png instead, which supports transparency (and has lossless compression).
Alternatively, you can use Graphics.Clear to have the image be the color you want for background (white, I guess) before drawing to it.
Aside from that, I'll suggest to use bmp instead of (pictureBox2.Image as Bitmap), and use Bitmap.LockBits. That would improve performance.
This might be useful for reference: Converting a bitmap to monochrome. See also C# - Faster Alternatives to SetPixel and GetPixel for Bitmaps for Windows Forms App.

Screen recorder crashes when I move the form window

I have followed a bunch of tutorials and made a screen recorder. It works by taking a screenshot and then using the AForge.video addon to convert this to avi format. The programme worked fine, but it ran out of memory after about 20 seconds. This would either crash the program or clear itself with a huge lag spike. To stop this I added a disposal method at the end of every screenshot to clear the memory. This kept the memory usage down however it makes the application hugely unstable. When I move the main window or wait for about 3 minutes on recording, the programme crashes and shows this:
A screenshot of the error
Every time I remove the dispose methods, the programme moves fine but runs out of memory quickly. Maybe I'm just using the dispose method wrong.
Here's the code that crashes the programme. There is way to much code to include it all.
counter = 0;
imagelist = new Bitmap[100000];
Globals.imgcount = 0;
Graphics g;
basePath = sel.ToString();
basePath = #"C:\Users\sim\Videos\Captures";
using (var videowriter = new VideoFileWriter())
{
videowriter.Open(basePath + "timelapse.avi", Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, 9, VideoCodec.MPEG4, 1200000);
while (Globals.recording == true)
{
try
{
try
{
//takes the screenshot
bm = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
//turns it into graphics
g = Graphics.FromImage(bm);
g.CopyFromScreen(0, 0, 0, 0, bm.Size);
counter++;
videowriter.WriteVideoFrame(bm);
//display image
Bitmap original = bm;
Bitmap resized2 = new Bitmap(original, new Size(pictureBox1.Width, pictureBox1.Height));
bm = resized2;
pictureBox1.Image = bm;
Thread.Sleep(10);
if (/*counter % 18 == 0*/ true)
{
try
{
g.Dispose();
bm.Dispose();
original.Dispose();
resized2.Dispose();
}
catch
{
MessageBox.Show("Disposal error");
}
}
}
catch { }
}
catch { }
}
videowriter.Close();
}
I hope that this is enough information to figure something out.
Thanks to anyone who can help.
You are doing many things unnecessary eg creating 3 bitmaps instead of one, setting the image bm to picbox and of cource running the code to main UI. Of cource it will freeze. For an easy and quick fix create a timer. Set the interval to 10. Create a button that will stop the timer and one that will start it and record. In timer instead of calling
repeatedly
pictureBox1.Image = bm;
use
pictureBox1.Invalidate();
Code:
//not good names. change it to something meaningfull
private Bitmap bm;
private Graphics g;
VideoFileWriter videowriter;
private void timer1_Tick( object sender, EventArgs e ) {;
//takes the screenshot
g.CopyFromScreen( 0, 0, 0, 0, bm.Size );
videowriter.WriteVideoFrame(bm);
pictureBox1.Invalidate();
}
The button that starts the recording:
private void Start_Click( object sender, EventArgs e ) {
//create both bitmap and graphics once!
bm = new Bitmap( Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height );
g = Graphics.FromImage( bm );
pictureBox1.Image = bm; //Just once!
basePath = sel.ToString();
basePath = #"C:\Users\sim\Videos\Captures";
videowriter = new VideoFileWriter();
videowriter.Open(basePath + "timelapse.avi", Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, 9, VideoCodec.MPEG4, 1200000);
timer1.Enabled = true;
}
Button to stop recording:
private void Stop_Click( object sender, EventArgs e ) {
timer1.Enabled = false;
pictureBox1.Image = null;
bm.Dispose();
bm = null;
g.Dispose();
g = null;
videowriter.Close();
//I don't know if videowriter can be disposed if so dispose it too and set it to null
}
Also set picturebox SizeMode to StreachImage

c# - Print the winform in high quality?

This question may sound familiar but i have searched internet and couldn't find a solution to it.
I know for printing we can use Crystal Report but i am discarding that idea because of it's certain disadvantages. Here are some of the disadvantages:-
Needs installation on PC and if the Visual Studio version is 2017 then you have to download 200MB+ setup.
If you have made certain objects like textobject and lines in one section and you have to add something in the middle of it then you have to manually set location of every object otherwise if you collectively select all the object and move it then their original location and the spacing between each object gets lost.
Currently i am using VS2008 and it has crystal report integrated in it which has a well know problem of sometime changing the text of every textobject and adding an "i" in it for some reason.
I also tried to download an alternate to crystal report. But its interface is not that friendly.
Alternate that i am choosing
Now i have designed my report on Windows Form. When i am trying to print, its quality is worse as compared to Crystal Reports print. Here is the code for it
private System.IO.Stream streamToPrint;
string streamType;
private void printDoc_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
System.Drawing.Image image = System.Drawing.Image.FromStream(this.streamToPrint);
int x = e.MarginBounds.X;
int y = e.MarginBounds.Y;
int width = image.Width;
int height = image.Height;
if ((width / e.MarginBounds.Width) > (height / e.MarginBounds.Height))
{
width = e.MarginBounds.Width;
height = image.Height * e.MarginBounds.Width / image.Width;
}
else
{
height = e.MarginBounds.Height;
width = image.Width * e.MarginBounds.Height / image.Height;
}
System.Drawing.Rectangle destRect = new System.Drawing.Rectangle(x, y, width, height);
e.Graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, System.Drawing.GraphicsUnit.Pixel);
}
private void btnPrint_Click(object sender, EventArgs e)
{
string fileName = Application.StartupPath + "\\PrintPage.jpg";
using (Graphics gfx = this.CreateGraphics())
{
using (Bitmap bmp = new Bitmap(this.Width, this.Height, gfx))
{
this.DrawToBitmap(bmp, new Rectangle(0, 0, this.Width, this.Height));
bmp.Save(fileName);
}
}
FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StartPrint(fileStream, "Image");
fileStream.Close();
if (System.IO.File.Exists(fileName))
{
System.IO.File.Delete(fileName);
}
}
public void StartPrint(Stream streamToPrint, string streamType)
{
this.printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
this.streamToPrint = streamToPrint;
this.streamType = streamType;
System.Windows.Forms.PrintDialog PrintDialog1 = new PrintDialog();
PrintDialog1.AllowSomePages = true;
PrintDialog1.ShowHelp = true;
PrintDialog1.Document = printDoc;
DialogResult result = PrintDialog1.ShowDialog();
if (result == DialogResult.OK)
{
printDoc.Print();
//docToPrint.Print();
}
}
private void Frm_Test_Shown(object sender, EventArgs e)
{
try
{
btnPrint_Click(sender, e);
}
catch (Exception ex) { clsUtility.ShowErrMsg(ex.Message); }
}
I understand the reason why it is doing so because of the image and screen resolution thing (Ref : https://stackoverflow.com/a/12547806/2994869). The workaround people mentioned was to increase the size of windows form and it's object by 6 times but that had the same result still the quality is worse.
Is there any workaround or any trick that i can do to print a windows form so that quality is near to that of Crystal Report's.
For high quality you need to create a source with higher resolution than the screen, which is all you can get from DrawToBitmap.
Using DrawToBitmap will only help if you can enlarge a single control a lot. For the whole form it will not help.
You will need to fully re-create the parts you want to print and use as many DrawString and other DrawXXX methods as needed. Yes, a lot of work. (But fun ;-)
But the code you show also blunders by using a jpg file format, which was created for soft images (i.e. photographs). Change that to png and compare!

Resize image in c# and save this image

I have some task - resize image if height or width >500px.
I try this code.
But when I choosed image I have error like
NewImage.Save(path);
В GDI+ error of the general form.
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog fdlg = new OpenFileDialog();
fdlg.Multiselect = true;
if (fdlg.ShowDialog() == DialogResult.OK)
{
for (int i = 0; i < fdlg.FileNames.Length; i++)
{
string file = fdlg.FileNames[i];
string path = System.IO.Path.GetFullPath(file);
System.Drawing.Image img = System.Drawing.Image.FromFile(path);
if (img.Width > 500 || img.Height > 500)
{
int currW = img.Width;
int currH = img.Height;
int realWPer = 500 * 100 / currW;
int realHPer = 500 * 100 / currH;
int realW = currW / 100 * realWPer; // new width
int realH = currH / 100 * realHPer; // new height
Image NewImage = resizeImage(img, new Size(realW, realH));
NewImage.Save(path);
}
}
}
}
public static Image resizeImage(Image imgToResize, Size size)
{
return (Image)(new Bitmap(imgToResize, size));
}
You haven't posted the error message so one can only guess what may be wrong, I'd guess you get an error that you are trying to access a locked file.
You are trying to save the new image over the old image which is still open. You never close/dispose the img so it's still open when you try to save the new image using the same path as the old

Why do I keep getting a 'System.OutOfMemoryException'?

Here is my Code, I am trying to stitch two pictures together and as soon as I get to line 42 "Image img = Image.FromFile(file.FullName);" I get an out of memory error. What should I do?
namespace Practicing_Stiching
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void cmdCombine_Click(object sender, EventArgs e)
{
//Change the path to location where your images are stored.
DirectoryInfo directory = new DirectoryInfo(#"C:\Users\Elder Zollinger\Desktop\Images");
if (directory != null)
{
FileInfo[] files = directory.GetFiles();
CombineImages(files);
}
}
private void CombineImages(FileInfo[] files)
{
//change the location to store the final image.
string finalImage = #"C:\Users\Elder Zollinger\Desktop\Images";
List<int> imageHeights = new List<int>();
int nIndex = 0;
int width = 0;
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
imageHeights.Add(img.Height);
width += img.Width;
img.Dispose();
}
imageHeights.Sort();
int height = imageHeights[imageHeights.Count - 1];
Bitmap img3 = new Bitmap(width, height);
Graphics g = Graphics.FromImage(img3);
g.Clear(SystemColors.AppWorkspace);
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
if (nIndex == 0)
{
g.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
g.DrawImage(img, new Point(width, 0));
width += img.Width;
}
img.Dispose();
}
g.Dispose();
img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);
img3.Dispose();
imageLocation.Image = Image.FromFile(finalImage);
}
}
}
That's likely GDI playing tricks on you.
You see, when GDI encounters an unknown file, it will quite likely cause an OutOfMemoryException. Since you're not filtering the input images at all, I'd expect that you're simply grabbing a non-image file (or an image type that GDI doesn't understand).
Oh, and a bit sideways - make sure you set JPEG quality when saving JPEGs - the default is something like 75, which is rather bad for a lot of images. And please, do use using - it's very handy to ensure proper and timely clean-up :)
Get more memory!
But seriously, you don't appear to be filtering out files that are not image files. There are some hidden files in folders that you may be trying to open as an image accidentally, such as "Thumbs.db". Make sure that the file is an image with something like if (Path.GetExtension(file.FullPath) != ".png") continue;.
Also, on objects that you are calling .Dispose() on, consider wrapping them in a using() instead. For example:
using(var img = Image.FromFile(file.FullPath))
{
// ...
}

Categories