this is my model class
public class News: Public
{
[Key]
public int NewsID { get; set; }
[Required]
[StringLength(100, MinimumLength = 2)]
public string Title { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime NewsDate { get; set; }
[Required]
[DataType(DataType.MultilineText)]
[StringLength(1000, MinimumLength = 2)]
public string NewsTXT { get; set; }
public byte[] NewsPic { get; set; }
}
I use it in create controller for save picture in Byte[] to database
using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
{
news.NewsPic = binaryReader.ReadBytes(Request.Files[0].ContentLength);
}
I want make thumb of image in my controller and show in view and don't want save thumb anywhere.
i want do something like this, but image fetch from database
Thumbnail Controller
public ActionResult Thumbnail(int width, int height){
var imageFile = Path.Combine(Server.MapPath("~/app_data"), "test.png");
using (var srcImage = Image.FromFile(imageFile))
using (var newImage = new Bitmap(width, height))
using (var graphics = Graphics.FromImage(newImage))
using (var stream = new MemoryStream())
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(srcImage, new Rectangle(0, 0, width, height));
newImage.Save(stream, ImageFormat.Png);
return File(stream.ToArray(), "image/png");
}
}
in view
<img src="#Url.Action("Thumbnail", "SomeController", new { width = 100, height = 50 })" alt="thumb" />
my version of this code is, in thumb controller is:
public ActionResult Thumbnail(int width, int height,int id)
{
// TODO: the filename could be passed as argument of course
var photo = db.News.Find(id).NewsPic;
string imageBase64 = Convert.ToBase64String(photo);
var imageSrc = string.Format("data:image/jpg;base64,{0}", imageBase64);
using (var srcImage = Image.FromFile(imageSrc))
using (var newImage = new Bitmap(width, height))
using (var graphics = Graphics.FromImage(newImage))
using (var stream = new MemoryStream())
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(srcImage, new Rectangle(0, 0, width, height));
newImage.Save(stream, ImageFormat.Png);
return File(stream.ToArray(), "image/png");
}
}
my version, in view:
<img src="#Url.Action("Thumbnail", "News", new { width = 100, height = 50,id=Model.NewsID })" alt="thumb" />
but dosent work
public ActionResult Thumbnail(int width, int height, int id){
// TODO: the filename could be passed as argument of course
var photo = db.News.Find(id).NewsPic;
var base64 = Convert.ToBase64String(photo);
// Convert Base64 String to byte[]
byte[] imageBytes = Convert.FromBase64String(base64);
MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
// Convert byte[] to Image
ms.Write(imageBytes, 0, imageBytes.Length);
Image image = Image.FromStream(ms, true);
using (var newImage = new Bitmap(width, height))
using (var graphics = Graphics.FromImage(newImage))
using (var stream = new MemoryStream())
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(image, new Rectangle(0, 0, width, height));
newImage.Save(stream, ImageFormat.Png);
return File(stream.ToArray(), "image/png");
}
}
Related
I have an ASP.NET Core 3.1 WebAPI that is responsible for providing other apps I have with images. I am trying to improve the performance of my apps. One of the feedback I get from running PageSpeed Insights test is to Serve images in next-gen formats.
All of the images that my WebAPI server are in JPEG format. I don't know much about image compression or image-formats, but I would like to evaluate the results from converting JPEG images to WebP as study show that WebP leads to better results.
I use the following ImageProcessor class to save uploaded images to my WebAPI.
public class ImageProcessor
{
public Image GetResizedImage(Stream stream, int newWidth, out ImageFormat imageFormat)
{
Image sourceImage = Image.FromStream(stream);
SizeF thumbSize = GetNewSize(sourceImage, newWidth);
imageFormat = sourceImage.RawFormat;
return ResizeImage(sourceImage, (int)thumbSize.Width, (int)thumbSize.Height);
}
protected SizeF GetNewSize(Image img, int newMaxWidth)
{
var size = new SizeF
{
Width = newMaxWidth,
Height = (newMaxWidth * img.Height) / img.Width
};
return size;
}
protected Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
var xRes = Math.Max(Math.Min(image.HorizontalResolution, 96), 72);
var yRes = Math.Max(Math.Min(image.VerticalResolution, 96), 72);
destImage.SetResolution(xRes, yRes);
using (Graphics graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (ImageAttributes wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
}
Here is how I call the ImageProcessor class to store images on disk from the controller
public async Task<IActionResult> Store(IFormFile file)
{
if(!ModelState.IsValid)
{
return Problem("Invalid model!");
}
// Process Image
Image image = GetResizedImage(file.OpenReadStream(), 1024, out ImageFormat imageFormat);
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, imageFormat);
memoryStream.Seek(0, SeekOrigin.Begin);
// Store it on disk
string fullPath = "full path to the new image";
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
using FileStream cacheWriter = new FileStream(fullPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write, 4096, true);
await memoryStream.CopyToAsync(cacheWriter);
return Ok();
}
Question
How can I store the image in a WebP format using .Net Core?
If I were you I would look at installing an instance of Thumbor or using Cloudinary to generate your webp files.
Then you can use JS to conditionally load the correct file.
The ImageHandler class is responsible for converting the image to jpg and 60x60 size, then it converts it to Base64. The first Image is fine but when I try to proccess another image in the same run it crashes.
class ImageHandler
{
public static void convertToFormat(string filename)
{
var image = Image.FromFile(#filename);
var bitmap = ResizeImage(image, Globals.ImageSize, Globals.ImageSize);
bitmap.Save(Globals.PRED_PATH, ImageFormat.Jpeg);
}
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
public static string ConvertImageToBase64String()
{
Image image = Image.FromFile(Globals.PRED_PATH);
var imageStream = new MemoryStream();
image.Save(imageStream, ImageFormat.Jpeg);
imageStream.Position = 0;
var imageBytes = imageStream.ToArray();
return Convert.ToBase64String(imageBytes);
}
}
Function Call:
ImageHandler.convertToFormat(FilePath);
string encodedImage = ImageHandler.ConvertImageToBase64String();
As a quick fix you can add image.Dispose(); after image.Save(imageStream, ImageFormat.Jpeg); in the method ConvertImageToBase64String to make it work.
However I would recommend that you add using statements to convertToFormat and ConvertImageToBase64String to properly free the resources after use.
public static void convertToFormat(string filename)
{
using (var image = Image.FromFile(#filename))
{
using (var bitmap = ResizeImage(image, Globals.ImageSize, Globals.ImageSize))
{
bitmap.Save(Globals.PRED_PATH, ImageFormat.Jpeg);
}
}
}
public static string ConvertImageToBase64String()
{
using (var image = Image.FromFile(Globals.PRED_PATH))
{
using (var imageStream = new MemoryStream())
{
image.Save(imageStream, ImageFormat.Jpeg);
imageStream.Position = 0;
var imageBytes = imageStream.ToArray();
return Convert.ToBase64String(imageBytes);
}
}
}
I need to change the size of the photo and save it to a new size when the user selects a photo for the upload, before saving the photo.
i using this code but it not save with new size . whats the problem ?
public async Task<IActionResult> UploadNewsPic()
{
var file = Request.Form.Files[0];
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))
{
if (file.IsImage())
{
await file.ResizeImage(3, 3);
file.CopyTo(stream);
}
}
}
return Ok();
}
catch (Exception e)
{
return BadRequest();
}
}
and this is Resize Extention :
public async static Task<Image> ResizeImage(this IFormFile file, int width, int height)
{
using (var memoryStream = new MemoryStream())
{
await file.CopyToAsync(memoryStream);
using (var img = Image.FromStream(memoryStream))
{
return img.Resize(width, height);
}
}
}
public static Image Resize(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;
}
You need to save the result from ResizeImage to the stream. Right now you are just copying the original file.
var img = await file.ResizeImage(3, 3);
img.Save(stream, SomeFormat);
Your ResizeImage() function return a resized image, it doesn't edit the image itself, so you must set it to a variable.
if (file.IsImage())
{
Image imageResized = await file.ResizeImage(3, 3);
// ...
}
I am trying to generate a thumbnail from the base64string. I am storing the image in a table and am trying to generate a thumbnail from the base64string being stored.
I am able to generate the thumbnail if I provide a path to the image, but that will not work in my case.
This is the working solution of generating a thumbnail from an image path:
protected void GenerateThumbnail(object sender, EventArgs e)
{
string path = Server.MapPath("../src/img/myImage.png");
System.Drawing.Image image = System.Drawing.Image.FromFile(path);
using (System.Drawing.Image thumbnail = image.GetThumbnailImage(100, 100, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero))
{
using (MemoryStream memoryStream = new MemoryStream())
{
thumbnail.Save(memoryStream, ImageFormat.Png);
Byte[] bytes = new Byte[memoryStream.Length];
memoryStream.Position = 0;
memoryStream.Read(bytes, 0, (int)bytes.Length);
string base64String = Convert.ToBase64String(bytes, 0, bytes.Length);
Image2.ImageUrl = "data:image/png;base64," + base64String;
Image2.Visible = true;
}
}
}
Can anyone provide any advice on how to use the base64string instead of the image path the generate thumbnail?
Assuming, b64 is the base64 string, you can convert it to a byte array and use that to construct the starting image.
byte[] bytes = Convert.FromBase64String(b64);
using (MemoryStream ms = new MemoryStream(bytes))
{
Bitmap thumb = new Bitmap(100, 100);
using (Image bmp = Image.FromStream(ms))
{
using (Graphics g = Graphics.FromImage(thumb))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawImage(bmp, 0, 0, 100, 100);
}
}
// a picturebox to show/test the result
picOut.Image = thumb;
}
Be sure to dispose of the thumb when you are done with it.
Mixed few tricks found online. (one from #Plutonix)
string ThumbNailBase64 = ResizeBase64Image(YourBase64String,200, 300);
base64 Input => resize => base64 Output
You get the desired thumbnail with auto aspect ratio.
public static string ResizeBase64Image(string Base64String, int desiredWidth, int desiredHeight)
{
Base64String = Base64String.Replace("data:image/png;base64,", "");
// Convert Base64 String to byte[]
byte[] imageBytes = Convert.FromBase64String(Base64String);
using (MemoryStream ms = new MemoryStream(imageBytes))
{
// Convert byte[] to Image
ms.Write(imageBytes, 0, imageBytes.Length);
Image image = Image.FromStream(ms, true);
var imag = ScaleImage(image, desiredWidth, desiredHeight);
using (MemoryStream ms1 = new MemoryStream())
{
//First Convert Image to byte[]
imag.Save(ms1, imag.RawFormat);
byte[] imageBytes1 = ms1.ToArray();
//Then Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes1);
return "data:image/png;base64,"+base64String;
}
}
}
public static Image ScaleImage(Image image, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / image.Width;
var ratioY = (double)maxHeight / image.Height;
var ratio = Math.Min(ratioX, ratioY);
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
using (var graphics = Graphics.FromImage(newImage))
graphics.DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
I have a simple web application (ASP.NET MVC 5 C#) which allows users to upload several files (images actually).
Currently it works well, the images are stored into the data base and I can read them later.
But I want to resize the images before saving them into the db, since the user can upload extremely big images.
Here is my controller:
public ActionResult Create(Annonce annonce, IEnumerable<HttpPostedFileBase> photos)
{
if (ModelState.IsValid)
{
// Read each uploaded files and add if into the collection
foreach (HttpPostedFileBase fichier in photos)
{
if (fichier != null && fichier.ContentLength > 0)
{
// Making a new object
var photo = new Photo
{
FileName = System.IO.Path.GetFileName(fichier.FileName),
ContentType = fichier.ContentType
};
using (var reader = new System.IO.BinaryReader(fichier.InputStream))
{
photo.Content = reader.ReadBytes(fichier.ContentLength);
}
// Add the current image to the collection
annonce.Photos.Add(photo);
}
}
db.Annonces.Add(annonce);
db.SaveChanges();
return RedirectToAction("Details", new { id = annonce.ID });
}
return View(annonce);
}
How can I resize my images and still be able to save them into the db?
Is-it even possible?
Thanks!
This code will perform a high quality resizing.(means you wont lose very much)
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width,image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
Call ResizeImage() and assign it to a bitmap which you'll insert into your database.goodluck
you can convert it to byte array and than store it in your db as byte type
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
you can do the same but inverted to get it out and display it as image from the DB:
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
You also approach to ImageResizer as link below:
http://www.c-sharpcorner.com/article/image-resize-in-asp-net-mvc-using-image-resizer/