How to resize images to display from database - c#

I am doing a small project where I have to display all images from database to Listview.
I am passing image id,width,and height as querystring parameter.
<asp:Image ID="Image1" runat="server" ImageUrl='<%#"~/Handler/ImageHandler.ashx?ImgHeight=150&ImgWidth=200&ImgID="+Eval("Image_ID")%>' Height="150px" Width="200px"/>
public void ProcessRequest (HttpContext context)
{
string imgwidth = context.Request.QueryString["ImgWidth"];
string imgheight = context.Request.QueryString["ImgHeight"];
string imageid = context.Request.QueryString["ImgID"];
if (imgwidth != string.Empty && imgheight != string.Empty && (imgwidth != null && imgheight != null))
{
if (!System.Web.UI.WebControls.Unit.Parse(imgwidth).IsEmpty && !System.Web.UI.WebControls.Unit.Parse(imgheight).IsEmpty)
{
//create unit object for height and width. This is to convert parameter passed in differen unit like pixel, inch into generic unit.
System.Web.UI.WebControls.Unit widthUnit=System.Web.UI.WebControls.Unit.Parse(imgwidth);
System.Web.UI.WebControls.Unit heightUnit = System.Web.UI.WebControls.Unit.Parse(imgheight);
//AFTER THIS ???
}
}
}
when I display image directly from database some images get stretch and doesn't look good, this is because the image size is large. So I need to display the images just for thumbsnail in image gallery.

You could use GetThumbnailImage Method
refer the code
public Void GenerateImage(int iWidth,int iHeight,byte[] ImageBytes)
{
System.Drawing.Image image = byteArrayToImage(ImageBytes)
// create the actual thumbnail image
System.Drawing.Image thumbnailImage = image.GetThumbnailImage(iWidth, iHeight, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
// make a memory stream to work with the image bytes
MemoryStream imageStream = new MemoryStream();
// put the image into the memory stream
thumbnailImage.Save(imageStream, System.Drawing.Imaging.Imageformat.Jpeg);
// make byte array the same size as the image
byte[] imageContent = new Byte[imageStream.Length];
// rewind the memory stream
imageStream.Position = 0;
// load the byte array with the image
imageStream.Read(imageContent, 0, (int)imageStream.Length);
// return byte array to caller with image type
Response.ContentType = "image/jpeg";
Response.BinaryWrite(imageContent);
}
public bool ThumbnailCallback()
{
return true;
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}

You could use this code to give the image a new size, while preserving the aspect ratio:
public static Image ResizeCanvas(Image original, Size newSize, Color background)
{
int xStart = (newSize.Width / 2) - (original.Width / 2);
int yStart = (newSize.Height / 2) - (original.Height / 2);
// Create blank canvas
Bitmap resizedImg = new Bitmap(newSize.Width, newSize.Height);
Graphics gfx = Graphics.FromImage(resizedImg);
// Fill canvas
gfx.FillRectangle(new SolidBrush(background), new Rectangle(new Point(0, 0), newSize));
gfx.DrawImage(original, xStart, yStart, original.Width, original.Height);
return resizedImg;
}

Related

How to crop a captured screenshot?

Capturing a screen shot is quite easy but cropping is a different story, or at least appears so. We are attempting to emulate the solution here in Xamarin using SkiaSharp (System.Drawing not supported in Xamarin).
Currently we are able to capture the screenshot and return the image BUT if we crop our image the image returned is all black.
How do we crop a captured screenshot correctly?
NOTE*: image = image.Subset(rec); under the "crop image" section is how we are trying to crop.
iOS screenshot
public byte[] Capture()
{
var capture = UIScreen.MainScreen.Capture();
using (NSData data = capture.AsPNG())
{
var bytes = new byte[data.Length];
Marshal.Copy(data.Bytes, bytes, 0, Convert.ToInt32(data.Length));
return bytes;
}
}
Droid screenshot
public byte[] Capture()
{
var rootView = context.Window.DecorView.RootView;
using (var screenshot = Bitmap.CreateBitmap(
rootView.Width,
rootView.Height,
Bitmap.Config.Argb8888))
{
var canvas = new Canvas(screenshot);
rootView.Draw(canvas);
using (var stream = new MemoryStream())
{
screenshot.Compress(Bitmap.CompressFormat.Png, 90, stream);
return stream.ToArray();
}
}
}
Attempting to crop captured screenshot
// Use this function to crop a screen shot to a specific element.
public byte[] test(byte[] screenshotData, View element)
{
// locate IntPtr to byte[] of uncropped screenshot
GCHandle gch = GCHandle.Alloc(screenshotData, GCHandleType.Pinned);
IntPtr addr = gch.AddrOfPinnedObject();
// assign initial bounds
SKImageInfo info = new SKImageInfo((int)App.Current.MainPage.Width,
(int)App.Current.MainPage.Height);
// create initial pixel map
using SKPixmap pixmap = new SKPixmap(info, addr);
// Release
gch.Free();
// create bitmap
using SKBitmap bitmap = new SKBitmap();
// assign pixel data
bitmap.InstallPixels(pixmap);
// create surface
using SKSurface surface = SKSurface.Create(info);
// create a canvas for drawing
using SKCanvas canvas = surface.Canvas;
// draw
canvas.DrawBitmap(bitmap, info.Rect);
// get an image subset to save
SKImage image = surface.Snapshot();
SKRectI rec = new SKRectI((int)element.Bounds.Left, (int)element.Bounds.Top,
(int)element.Bounds.Right, (int)element.Bounds.Bottom);
// crop image
image = image.Subset(rec);
byte[] bytes = SKBitmap.FromImage(image).Bytes;
image.Dispose();
return bytes;
}
EDIT: Alternative solution attempt (not working)
// Use this function to crop a screen shot to a specific element.
public byte[] test(byte[] screenshotData, View element)
{
// locate IntPtr to byte[] of uncropped screenshot
GCHandle gch = GCHandle.Alloc(screenshotData, GCHandleType.Pinned);
IntPtr addr = gch.AddrOfPinnedObject();
// assign initial bounds
SKImageInfo info = new SKImageInfo((int)App.Current.MainPage.Width,
(int)App.Current.MainPage.Height);
// create bitmap
SKBitmap bitmap = new SKBitmap();
bitmap.InstallPixels(info, addr);
// boundaries
SKRect cropRect = new SKRect((int)element.Bounds.Left, (int)element.Bounds.Top,
(int)element.Bounds.Right, (int)element.Bounds.Bottom);
SKBitmap croppedBitmap = new SKBitmap((int)cropRect.Width,
(int)cropRect.Height);
SKRect dest = new SKRect(0, 0, cropRect.Width, cropRect.Height);
SKRect source = new SKRect(cropRect.Left, cropRect.Top,
cropRect.Right, cropRect.Bottom);
// draw with destination and source rectangles
// to extract a subset of the original bitmap
using SKCanvas canvas = new SKCanvas(croppedBitmap);
canvas.DrawBitmap(bitmap, source, dest);
return croppedBitmap.Bytes;
//return bitmap.Bytes;
}
iOS solution - As seen here.
// crop the image, without resizing
private UIImage CropImage(UIImage sourceImage, int crop_x, int crop_y, int width, int height)
{
var imgSize = sourceImage.Size;
UIGraphics.BeginImageContextWithOptions(new System.Drawing.SizeF(width, height), false, 0.0f);
var context = UIGraphics.GetCurrentContext();
var clippedRect = new RectangleF(0, 0, width, height);
context.ClipToRect(clippedRect);
var drawRect = new RectangleF(-crop_x, -crop_y, imgSize.Width, imgSize.Height);
sourceImage.Draw(drawRect);
var modifiedImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return modifiedImage;
}
Android solution - getNavigationBarSize(context) as seen here
// crop the image, without resizing
private byte[] CropImage(byte[] screenshotBytes, int top)
{
Android.Graphics.Bitmap bitmap = Android.Graphics.BitmapFactory.DecodeByteArray(
screenshotBytes, 0, screenshotBytes.Length);
int viewStartY = (int)(top * 2.8f);
int viewHeight = (int)(bitmap.Height - (top * 2.8f));
var navBarXY = getNavigationBarSize(context);
int viewHeightMinusNavBar = viewHeight - navBarXY.Y;
Android.Graphics.Bitmap crop = Android.Graphics.Bitmap.CreateBitmap(bitmap,
0, viewStartY,
bitmap.Width, viewHeightMinusNavBar
);
bitmap.Dispose();
using MemoryStream stream = new MemoryStream();
crop.Compress(Android.Graphics.Bitmap.CompressFormat.Jpeg, 100, stream);
return stream.ToArray();
}
*NOTE: Unsure why a multiplication of 2.8 is required, though this works correctly. It should be stated testing was only done in the Android emulator. Perhaps it's emulator specific.
*NOTE2: x = 0 and width is equal to the entire width of the screen as that's per our requirement. Likewise top is Element.Bounds.Top.

C# Upload image and saving as Bitmap Increase size of the image

For uploading image I am using plupload on client side. Then in my controlled I have next logic:
public ActionResult UploadFile()
{
try
{
var file = Request.Files.Count > 0 ? Request.Files[0] : null;
using (var fileStream = new MemoryStream())
{
using (var oldImage = new Bitmap(file.InputStream))
{
var format = oldImage.RawFormat;
using (var newImage = ImageUtility.ResizeImage(oldImage, 800, 2000))
{
newImage.Save(fileStream, format);
}
byte[] bits = fileStream.ToArray();
}
}
{
catch (Exception ex)
{
}
}
ImageUtility.ResizeImage Method:
public static class ImageUtility
{
public static Bitmap ResizeImage(Bitmap image, int width, int height)
{
if (image.Width <= width && image.Height <= height)
{
return image;
}
int newWidth;
int newHeight;
if (image.Width > image.Height)
{
newWidth = width;
newHeight = (int)(image.Height * ((float)width / image.Width));
}
else
{
newHeight = height;
newWidth = (int)(image.Width * ((float)height / image.Height));
}
var newImage = new Bitmap(newWidth, newHeight);
using (var graphics = Graphics.FromImage(newImage))
{
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
graphics.FillRectangle(Brushes.Transparent, 0, 0, newWidth, newHeight);
graphics.DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
}
}
The issue which i have here that Image size is increased.
I uploaded image of 1.62MB and after this controller is called and it creates instance if Bitmap and then save Bitmap to filestream and read bits with "fileStream.ToArray();" I am getting 2.35MB in "bits".
Can anyone tell me what's the reason of increasing the image size after I save it as bitmap. I need Bitmap because I need to check with and height of uploaded image and resize it if I need.
The answer is simple, the bitmap takes up more memory the whatever format the image was in previously because it's uncompressed it stays in that uncompressed format after saving it.
jpeg, png, gif, etc. are compressed and therefore use less bytes tha a bitmap which is uncompressed.
If you just want to save the original image, just save file.InputStream.
If you need to resize, you can use a library to apply jpg/png/etc compression and then save the result.
What is the goal here? Are you merely trying to upload an image? Does it need to be validated as an image? Or are you just trying to upload the file?
If upload is the goal, without any regard to validation, just move the bits and save them with the name of the file. As soon as you do this ...
using (var oldImage = new Bitmap(file.InputStream))
... you are converting to a bitmap. Here is where you are telling the bitmap what format to use (raw).
var format = oldImage.RawFormat;
If you merely want to move the file (upload), you can run the memory stream to a filestream object and you save the bits.
If you want a few checks on whether the image is empty, etc, you can try this page (http://www.codeproject.com/Articles/1956/NET-Image-Uploading), but realize it is still putting it in an image, which is not your desire if you simply want to save "as is".

Displaying TIF image using byte array to writeable bitmap(C#)

I've a byte array of a tiff image. I want to form 3 images from it,that i'll do later but the problem is i'm not able to display the original image as it is.
Here is my xaml:
<Image Grid.Row="0" Grid.Column="0" Name="ReferenceImage"/>
xaml.cs code:
public MainWindow()
{
InitializeComponent();
ImagePath = #"G:\TiffImage\Test.TIF"
DisplayAllImages();
}
private void DisplayAllImages()
{
byte[] imageSize = File.ReadAllBytes(ImagePath);
ReferenceImage.Source = DisplayAllImages(imageSize, 64, 64);
}
private WriteableBitmap DisplayAllImages(byte[] imageData,int height,int width)
{
if (imageData != null)
{
PixelFormat format = PixelFormats.Gray8;
WriteableBitmap wbm = new WriteableBitmap(height, width, 96, 96, format, null);
wbm.WritePixels(new Int32Rect(0, 0, height, width), imageData, 1*width, 0);
return wbm;
}
else
{
return null;
}
}
My main aim is to display image using byte array like this way only, so that i can extract byte array to form other image as per requirements.
The image file contains encoded bitmap data. In order to access the raw pixels you would first have to decode the bitmap:
BitmapSource bitmap;
using (var fileStream = new FileStream(ImagePath, FileMode.Open, FileAccess.Read))
{
bitmap = BitmapFrame.Create(
fileStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
Now you would get the raw pixels by calling the CopyPixels method of the BitmapSource:
var width = bitmap.PixelWidth;
var height = bitmap.PixelHeight;
var stride = (width * bitmap.Format.BitsPerPixel + 7) / 8;
var imageData = new byte[height * stride];
bitmap.CopyPixels(imageData, stride, 0);
I'm not getting the expected images.Although i'm able to generate images which is matching almost 75% but not completely.

Resize byte[] of Image

After reading from file dialog I want to resize a picture. I have the done the following code. Now I want to resize the stream of picture. How do I do it?
Stream stream = (Stream)openFileDialog.File.OpenRead();
byte[] bytes = new byte[stream.Length];
There is no need to declare a byte[], to resize an image just use
Image image = Image.FromFile(fileName);
check this other answer to see how to scale the image aftewards
try this
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);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
Usage
Image img = Image.FromStream(stream);
Image thumb = ScaleImage(img);
stream.Close();
stream.Dispose();
stream = new MemoryStream();
thumb.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
I have an picturebox. I load an image, resizing and conveting to byte at last sending to sqllite. Maybe it can be hlepfıull to you Code is below.
private static byte[] byteResim = null;
private void btnResimEkle_Click(object sender, EventArgs e)
{
openFileDialog1.Title = "Resimdosyası seçiniz.";
openFileDialog1.Filter = "Resim files (*.jpg)|*.jpg|Tüm dosyalar(*.*)|*.*";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string resimYol = openFileDialog1.FileName; // File name of the image
picResim.Image = Image.FromFile(resimYol);// picResim is name of picturebox
picResim.Image = YenidenBoyutlandir(new Bitmap(picResim.Image)); //this method resizing the image
Image UyeResim = picResim.Image; // and this four block converting to image to byte
MemoryStream ms = new MemoryStream();
UyeResim.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byteResim = ms.ToArray(); // byteResim variable format Byte[]
}
}
Image YenidenBoyutlandir(Image resim)// resizing image method
{
Image yeniResim = new Bitmap(150, 156);
using (Graphics abc = Graphics.FromImage((Bitmap)yeniResim))
{
abc.DrawImage(resim, new System.Drawing.Rectangle(0, 0, 150, 156));
}
return yeniResim;
}

How to display Grayscale image after changing the indexing in C#

I have a Grayscale image which I am pulling from the DB (it is in Bytes). I want to draw some boxes using graphics object on it and then display this image. This is what was coded before -
public byte[] DrawOverlayOnGreyscaleImage(byte[] buffer, List<ImagingTransaction.ImagingTransactionField> TransactionFieldList, BLLImageType imageType)
{
//Load image into a bitmap object via first going into a MemoryStream
MemoryStream msBitmap = new MemoryStream(buffer);
Bitmap BitmapObj = null;
BitmapObj = new Bitmap(msBitmap);
int bmwidth = BitmapObj.Width;
int bmheight = BitmapObj.Height;
// draw some text on top
Graphics g = Graphics.FromImage(BitmapObj);
Because of the changes in the way the image is now generated (Format8bppIndexed) the Graphics object threw an exception - "A graphics object cannot be created from an image that has an indexed pixel format". So I changed the Bitmap to be Format24bppRGB. Now, there is no exception. But after I draw boxes on the image and try to save it, the image is all black. This is because in case of "Grayscale" images R=G=B. This is lost after making it non indexed. I change the Bitmap to be again Indexed (Format8bbIndexed). Change the ColorPalette, but nothing helps. I still get the image to be totally black. Please help. My new code is as follows -
public byte[] DrawOverlayOnGreyscaleImage(byte[] buffer, List<ImagingTransaction.ImagingTransactionField> TransactionFieldList, BLLImageType imageType)
{
//Load image into a bitmap object via first going into a MemoryStream
MemoryStream msBitmap = new MemoryStream(buffer);
Bitmap BitmapObj = null;
BitmapObj = new Bitmap(msBitmap);
int bmwidth = BitmapObj.Width;
int bmheight = BitmapObj.Height;
Bitmap tmp = new Bitmap(BitmapObj.Width, BitmapObj.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(tmp);
Rectangle srcRect;
int RectWidth;
int RectHeight;
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
foreach (ImagingTransaction.ImagingTransactionField Field in TransactionFieldList)
{
// first, do they want to see the rectangles
if (imageType == BLLImageType.GreyScale_With_FieldRectangles || imageType == BLLImageType.GreyScale_With_FieldRectangles_And_Field_Data)
{
RectWidth = Field.LowerRightX - Field.UpperLeftX;
RectHeight = Field.LowerRightY - Field.UpperLeftY;
// sanity check for negative values
if (RectWidth <= 0)
RectWidth = 10;
if (RectHeight <= 0)
RectHeight = 10;
srcRect = new Rectangle(Field.UpperLeftX, Field.UpperLeftY, RectWidth, RectHeight);
g.DrawRectangle(myPen, srcRect);
}
// now, do they want to see the text to the lower right of the field
if (imageType == BLLImageType.GreyScale_With_Field_Data || imageType == BLLImageType.GreyScale_With_FieldRectangles_And_Field_Data)
{
g.DrawString(Field.FieldValue, new Font("Tahoma", 12), Brushes.Red, new PointF(Field.LowerRightX, Field.LowerRightY)); ;
}
}
MemoryStream msBitmapWithRectangle = new MemoryStream();
// Save to memory using the Jpeg format
Bitmap tmp2 = new Bitmap(tmp.Width, tmp.Height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
ColorPalette pal = tmp2.Palette;
for (int i = 0; i < pal.Entries.Length; i++)
{
// create greyscale color table
pal.Entries[i] = Color.FromArgb(i, i, i);
}
tmp2.Palette = pal;
tmp2.Save(msBitmapWithRectangle, System.Drawing.Imaging.ImageFormat.Jpeg);
// read to end
byte[] ByteArrayWithRectangle = msBitmapWithRectangle.GetBuffer();
// cleanup
tmp.Dispose();
tmp2.Dispose();
BitmapObj.Dispose();
msBitmap.Close();
msBitmapWithRectangle.Close();
return ByteArrayWithRectangle;
}
Seems that tmp2 is created but never filled with original bitmap, so you create a perfectly black rectangle.
Try creating a new bitmap in the BPP and size you need, and draw the image, and then draw the rectange.

Categories