C# Image Resize from Stream - c#

I'm trying to resize an image from stream. Getting the error
Value cannot be null.Parameter name: encoder
on the line
System.Drawing.Bitmap fullSizeBitmap = new
System.Drawing.Bitmap(fullsizeImage, new System.Drawing.Size(width,
image_height));
How do I add an encoder here? and I need it to be from the original image
public static FileProperty UploadImage(IFormFile file, string folderPath, string fileName, FileNote note, int image_height)
{
FileProperty property = new FileProperty();
if (file.Length > 0)
{
MemoryStream ms = new MemoryStream();
file.CopyTo(ms);
var fileBytes = ms.ToArray();
MemoryStream inputMemoryStream = new MemoryStream(fileBytes);
System.Drawing.Image fullsizeImage = System.Drawing.Image.FromStream(inputMemoryStream);
int width = (image_height / fullsizeImage.Height) * fullsizeImage.Width;
System.Drawing.Bitmap fullSizeBitmap = new System.Drawing.Bitmap(fullsizeImage, new System.Drawing.Size(width, image_height));
using (var stream = new MemoryStream())
{
fullSizeBitmap.Save(stream, fullSizeBitmap.RawFormat);
using (MemoryStream memoryStream = new MemoryStream(stream.ToArray()))
{
UploadFromStreamAsync(memoryStream);
}
}
property.FileName = fileName;
property.FileExtention = Path.GetExtension(fileName);
property.FileSize = file.Length;
property.FileType = file.ContentType;
property.FileNote = note.ToString();
}
return property;
}

Just use file.OpenReadStream() to read and resize the file, then save the resized bitmap to the MemoryStream and upload.
And instead of using bitmap.RawFormat you can get the uploaded image format using a method as below:
if (file.Length > 0)
{
using(var stream = file.OpenReadStream())
{
var image = Image.FromStream(stream);
int width = (image_height / fullsizeImage.Height) * fullsizeImage.Width;
Bitmap fullSizeBitmap = new Bitmap(fullsizeImage, new Size(width, image_height));
var imgFormat = GetImageFormat(file.FileName);
using(var ms = new MemoryStream())
{
fullSizeBitmap.Save(ms, imgFormat);
UploadFromStreamAsync(ms);
}
}
}
The method to get the image format by file extension:
public ImageFormat GetImageFormat(string fileName)
{
var dotIndex = fileName.LastIndexOf('.');
var ext = fileName.Substring(dotIndex, fileName.Length - dotIndex).ToLower();
switch (ext)
{
case ".bmp": return ImageFormat.Bmp;
case ".emf": return ImageFormat.Emf;
case ".exif": return ImageFormat.Exif;
case ".gif": return ImageFormat.Gif;
case ".icon": return ImageFormat.Icon;
case ".Jpg": return ImageFormat.Jpeg;
case ".Jpeg": return ImageFormat.Jpeg;
case ".png": return ImageFormat.Png;
case ".tiff": return ImageFormat.Tiff;
case ".Wmf": return ImageFormat.Wmf;
default: throw new InvalidDataException("Format not supported");
}
}
If you still need to get the uploaded image encoder info use the below method:
// ext: image extension
using System.Drawing.Imaging;
public static ImageCodecInfo GetEncoderInfo(string ext)
{
return ImageCodecInfo.GetImageEncoders().SingleOrDefault(x => x.FilenameExtension.ToLower().Contains(ext));
}

Related

Selenium screenshot to memory [duplicate]

I used
private BitmapImage byteArrayToImage(byte[] byteArrayIn)
{
try
{
MemoryStream stream = new MemoryStream();
stream.Write(byteArrayIn, 0, byteArrayIn.Length);
stream.Position = 0;
System.Drawing.Image img = System.Drawing.Image.FromStream(stream);
BitmapImage returnImage = new BitmapImage();
returnImage.BeginInit();
MemoryStream ms = new MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
returnImage.StreamSource = ms;
returnImage.EndInit();
return returnImage;
}
catch (Exception ex)
{
throw ex;
}
return null;
}
This method in my application to convert byte array to an image. But it throws "Parameter is not valid" exception.. why it is happening..? Is there any alternative method.??
Hi this should be working:
private static BitmapImage LoadImage(byte[] imageData)
{
if (imageData == null || imageData.Length == 0) return null;
var image = new BitmapImage();
using (var mem = new MemoryStream(imageData))
{
mem.Position = 0;
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = null;
image.StreamSource = mem;
image.EndInit();
}
image.Freeze();
return image;
}
If you have array like this:
byte[] byteArrayIn = new byte[] {255, 128, 0, 200};
And you want something like:
Use:
BitmapSource bitmapSource = BitmapSource.Create(2, 2, 300, 300,PixelFormats.Indexed8, BitmapPalettes.Gray256, byteArrayIn, 2);
Image.Source = bitmapSource;
In xaml:
<Image RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.EdgeMode="Aliased" x:Name="Image"></Image>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnBrowse_Click(object sender, RoutedEventArgs e)
{
var of = new OpenFileDialog();
of.Filter = "Image files (*.png;*.jpeg)|*.png;*.jpeg|All files (*.*)|*.*";
var res = of.ShowDialog();
if (res.HasValue)
{
imgPreview.Source = new BitmapImage(new Uri(of.FileName));
var t = Utils.ConvertBitmapSourceToByteArray(imgPreview.Source as BitmapSource);
var d = Utils.ConvertBitmapSourceToByteArray(new BitmapImage(new Uri(of.FileName)));
var s = Utils.ConvertBitmapSourceToByteArray(imgPreview.Source);
var enc = Utils.ConvertBitmapSourceToByteArray(new PngBitmapEncoder(), imgPreview.Source);
//imgPreview2.Source = Utils.ConvertByteArrayToBitmapImage(enc);
imgPreview2.Source = Utils.ConvertByteArrayToBitmapImage2(enc);
//var i = 0;
}
else
{
MessageBox.Show("Select a currect file...");
}
}
}
/util.cs/
public class Utils
{
public static byte[] ConvertBitmapSourceToByteArray(BitmapEncoder encoder, ImageSource imageSource)
{
byte[] bytes = null;
var bitmapSource = imageSource as BitmapSource;
if (bitmapSource != null)
{
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
using (var stream = new MemoryStream())
{
encoder.Save(stream);
bytes = stream.ToArray();
}
}
return bytes;
}
public static byte[] ConvertBitmapSourceToByteArray(BitmapSource image)
{
byte[] data;
BitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
return data;
}
public static byte[] ConvertBitmapSourceToByteArray(ImageSource imageSource)
{
var image = imageSource as BitmapSource;
byte[] data;
BitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
return data;
}
public static byte[] ConvertBitmapSourceToByteArray(Uri uri)
{
var image = new BitmapImage(uri);
byte[] data;
BitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
return data;
}
public static byte[] ConvertBitmapSourceToByteArray(string filepath)
{
var image = new BitmapImage(new Uri(filepath));
byte[] data;
BitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
return data;
}
public static BitmapImage ConvertByteArrayToBitmapImage(Byte[] bytes)
{
var stream = new MemoryStream(bytes);
stream.Seek(0, SeekOrigin.Begin);
var image = new BitmapImage();
image.BeginInit();
image.StreamSource = stream;
image.EndInit();
return image;
}
}

Resize IFormFile before Upload to Blob Storage

I'm currently uploading a list of images to azure blob storage via the below function (path is then stored in DB).
This is all working fine however if the images are larger than a certain resolution, I want to resize to hopefully cut down the image file size (this would obviously be.
I've found examples of cropping an 'Image' however as this is a list of IFormFile (from an input type=upload) it doesn't seem to work the same. I've tried converting the IFormFile to an image and then resizing the image, however I'm then unable to convert back to IFormFile.
Any help or pointers would be great. Thanks.
public async Task UploadImagesAsync(IFormFileCollection files, int VehicleID)
{
var connectionString = _configuration.GetConnectionString("AzureStorageAccount");
var container = _uploadService.GetBlobContainer(connectionString);
foreach (var file in files)
{
// Resize file here
// parse the content disposition header
var contentDisposition = ContentDispositionHeaderValue.Parse(file.ContentDisposition);
// grab file name
var fileName = "Vehicles/" + VehicleID + "/" + contentDisposition.FileName.Trim('"');
// get reference
var blockBlob = container.GetBlockBlobReference(fileName);
// upload
await blockBlob.UploadFromStreamAsync(file.OpenReadStream());
According to my research, we can use SixLabors to resize the image in the application.
For example
public async Task UploadImagesAsync(IFormFileCollection files, int VehicleID)
{
foreach (var file in files)
{
var extension = Path.GetExtension(file.FileName);
var encoder = GetEncoder(extension);
if (encoder != null)
{
using (var output = new MemoryStream())
using (Image<Rgba32> image = Image.Load(input))
{
var divisor = image.Width / thumbnailWidth;
var height = Convert.ToInt32(Math.Round((decimal)(image.Height / divisor)));
image.Mutate(x => x.Resize(thumbnailWidth, height));
image.Save(output, encoder);
output.Position = 0;
await blockBlob.UploadFromStreamAsync(output);
}
}
}
}
private static IImageEncoder GetEncoder(string extension)
{
IImageEncoder encoder = null;
extension = extension.Replace(".", "");
var isSupported = Regex.IsMatch(extension, "gif|png|jpe?g", RegexOptions.IgnoreCase);
if (isSupported)
{
switch (extension)
{
case "png":
encoder = new PngEncoder();
break;
case "jpg":
encoder = new JpegEncoder();
break;
case "jpeg":
encoder = new JpegEncoder();
break;
case "gif":
encoder = new GifEncoder();
break;
default:
break;
}
}

Convert IFormFile to Image in Asp Core

i need to resize file upload if file is image .
i write the extention for resize that :
public static Image ResizeImage(this Image image, int width, int height)
{
var res = new Bitmap(width, height);
using (var graphic = Graphics.FromImage(res))
{
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(image, 0, 0, width, height);
}
return res;
}
and this is Upload Action :
[HttpPost("UploadNewsPic"), DisableRequestSizeLimit]
public IActionResult UploadNewsPic(IFormFile file)
{
if (file.IsImage())
{
}
try
{
if (file.Length > 0)
{
string fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
string fullPath = Path.Combine(_applicationRoot.UploadNewPath(), file.Name);
using (var stream = new FileStream(fullPath, FileMode.Create))
{
file.CopyTo(stream);
}
}
return Ok();
}
catch (Exception e)
{
return BadRequest();
}
}
now my problem is here => my extention just work on type of Image file but type of this file is IFormFile . how can i convert the IFormFile to Image type ?
You should use the Image.FromStream() method to read the stream as an Image:
public async Task<IActionResult> FileUpload(IFormFile file)
{
if (file == null || file.Length == 0)
{
return BadRequest();
}
using (var memoryStream = new MemoryStream())
{
await file.CopyToAsync(memoryStream);
using (var img = Image.FromStream(memoryStream))
{
// TODO: ResizeImage(img, 100, 100);
}
}
}
You need to open file using OpenReadStream and convert into image format. And pass the same to your extension method.
FileDetails fileDetails;
using (var reader = new StreamReader(file.OpenReadStream()))
{
var fileContent = reader.ReadToEnd();
var parsedContentDisposition = ContentDispositionHeaderValue.Parse(file.ContentDisposition);
fileDetails = new FileDetails
{
Filename = parsedContentDisposition.FileName,
Content = fileContent,
ContentType=file.ContentType
};
}

I get an error "Parameter is not valid" when trying to convert byte to image

This is my code:
string photo = "somedata";
byte[] byt = System.Text.Encoding.UTF8.GetBytes(photo);
string strModified = Convert.ToBase64String(byt);
byte[] photoData = Convert.FromBase64String(strModified);
Image img = cnvrtToImg(photoData);
public Image cnvrtToImg(byte[] byteArrayIn)
{
using (MemoryStream mStream = new MemoryStream(byteArrayIn))
{
return Image.FromStream(mStream);
}
}
When the method cnvrtToImg is invoked, I get an error
Parameter is not valid
Please give me a solution
I think that System.Text.Encoding.UTF8 is not for image data, it is for text, not binary data. UTF8 just can't do some binary sequence. Base64 is the choice if you need convert binary to text.
I test with this, and confirm the cnvrtToImg is correct:
class Program
{
public static Image cnvrtToImg(byte[] byteArrayIn)
{
using (MemoryStream mStream = new MemoryStream(byteArrayIn))
{
return Image.FromStream(mStream);
}
}
static void Main(string[] args)
{
using (var file = File.Open(#"D:\0.jpg", FileMode.Open))
{
var buffer = new byte[file.Length];
file.Read(buffer, 0, (int) file.Length);
cnvrtToImg(buffer);
}
}
}
//finish

Better TIF to PNG conversion with Bitmap.Save()?

Update: Tried SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; and it's noticeable at full zoom, but it doesn't solve the problem, the problem is just anti-aliased now...
The TIFs are scanned documents, and contain things like lines for tables and text.
Current approach:
using System.Drawing;
using System.Drawing.Imaging;
var image = Image.FromFile(tifFileName);
Image bitmap = new Bitmap(image, (int)(image.Width), (int)(image.Height));
var imageFinal = new Bitmap(image.Width, image.Height);
var graphic = Graphics.FromImage(imageFinal);
graphic.DrawImage(image, 0, 0, image.Width, image.Height);
using(var imgStream = new MemoryStream())
{
imageFinal.Save(imgStream, ImageFormat.Png);
return new MemoryStream(imgStream.GetBuffer());
}
But, it ends up looking like garbage, for example any kind of slightly slanted line has a hint of a stair step, and other fine elements such as text look rough. Especially in comparison to using GIMP to save a TIF as a PNG, which looks great.
So, is there something I can add to make this work better? Or am I going to have to find another approach entirely?
My immediate impression is that you're going to too much trouble, since you aren't resizing:
var image = Image.FromFile(#"C:\Sample.tiff");
image.Save(#"C:\Sample.png", ImageFormat.Png);
If using the Image type doesn't solve your aliasing problems, try picking your encoder manually:
#region Using Directives
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
#endregion
namespace TiffToBitmap
{
internal class Program
{
private static void Main()
{
// Just save the image.
SaveImage(#"C:\Sample1.png", "image/tiff");
// Get a byte array from the converted image.
var imageBytes = GetBytes("image/tiff");
// Save it for easy comparison.
File.WriteAllBytes(#"C:\Sample2.png", imageBytes);
}
private static byte[] GetBytes(string mimeType)
{
var image = Image.FromFile(#"C:\Sample.tiff");
var encoders = ImageCodecInfo.GetImageEncoders();
var imageCodecInfo = encoders.FirstOrDefault(encoder => encoder.MimeType == mimeType);
if (imageCodecInfo == null)
{
return null;
}
using (var memoryStream = new MemoryStream())
{
var imageEncoderParams = new EncoderParameters(1);
imageEncoderParams.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
image.Save(memoryStream, imageCodecInfo, imageEncoderParams);
return memoryStream.GetBuffer();
}
}
private static void SaveImage(string path, string mimeType)
{
var image = Image.FromFile(#"C:\Sample.tiff");
var encoders = ImageCodecInfo.GetImageEncoders();
var imageCodecInfo = encoders.FirstOrDefault(encoder => encoder.MimeType == mimeType);
if (imageCodecInfo == null)
{
return;
}
var imageEncoderParams = new EncoderParameters(1);
imageEncoderParams.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
image.Save(path, imageCodecInfo, imageEncoderParams);
}
}
}
Here is my realization of image/tiff type conversion:
Convertion block:
/// <summary>
/// Convert Tiff image to another mime-type
/// </summary>
/// <param name="tiffImage">Source Tiff file</param>
/// <param name="mimeType">Desired result mime-type</param>
/// <returns>Converted image</returns>
public Bitmap ConvertTiffToBitmap(Image tiffImage, string mimeType)
{
var imageCodecInfo = ImageCodecInfo.GetImageEncoders().First(encoder => encoder.MimeType == MimeType.Tiff);
using (var memoryStream = new MemoryStream())
{
// Setting encode params
var imageEncoderParams = new EncoderParameters(1)
{
Param = {[0] = new EncoderParameter(Encoder.Quality, 100L)}
};
tiffImage.Save(memoryStream, imageCodecInfo, imageEncoderParams);
var converter = new ImageConverter();
// Reading stream data to new image
var tempTiffImage = (Image)converter.ConvertFrom(memoryStream.GetBuffer());
// Setting new result mime-type
imageCodecInfo = ImageCodecInfo.GetImageEncoders().First(encoder => encoder.MimeType == mimeType);
tempTiffImage?.Save(memoryStream, imageCodecInfo, imageEncoderParams);
return new Bitmap(Image.FromStream(memoryStream, true));
}
}
public static class MimeType
{
public const string Bmp = "image/bmp";
public const string Gif = "image/gif";
public const string Jpeg = "image/jpeg";
public const string Png = "image/png";
public const string Tiff = "image/tiff";
}
Usage:
var sourceImg = Image.FromFile(#"C:\MyImage.tif", true);
var codec = ImageCodecInfo.GetImageDecoders().First(c => c.FormatID == sourceImg.RawFormat.Guid);
if (codec.MimeType == MimeType.Tiff)
{
sourceImg = ConvertTiffToBitmap(sourceImg, MimeType.Jpeg);
}
Hope, it could be usefull

Categories

Resources