I have an image in an array and I'm saving it this way:
ImageConverter ic = new ImageConverter();
Image img = (Image)ic.ConvertFrom(Jpeg);
Bitmap bitmap1 = new Bitmap(img);
string saveString = "c:\\M_files\\new_pics\\" + pictureCounter + ".jpg";
bitmap1.Save(saveString, System.Drawing.Imaging.ImageFormat.Jpeg);
It works but I need it to be faster since its an image from camera that needs to stream. Is there a faster way? My array is in bytes then I use the container to convert to bitmap then save as jpeg.
try this code, this works fast and efficient, in this piece of code you can convert a picture to JPEG specitfying the width and height, and can pass as many number of images as you want. You can modify it to your own Requirement.
public void CreateThumbnail(string[] b, double wid, double hght, bool Isprint)
{
string[] path;
path = new string [64];
path = b;
string saveath = "i:\\check\\a test\\";
for (int i = 0; i < b.Length; i++)
{
DirectoryInfo dir = new DirectoryInfo(path[i]);
string dir1 = dir.ToString();
dir1 = dir1.Substring(dir1.LastIndexOf("\\"));
FileInfo[] files1 = dir.GetFiles();
foreach (FileInfo f in files1)
{
string gh = f.ToString();
try
{
System.Drawing.Image myThumbnail150;
System.Drawing.Image.GetThumbnailImageAbort myCallback = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback);
System.Drawing.Image imagesize = System.Drawing.Image.FromFile(f.FullName);
Bitmap bitmapNew = new Bitmap(imagesize);
double maxWidth = wid;
double maxHeight = hght;
int w = imagesize.Width;
int h = imagesize.Height;
// Longest and shortest dimension
int longestDimension = (w > h) ? w : h;
int shortestDimension = (w < h) ? w : h;
// propotionality
float factor = ((float)longestDimension) / shortestDimension;
// default width is greater than height
double newWidth = maxWidth;
double newHeight = maxWidth / factor;
// if height greater than width recalculate
if (w < h)
{
newWidth = maxHeight / factor;
newHeight = maxHeight;
}
myThumbnail150 = bitmapNew.GetThumbnailImage((int)newWidth, (int)newHeight, myCallback, IntPtr.Zero);
string ext = Path.GetExtension(f.Name);
if (!Directory.Exists(saveath + dir1))
{
Directory.CreateDirectory(saveath + dir1);
myThumbnail150.Save(saveath + dir1 + "\\" + f.Name.Replace(ext, ".Jpeg"), System.Drawing.Imaging.ImageFormat.Jpeg);
}
else if(Directory.Exists(saveath+dir1))
{
myThumbnail150.Save(saveath + dir1+" \\"+ f.Name.Replace(ext, ".Jpeg"), System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
catch (Exception ex)
{
Console.WriteLine("something went wrong" + ex.ToString());
}
}
}
}
Related
I'm working on a Xamarin app where user's can pick Images using the Xamarin Essentials plugin. My issue now is finding away to shrink the image size using the image full path, before it's loaded to the cloud.
The Code
// Pick Image
private async Task PickImages()
{
if (ImageCollection.Count >= 10)
{
ToastMessageLong("Cannot Select More then 10 Images.");
return;
}
ImageLink image = new();
try
{
FileResult result = await MediaPicker.PickPhotoAsync(new MediaPickerOptions
{
Title = "Pick an Image"
});
if (result == null) return;
image.PostImages = result.FullPath;
ImageCollection.Add(image);
}
catch (Exception x)
{
await DisplayAlert("", x.Message);
}
}
private async Task UploadImagesToCloud()
{
if (ImageCollection.Count > 0)
{
List<ImageLink> imageLinks = new();
foreach (ImageLink img in ImageCollection)
{
// Need to Compress Image before adding to cloud..
ImageLink link = await CloudService.CS.UploadPostImage(img.PostImages);
imageLinks.Add(link);
}
P.Images = imageLinks;
}
}
You could resize the image size befor uploading it to cloud.Here is one method for resizing the image:
#if __IOS__
public static byte[] ResizeImageIOS(byte[] imageData, float width, float height)
{
UIImage originalImage = ImageFromByteArray(imageData);
UIImageOrientation orientation = originalImage.Orientation;
//create a 24bit RGB image
using (CGBitmapContext context = new CGBitmapContext(IntPtr.Zero,
(int)width, (int)height, 8,
4 * (int)width, CGColorSpace.CreateDeviceRGB(),
CGImageAlphaInfo.PremultipliedFirst))
{
RectangleF imageRect = new RectangleF(0, 0, width, height);
// draw the image
context.DrawImage(imageRect, originalImage.CGImage);
UIKit.UIImage resizedImage = UIKit.UIImage.FromImage(context.ToImage(), 0, orientation);
// save the image as a jpeg
return resizedImage.AsJPEG().ToArray();
}
}
#if __ANDROID__
public static byte[] ResizeImageAndroid (byte[] imageData, float width, float height)
{
// Load the bitmap
Bitmap originalImage = BitmapFactory.DecodeByteArray (imageData, 0, imageData.Length);
Bitmap resizedImage = Bitmap.CreateScaledBitmap(originalImage, (int)width, (int)height, false);
using (MemoryStream ms = new MemoryStream())
{
resizedImage.Compress (Bitmap.CompressFormat.Jpeg, 100, ms);
return ms.ToArray ();
}
}
you could refer to ImageResizer
Solution I was Given using SkiaSharp.
public static string CreateThumbnail(string Path, string fileName)
{
var bitmap = SKBitmap.Decode(Path);
int h = bitmap.Height;
int w = bitmap.Width;
int newWidth = w;
int newHeight = h;
//resize algorythm
if (h > 1080 || w > 1080)
{
int rectHeight = 1080;
int rectWidth = 1080;
//aspect ratio calculation
float W = w;
float H = h;
float aspect = W / H;
//new dimensions by aspect ratio
newWidth = (int)(rectWidth * aspect);
newHeight = (int)(newWidth / aspect);
//if one of the two dimensions exceed the box dimensions
if (newWidth > rectWidth || newHeight > rectHeight)
{
//depending on which of the two exceeds the box dimensions set it as the box dimension and calculate the other one based on the aspect ratio
if (newWidth > newHeight)
{
newWidth = rectWidth;
newHeight = (int)(newWidth / aspect);
}
else
{
newHeight = rectHeight;
newWidth = (int)(newHeight * aspect);
}
}
}
var resizedImage = bitmap.Resize(new SKImageInfo(newWidth, newHeight), SKBitmapResizeMethod.Lanczos3);
var image = resizedImage.Encode(SKEncodedImageFormat.Jpeg, 80);
var path = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var filepath = System.IO.Path.Combine(path, fileName);
string finalPath = filepath;
using (var stream = File.OpenWrite(filepath))
image.SaveTo(stream);
return finalPath;
}
I am extracting info from about 70,000 images and wanted to get their average RGB info. The current code below works, but runs out of memory. So far it just prints out the camera make, model, RGB values and file name. To get started, I found this code, which I adapted:
public static RGBValues AverageRGB(Bitmap bm)
{
BitmapData srcData = bm.LockBits(
new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height),
ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
int stride = srcData.Stride;
IntPtr Scan0 = srcData.Scan0;
long[] totals = new long[] { 0, 0, 0 };
int width = bm.Width;
int height = bm.Height;
unsafe
{
byte* p = (byte*)(void*)Scan0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
for (int color = 0; color < 3; color++)
{
int idx = (y * stride) + x * 4 + color;
totals[color] += p[idx];
}
}
}
}
long avgB = totals[0] / (width * height);
long avgG = totals[1] / (width * height);
long avgR = totals[2] / (width * height);
RGBValues rgb = new RGBValues();
rgb.R = avgR;
rgb.G = avgG;
rgb.B = avgB;
return rgb;
}
public class RGBValues
{
public long R;
public long G;
public long B;
}
I then call it like this:
public MainWindow()
{
string folder = #"F:\Photos";
DirSearch(folder);
int counter = 0;
foreach (var filename in filelist)
{
GetImageInfo(filename);
counter++;
if (counter >= 10)
{
GC.Collect();
GC.WaitForPendingFinalizers();
counter = 0;
}
}
InitializeComponent();
}
private void GetImageInfo(string filename)
{
FileInfo info = new FileInfo(filename);
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Bitmap bmp = new Bitmap(filename);
PropertyItem[] propItems = bmp.PropertyItems;
var temp = AverageRGB(bmp);
string manufacturer = encoding.GetString(propItems[1].Value);
string model = encoding.GetString(propItems[2].Value);
Console.WriteLine("manufacturer: " + manufacturer + ", model: " + model + ", colorinfo: " + temp.R + ", " + temp.G + ", " + temp.B + ", Filename: " + info.Name);
}
public static void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d))
{
filelist.Add(f);
}
DirSearch(d);
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
I threw in some garbage collection efforts, but it still runs out of memory after doing around 150 photos. I thought that C# would automatically discard info it didn't need anymore. Is it because this is using unsafe that it continues to hold on to extra info? What can I do to force it to purge old info?
The image gets distorted while cropping it into various sizes. How do I do this without affecting the image quality? My current result is a distorted blurry image. Please help.
Here is my code:
var common = new Common();
string filesPath = HttpContext.Current.Server.MapPath(Const.directoryPath);
string imageUrl1 = UploadImageToAzure(1123, "\\Configurator\\_trunk\\Content\\TempImages\\eddaec5aa33e4b1593b304674a842874.jpeg, "eddaec5aa33e4b1593b304674a842874_260x190.jpeg", cloudstorage, containerName);
string cropimage260x190 = CropImagewithName(inputStream/*System.Io.Stream*/, 260, 190, cropedImageName);
public string CropImagewithName(Stream stream, int width, int height, string name)
{
int bmpW = 0;
int bmpH = 0;
string filePath = string.Empty;
string imgName = string.Empty;
try
{
{
bmpW = width;
bmpH = height;
int newWidth = bmpW;
int newHeight = bmpH;
imgName = name;
imgName = imgName.Replace("-", "");
filePath = Const.directoryPath + imgName;
this.upBmp = new Bitmap(stream);
this.newBmp = new Bitmap(newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
this.newBmp.SetResolution(300, 300);
int upWidth = this.upBmp.Width;
int upHeight = this.upBmp.Height;
int newX = 0;
int newY = 0;
decimal reDuce;
if (upWidth > upHeight)
{
reDuce = Convert.ToDecimal(newWidth) / Convert.ToDecimal(upWidth);
newHeight = Convert.ToInt32((Convert.ToDecimal(upHeight) * reDuce));
newY = (bmpH - newHeight) / 2;
newX = 0;
}
else if (upWidth < upHeight)
{
reDuce = Convert.ToDecimal(newHeight) / Convert.ToDecimal(upHeight);
newWidth = Convert.ToInt32((Convert.ToDecimal(upWidth) * reDuce));
newX = (bmpW - newWidth) / 2;
newY = 0;
}
else if (upWidth == upHeight) //
{
reDuce = Convert.ToDecimal(newHeight) / Convert.ToDecimal(upHeight);
newWidth = Convert.ToInt32((Convert.ToDecimal(upWidth) * reDuce));
newX = (bmpW - newWidth) / 2;
newY = (bmpH - newHeight) / 2;
}
newGraphic = Graphics.FromImage(newBmp);
this.newGraphic.Clear(Color.White);
this.newGraphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
this.newGraphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
newGraphic.DrawImage(upBmp, newX, newY, newWidth, newHeight);
newBmp.Save(HttpContext.Current.Server.MapPath(filePath), System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
catch (Exception)
{
}
finally
{
this.upBmp.Dispose();
this.newBmp.Dispose();
this.newGraphic.Dispose();
}
return imgName;
}
You are experiencing JPEG compression artifacts, not geometrical distortion. You need to set JPEG compression quality before saving your image. Here is how you can save your image with highest quality (look for 100L in the code below):
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == ImageFormat.Jpeg.Guid)
{
var myEncoder = System.Drawing.Imaging.Encoder.Quality;
var myEncoderParameter = new EncoderParameter(myEncoder, 100L);
var myEncoderParameters = new EncoderParameters(1) { Param = { [0] = myEncoderParameter } };
newBmp.Save(#"C:\qqq\111.jpeg", codec, myEncoderParameters);
break;
}
}
Here is the MSDN article for it: https://msdn.microsoft.com/en-us/library/bb882583(v=vs.110).aspx
how to rotate image through put in angle value in textbox using graphics in asp.net c#?
I take a textbox and image and button.I want to give value in angle in textbox and image will be rotate according to given value.so,i can only doing a simple button_click event ,but it is not proper for textbox.so,give simple code ...
protected void Button2_Click(object sender, EventArgs e)
{
string path = Server.MapPath(Image1.ImageUrl);
////create an image object from the image in that path
System.Drawing.Image img = System.Drawing.Image.FromFile(path);
////rotate the image
img.RotateFlip(RotateFlipType.Rotate90FlipXY);
////save the image out to the file
img.Save(path);
////release image file
img.Dispose();
}
Following code save the rotated image into newfile.png in current project folder path
Try This:
protected void Button2_Click1(object sender, EventArgs e)
{
string path = Server.MapPath(Image1.ImageUrl);
string newpath =Server.MapPath(#"~/filename.png");
////create an image object from the image in that path
System.Drawing.Bitmap img =new System.Drawing.Bitmap(path);
Bitmap map = RotateBitmap(COnvert.ToSingle(textBox1.Text), img);
map.Save(newpath);
////release image file
img.Dispose();
}
public Bitmap RotateBitmap(float Angle, Bitmap bm_in)
{
try
{
float wid = bm_in.Width;
float hgt = bm_in.Height;
Point[] corners = { new Point(0, 0), new Point(int.Parse(wid.ToString()), 0), new Point(0, int.Parse(hgt.ToString())), new Point(int.Parse(wid.ToString()), int.Parse(hgt.ToString())) };
int cx = int.Parse(wid.ToString()) / 2;
int cy = int.Parse(hgt.ToString()) / 2;
long i;
for (i = 0; i <= 3; i++)
{
corners[i].X -= Convert.ToInt32(cx.ToString());
corners[i].Y -= Convert.ToInt32(cy.ToString());
}
float theta = (float)(Angle * Math.PI / 180.0);
float sin_theta = (float)Math.Sin(theta);
float cos_theta = (float)Math.Cos(theta);
float X;
float Y;
for (i = 0; i <= 3; i++)
{
X = corners[i].X;
Y = corners[i].Y;
corners[i].X = (int)(X * cos_theta + Y * sin_theta);
corners[i].Y = (int)(-X * sin_theta + Y * cos_theta);
}
float xmin = corners[0].X;
float ymin = corners[0].Y;
for (i = 1; i <= 3; i++)
{
if (xmin > corners[i].X)
xmin = corners[i].X;
if (ymin > corners[i].Y)
ymin = corners[i].Y;
}
for (i = 0; i <= 3; i++)
{
corners[i].X -= int.Parse(xmin.ToString());
corners[i].Y -= int.Parse(ymin.ToString());
}
Bitmap bm_out = new Bitmap((int)(-2 * xmin), (int)(-2 * ymin));
Graphics gr_out = Graphics.FromImage(bm_out);
// ERROR: Not supported in C#: ReDimStatement
Point[] temp = new Point[3];
if (corners != null)
{
Array.Copy(corners, temp, Math.Min(corners.Length, temp.Length));
}
corners = temp;
gr_out.DrawImage(bm_in, corners);
return bm_out;
}
catch (Exception ex)
{
string s = ex.Message;
return bm_in;
}
}
i am trying to create thumbnails. my path to original folder is: suppose I:\my images**, and i want to generate it to **i:\new images. i got two problem, first problem is that if my images folder contains subfolder then in the new images it should also be in the sub folder not as a parent folder .
second i got an Error.**A generic error occurred in GDI+.
3rd i get this error: Out of memory.**
its a csharp console application
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
at System.Drawing.Image.Save(String filename, ImageFormat format)
at ConsoleApplication1.Program.CreateThumbnail(String[] b, Double wid, Double hght, Boolean Isprint)
public void CreateThumbnail(string[] b, double wid, double hght, bool Isprint)
{
string[] path;
path = new string [64];
path = b;
string saveath = "i:\\check\\a test\\";
for (int i = 0; i < b.Length; i++)
{
DirectoryInfo dir = new DirectoryInfo(path[i]);
string dir1 = dir.ToString();
dir1 = dir1.Substring(dir1.LastIndexOf("\\"));
FileInfo[] files1 = dir.GetFiles();
foreach (FileInfo f in files1)
{
string gh = f.ToString();
try
{
System.Drawing.Image myThumbnail150;
System.Drawing.Image.GetThumbnailImageAbort myCallback = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback);
System.Drawing.Image imagesize = System.Drawing.Image.FromFile(f.FullName);
Bitmap bitmapNew = new Bitmap(imagesize);
double maxWidth = wid;
double maxHeight = hght;
int w = imagesize.Width;
int h = imagesize.Height;
// Longest and shortest dimension
int longestDimension = (w > h) ? w : h;
int shortestDimension = (w < h) ? w : h;
// propotionality
float factor = ((float)longestDimension) / shortestDimension;
// default width is greater than height
double newWidth = maxWidth;
double newHeight = maxWidth / factor;
// if height greater than width recalculate
if (w < h)
{
newWidth = maxHeight / factor;
newHeight = maxHeight;
}
myThumbnail150 = bitmapNew.GetThumbnailImage((int)newWidth, (int)newHeight, myCallback, IntPtr.Zero);
string ext = Path.GetExtension(f.Name);
if (!Directory.Exists(saveath + dir1))
{
Directory.CreateDirectory(saveath + dir1);
myThumbnail150.Save(saveath + dir1 + "\\" + f.Name.Replace(ext, ".Jpeg"), System.Drawing.Imaging.ImageFormat.Jpeg);
}
else if(Directory.Exists(saveath+dir1))
{
myThumbnail150.Save(saveath + dir1+" \\"+ f.Name.Replace(ext, ".Jpeg"), System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
catch (Exception ex)
{
Console.WriteLine("something went wrong" + ex.ToString());
}
}
}
}
I have just refactored a bit the code and now it works (on my machine):
private static void CreateThumbnail(string[] b, double wid, double hght, bool Isprint)
{
string saveAt = "D:\\check";
foreach (string path in b)
{
var directory = new DirectoryInfo(path);
string outputPath = Path.Combine(saveAt, directory.Name);
foreach (FileInfo f in directory.GetFiles("*.*", SearchOption.AllDirectories))
{
if (f.DirectoryName != directory.FullName)
{
outputPath = Path.Combine(saveAt, directory.Name, f.Directory.Name);
}
if (!Directory.Exists(outputPath))
{
Directory.CreateDirectory(outputPath);
}
using (Image imagesize = Image.FromFile(f.FullName))
using (Bitmap bitmapNew = new Bitmap(imagesize))
{
double maxWidth = wid;
double maxHeight = hght;
int w = imagesize.Width;
int h = imagesize.Height;
// Longest and shortest dimension
int longestDimension = (w > h) ? w : h;
int shortestDimension = (w < h) ? w : h;
// propotionality
float factor = ((float)longestDimension) / shortestDimension;
// default width is greater than height
double newWidth = maxWidth;
double newHeight = maxWidth / factor;
// if height greater than width recalculate
if (w < h)
{
newWidth = maxHeight / factor;
newHeight = maxHeight;
}
string fileName = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(f.Name) + ".jpeg");
bitmapNew.GetThumbnailImage((int)newWidth, (int)newHeight, () => false, IntPtr.Zero)
.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
}
I have to say few things about your old code:
use foreach when possible;
avoid the first three lines, they are useless;
avoid unused variables;
keep your code as clean as possible;
About the "GDI+ generic error" and the "Out Of Memory" exceptions, you should take a look at that link on SO: What is the "best" way to create a thumbnail using ASP.NET?
You must use the C# using statement to make sure unmanaged GDI+ resources underneath the .NET surface are freed as quickly as possible to avoid out of memory errors.
The GDI+ generic can happen if the image cannot be converted for example.