I'm currently scanning few images and store ROIs in a List. Now I loop through the list and check if the ROI has a bar code in it. It works with few images and throws an AccessViolationException at converting mat to image for others and it is not getting caught in the catch block.
The below code is used to check if bar code exists.
List<Mat> subMats = new List<Mat>();
Mat mat = new Mat(image.Mat, enlargeROI(image.Mat,NEWRECTANGLE,PADDING));
subMats.Add(mat);
using (var mImage = new Image<Bgr, byte>(image.Width, image.Height))
{
var barcodeReader = new BarcodeReader();
foreach (var matt in subMats)
{
//TODO : check if the submat is a barcode
try
{
Image<Bgr, byte> img = matt.ToImage<Bgr, byte>(); // EXCEPTION THROWN AT THIS LINE
Bitmap bmp = img.ToBitmap();
if (barcodeReader.Decode(bmp) != null)
{
CvInvoke.Rectangle(image, NEWRECTANGLE, new MCvScalar(0.0, 0.0, 0.0), -1);
}
}
catch (Exception e)
{
Console.WriteLine("**" + e.Message);
}
}
}
The Exception says
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Tried to read it using images like below, but it wouldn't detect the barcodes properly.
public static List<Rectangle> rois = new List<Rectangle>();
rois.Add(NEWRECTANGLE);
using (var mImage = image)
{
var barcodeReader = new BarcodeReader();
int count = 0;
foreach (var roi in rois)
{
//TODO : check if the submat is a barcode
try
{
mImage.ROI = roi;
Bitmap bmp = mImage.ToBitmap();
if (barcodeReader.Decode(bmp) != null)
{
CvInvoke.Rectangle(image, NEWRECTANGLE, new MCvScalar(0.0, 0.0, 0.0), -1);
}
}
catch (Exception e)
{
Console.WriteLine("**" + e.Message);
}
}
}
What could go wrong? Any help would be appreciated.
Thanks.
EDIT
I have identified all my ROIs by finding contours. Looping through the contours I find the rectangles and store them in a List.
CvInvoke.FindContours(fullGrad, contours, null, Emgu.CV.CvEnum.RetrType.List, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxNone);
for (int i = 0; i < contours.Size; i++)
{
if (CvInvoke.ContourArea(contours[i]) < 2000) {
continue;
}
RotatedRect RECT = CvInvoke.MinAreaRect(contours[i]);
PointF[] VERTIXES = RECT.GetVertices();
int X = (int)VERTIXES[1].X;
int Y = (int)VERTIXES[2].Y;
//OBTAIN RECTANGLE THAT SURROUNDS THE DETECTED CONTOUR
int WIDTH = (int)(VERTIXES[3].X - VERTIXES[1].X);
int HEIGHT = (int)(VERTIXES[0].Y - VERTIXES[2].Y);
Rectangle NEWRECTANGLE = new Rectangle(X, Y, WIDTH, HEIGHT);
Mat mat = new Mat(image.Mat, enlargeROI(image.Mat,NEWRECTANGLE,PADDING));
subMats.Add(mat);
Related
i am using C# EmguCv library to detect diamonds from the image capture by a live camera and saved into the folder. i have done other task of the project and only remaining the detection part and almost got it but just missing something that i don't know where is the problem . so here is the Image and it should be detected as Image2 perfect as this image so now i am trying something but it not giving me the result i want. here's i what i am getting is image3 and image4.
here is my code:
imgInput = new Image<Bgr, byte>(img_path);
if (imgInput == null)
{
return;
}
try
{
// Convert image to grayscale
Mat grayImage = new Mat();
CvInvoke.CvtColor(imgInput, grayImage, ColorConversion.Bgr2Gray);
// Apply Gaussian blur to reduce noise
CvInvoke.GaussianBlur(grayImage, grayImage, new Size(7, 7), 4);
// Apply Canny edge detection
Mat edges = new Mat();
CvInvoke.Canny(grayImage, edges, 75, 200);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(edges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
int jk = 0;
dataGridView1.Columns.Add("stone_id", "Stone ID");
for (int i = 0; i < contours.Size; i++)
{
double perimeter = CvInvoke.ArcLength(contours[i], true);
VectorOfPoint approx = new VectorOfPoint();
CvInvoke.ApproxPolyDP(contours[i], approx, 0.04 * perimeter, true);
var bbox = CvInvoke.BoundingRectangle(contours[i]);
process_img = new Image<Bgr, byte>(img_path);
process_img.ROI = bbox;
var img = process_img.Copy();
if (jk == sel_row_id)
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 255, 17), 2);
if (contours.Size > 0)
{
byte maxRed, maxBlue, maxGreen;
maxRed = maxBlue = maxGreen = 0;
float meanRed, meanBlue, meanGreen;
meanRed = meanBlue = meanGreen = 0;
double medRed,medBlue,medGreen;
medRed = medBlue = medGreen = 0;
FindMax(img.Bitmap, ref maxRed, ref maxBlue, ref maxGreen, ref meanRed, ref meanBlue, ref meanGreen, ref medRed, ref medBlue, ref medGreen);
R_txtbox.Text = maxRed.ToString();
B_txtbox.Text = maxBlue.ToString();
G_txtbox.Text = maxGreen.ToString();
R_mean.Text = meanRed.ToString();
B_mean.Text = meanBlue.ToString();
G_mean.Text = meanGreen.ToString();
R_med.Text = medRed.ToString();
B_med.Text = medBlue.ToString();
G_med.Text = medGreen.ToString();
pictureBox5.Image = img.ToBitmap();
//colorCode.Text = myRgbColor.ToString();
}
}
else
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 0, 255), 2);
}
dataGridView1.Rows.Add(jk.ToString());
jk++;
pictureBox4.Image = imgInput.Bitmap;
img.Save("F:\\Objects" + "\\" + (i + 1) + ".jpg");
}
RefreshGridView();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
i am using EmguCv in C# .net framework projec. i have used find contours and draw contours and after that the object is cropped and show in another picture box. the problem is i need the objects detected shape not rectangle shape image.
similar to this solution : How to crop the internal area of a contour?
but in emguCV C#.
here is what i have tried so far.
imgInput = new Image<Bgr, byte>(img_path);
if (imgInput == null)
{
return;
}
try
{
var temp = imgInput.Not().SmoothGaussian(5).Convert<Gray, byte>().ThresholdBinaryInv(new Gray(250), new Gray(255));
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
Mat m = new Mat();
CvInvoke.FindContours(temp, contours, m, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
int jk = 0;
dataGridView1.Columns.Add("stone_id", "Stone ID");
for (int i = 0; i < contours.Size; i++)
{
double perimeter = CvInvoke.ArcLength(contours[i], true);
VectorOfPoint approx = new VectorOfPoint();
CvInvoke.ApproxPolyDP(contours[i], approx, 0.04 * perimeter, true);
if (jk == sel_row_id)
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 255, 17), 2);
if (contours.Size > 0)
{
Rectangle bbox = CvInvoke.BoundingRectangle(contours[0]); // here is the process of cropping rectangle.
imgInput.ROI = bbox;
var img = imgInput.Copy();
imgInput.ROI = Rectangle.Empty;
pictureBox5.Image = img.Bitmap;
}
}
else
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 0, 255), 2);
}
dataGridView1.Rows.Add(jk.ToString());
jk++;
//moments center of the shape
var moments = CvInvoke.Moments(contours[i]);
int x = (int)(moments.M10 / moments.M00);
int y = (int)(moments.M01 / moments.M00);
pictureBox4.Image = imgInput.Bitmap;
}
RefreshGridView();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The code below successfully takes screenshots of the monitors attached to my Windows 10 laptop computer, so long as the monitors are not "flipped". When the monitors are flipped to any orientation except "landscape" the captured images are all black pixels (r,g,b,a = 0,0,0,255)
How can I modify the code below so that it will also work with flipped monitors?
Target Framework is:
Net 4.8
Referenced packages are:
SharpDX 4.2.0
SharpDX.Direct2D1 4.2.0
SharpDX.Direct3D11 4.2.0
SharpDX.DXGI 4.2.0
SharpDX.DXGI 4.2.0
using System;
using System.IO;
using System.Runtime.ExceptionServices;
using SharpDX;
namespace ScreenCast {
internal static class Program {
[STAThread]
private static void Main() {
var captureCount = 0;
using var factory = new SharpDX.DXGI.Factory4();
foreach (var adapter in factory.Adapters1) {
using var device = new SharpDX.Direct3D11.Device(adapter);
foreach (var output in adapter.Outputs) {
if (output.Description.IsAttachedToDesktop) {
var description = output.Description;
using var output1 = output.QueryInterface<SharpDX.DXGI.Output1>();
Capture($"{captureCount++}.bmp", device, output1);
}
output.Dispose();
}
adapter.Dispose();
}
}
private static void Capture(string outputFileName, SharpDX.Direct3D11.Device device, SharpDX.DXGI.Output1 output1) {
int width = output1.Description.DesktopBounds.Right - output1.Description.DesktopBounds.Left;
int height = output1.Description.DesktopBounds.Bottom - output1.Description.DesktopBounds.Top;
using var stagingScreenTexture = new SharpDX.Direct3D11.Texture2D(device, new SharpDX.Direct3D11.Texture2DDescription {
Width = width,
Height = height,
CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.Read,
BindFlags = SharpDX.Direct3D11.BindFlags.None,
Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm,
OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None,
MipLevels = 1,
ArraySize = 1,
SampleDescription = { Count = 1, Quality = 0 },
Usage = SharpDX.Direct3D11.ResourceUsage.Staging
});
using var duplicatedOutput = output1.DuplicateOutput(device);
SharpDX.DXGI.Resource screenResource = null;
SharpDX.DXGI.OutputDuplicateFrameInformation duplicateFrameInformation;
AcquireFrame(duplicatedOutput, out duplicateFrameInformation, out screenResource);
duplicatedOutput.ReleaseFrame();
AcquireFrame(duplicatedOutput, out duplicateFrameInformation, out screenResource);
// copy resource into memory that can be accessed by the CPU
using var screenTexture = screenResource.QueryInterface<SharpDX.Direct3D11.Texture2D>();
device.ImmediateContext.CopyResource(screenTexture, stagingScreenTexture);
// Get the desktop capture texture
var mapSource = device.ImmediateContext.MapSubresource(stagingScreenTexture, 0, SharpDX.Direct3D11.MapMode.Read, SharpDX.Direct3D11.MapFlags.None);
using var bmp = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var bmpBounds = new System.Drawing.Rectangle(0, 0, width, height);
var bmpData = bmp.LockBits(bmpBounds, System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp.PixelFormat);
var src = mapSource.DataPointer;
var dest = bmpData.Scan0;
for (var y = 0; y < height; y++) {
SharpDX.Utilities.CopyMemory(dest, src, width * 4);
src += mapSource.RowPitch;
dest += bmpData.Stride;
}
bmp.UnlockBits(bmpData);
bmp.Save(outputFileName);
device.ImmediateContext.UnmapSubresource(stagingScreenTexture, 0);
screenResource.Dispose();
duplicatedOutput.ReleaseFrame();
// Display the texture using system associated viewer
System.Diagnostics.Process.Start(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, outputFileName)));
}
static void AcquireFrame(SharpDX.DXGI.OutputDuplication duplication, out SharpDX.DXGI.OutputDuplicateFrameInformation info, out SharpDX.DXGI.Resource resource) {
while (true) {
try {
duplication.AcquireNextFrame(100, out info, out resource);
return;
} catch (SharpDXException x) {
if (x.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
ExceptionDispatchInfo.Capture(x).Throw();
}
}
}
}
}
First, I only used SharpDX for a few days, so I'm by no means an expert, but I ran into a similar problem when capturing from rotated monitor and from what I've been able to deduce captured frame is not rotated.
e.g. Your monitor is rotated 90 deg to portrait (Width x Height 1080x1920) so you'd expect the captured frame to be portrait as well, right? Nope, you get the 1920 x 1080 landscape bitmap so your screen width= bitmap height and vice versa:
Here is the code I used in my capture class, still work in progress:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using Device = SharpDX.Direct3D11.Device;
using MapFlags = SharpDX.Direct3D11.MapFlags;
namespace EXM.ExampleCapture
{
public class DXScreenCaptureUtil {
private static ImageCodecInfo jpegCodec = ImageCodecInfo.GetImageEncoders()
.First(c => c.FormatID == ImageFormat.Jpeg.Guid);
private static EncoderParameters jpegParams = new EncoderParameters() { Param = new[] { new EncoderParameter(Encoder.Quality, 60L) } };
//Cache objects
private static Factory1 factory = new Factory1();
private static Adapter adapter;
private static Device device;
/// <summary>
/// Gets target device (Display) based on the rectangle we want to capture
/// </summary>
/// <param name="sourceRect">Rectangle we want to capture</param>
/// <returns>Screen which contains the area we want to capture or null if no device contains our area of interest</returns>
private static Screen GetTargetScreen(Rectangle sourceRect) {
foreach (var scr in Screen.AllScreens)
{
if (sourceRect.X >= scr.Bounds.X && sourceRect.Y >= scr.Bounds.Y
&& sourceRect.Right <= scr.Bounds.Width + scr.Bounds.X
&& sourceRect.Bottom <= scr.Bounds.Height + scr.Bounds.Y
)
{
return scr;
}
}
return null;
}
public static (byte[], int) Capture(Rectangle sourceRect, int jpegQuality) {
Screen targetScreen = GetTargetScreen(sourceRect);
if (targetScreen == null) {
throw new Exception($#"Could not find target screen for capture rectangle {sourceRect}");
}
//This is to instruct client receiving the image to rotate it, seems like a reasonable thing to offload it to client and save a bit of CPU time on server
int rotation = 0;
byte[] imageBytes = null;
// Width/Height of desktop to capture
int width = targetScreen.Bounds.Width;
int height = targetScreen.Bounds.Height;
Rectangle cropRect = new Rectangle(sourceRect.X - targetScreen.Bounds.X, sourceRect.Y - targetScreen.Bounds.Y, sourceRect.Width, sourceRect.Height);
// Create DXGI Factory1
if (adapter == null) { adapter = factory.Adapters.Where(x => x.Outputs.Any(o => o.Description.DeviceName == targetScreen.DeviceName)).FirstOrDefault(); }
// Create device from Adapter
if (device == null) { device = new Device(adapter); }
//using (var output = adapter.Outputs.Where(o => o.Description.DeviceName == targetScreen.DeviceName).FirstOrDefault()) //This creates a memory leak!
Output output = null;
//I'm open to suggestions here:
for (int i = 0; i < adapter.GetOutputCount(); i++) {
output = adapter.GetOutput(i);
if (output.Description.DeviceName == targetScreen.DeviceName) {
break;
}
else {
output.Dispose();
}
}
using (var output1 = output.QueryInterface<Output1>()) {
if (output1.Description.Rotation == DisplayModeRotation.Rotate90) {
width = targetScreen.Bounds.Height;
height = targetScreen.Bounds.Width;
int offsetX = targetScreen.Bounds.X - sourceRect.X;
cropRect = new Rectangle(
sourceRect.Y - targetScreen.Bounds.Y,
targetScreen.Bounds.Width - (sourceRect.Width + offsetX),
sourceRect.Height, sourceRect.Width);
rotation = 90;
}
else if (output1.Description.Rotation == DisplayModeRotation.Rotate270) {
width = targetScreen.Bounds.Height;
height = targetScreen.Bounds.Width;
int offsetY = targetScreen.Bounds.Y - sourceRect.Y;
cropRect = new Rectangle(
targetScreen.Bounds.Height - (sourceRect.Height + offsetY),
targetScreen.Bounds.X - sourceRect.X,
sourceRect.Height, sourceRect.Width);
rotation = 270;
}
else if (output1.Description.Rotation == DisplayModeRotation.Rotate180) {
rotation = 180;
}
// Create Staging texture CPU-accessible
var textureDesc = new Texture2DDescription {
CpuAccessFlags = CpuAccessFlags.Read,
BindFlags = BindFlags.None,
Format = Format.B8G8R8A8_UNorm,
Width = width,
Height = height,
OptionFlags = ResourceOptionFlags.None,
MipLevels = 1,
ArraySize = 1,
SampleDescription = { Count = 1, Quality = 0 },
Usage = ResourceUsage.Staging
};
using (var screenTexture = new Texture2D(device, textureDesc))
//Duplicate the output
using (var duplicatedOutput = output1.DuplicateOutput(device)) {
bool captureDone = false;
SharpDX.DXGI.Resource screenResource = null;
OutputDuplicateFrameInformation duplicateFrameInformation;
for (int i = 0; !captureDone; i++) {
try {
//Try to get duplicated frame within given time
duplicatedOutput.AcquireNextFrame(1000, out duplicateFrameInformation, out screenResource);
//Ignore first call, this always seems to return a black frame
if (i == 0) {
screenResource.Dispose();
continue;
}
//copy resource into memory that can be accessed by the CPU
using (var screenTexture2D = screenResource.QueryInterface<Texture2D>()) {
device.ImmediateContext.CopyResource(screenTexture2D, screenTexture);
}
//Get the desktop capture texture
var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, MapFlags.None);
var boundsRect = new System.Drawing.Rectangle(0, 0, width, height);
//Create Drawing.Bitmap
using (var bitmap = new System.Drawing.Bitmap(width, height, PixelFormat.Format32bppArgb)) {
//Copy pixels from screen capture Texture to GDI bitmap
var bitmapData = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
var sourcePtr = mapSource.DataPointer;
var destinationPtr = bitmapData.Scan0;
for (int y = 0; y < height; y++) {
//Copy a single line
Utilities.CopyMemory(destinationPtr, sourcePtr, width * 4);
//Advance pointers
sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
destinationPtr = IntPtr.Add(destinationPtr, bitmapData.Stride);
}
//Release source and dest locks
bitmap.UnlockBits(bitmapData);
device.ImmediateContext.UnmapSubresource(screenTexture, 0);
//Save the output
imageBytes = CropBitmapToJPEGBytes(bitmap, cropRect, jpegQuality);
}
//Capture done
captureDone = true;
}
catch (SharpDXException e) {
if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) {
throw;
}
}
finally {
//Dispose manually
if (screenResource != null) {
screenResource.Dispose();
}
duplicatedOutput.ReleaseFrame();
}
}
}
}
output.Dispose();
return (imageBytes, rotation);
}
/// <summary>
/// Crop bitmap
/// </summary>
/// <param name="orig">Original bitmap</param>
/// <param name="cropRect">Crop rectangle</param>
/// <returns>Cropped bitmap</returns>
static byte[] CropBitmapToJPEGBytes(Bitmap orig, Rectangle cropRect, int jpegQuality) {
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, (long)jpegQuality);
jpegParams.Param[0] = qualityParam;
byte[] imageBytes;
using (Bitmap nb = new Bitmap(cropRect.Width, cropRect.Height)) {
using (Graphics g = Graphics.FromImage(nb)) {
g.DrawImage(orig, -cropRect.X, -cropRect.Y);
using (MemoryStream s = new MemoryStream()) {
nb.Save(s, jpegCodec, jpegParams);
imageBytes = s.ToArray();
}
}
}
return imageBytes;
}
}
}
I'm using c# and aforge.net to find the perimeter of objects in following image.
Source Image
what I've done till now is ...
made image binary.
found the blobs.
Extracted image for each blob.
used MoravecCornersDetector class to find edge points.
When I draw Points, the result is like following image.
Final Image
Now my problem is ...
Now my problem is sorting these points to make a polygon and sum the distance between them to find perimeter.
Would you mind tell me How can I do this?
Do you know any better way to find perimeter?
private void Form1_Load(object sender, EventArgs e)
{
curImage = new Bitmap(#"1.jpg");
extractBlob(ThresholdImage(curImage));
}
Bitmap ThresholdImage(Bitmap image)
{
Bitmap result;
using (Bitmap aa = image)
{
// create grayscale filter (BT709)
Grayscale filter = new Grayscale(0.2125, 0.7154, 0.0721);
// apply the filter
Bitmap grayImage = filter.Apply(aa);
// create filter
Threshold filter2 = new Threshold(200);
// apply the filter
filter2.ApplyInPlace(grayImage);
result = new Bitmap(grayImage);
}
return result;
}
void extractBlob(Bitmap image)
{
BlobCounterBase bc = new BlobCounter();
bc.FilterBlobs = true;
bc.MinHeight = 5;
bc.MinWidth = 5;
bc.ProcessImage(image);
Blob[] blobs = bc.GetObjectsInformation();
for (int i = 0, n = blobs.Length; i < n; i++)
{
bc.ExtractBlobsImage(image, blobs[i], true);
Bitmap copy = blobs[i].Image.ToManagedImage();
Edge(copy);
// ------> Draw Edge(copy)
}
}
List<PointF> Edge(Bitmap image)
{
// create corner detector's instance
MoravecCornersDetector mcd = new MoravecCornersDetector();
// process image searching for corners
List<IntPoint> corners = mcd.ProcessImage(image);
List<PointF> eachObject = new List<PointF>();
foreach (var item in corners)
{
PointF p = new PointF(item.X, item.Y);
eachObject.Add(p);
}
return eachObject;
}
How do I save a generated thumbnail? I am getting this error:
Object reference not set to an instance of an object
This is my code. I am new to C#. I found the thumbnail generation code online and I thought I could use it but its giving me an error...
//1. <lcFilename> as path of large size file.
//2. <lnWidth> as width of required thumbnail.
//3. <lnHeight> as height of required thumbnail.
//The function returns a Bitmap object of the changed thumbnail image which you can save on the disk.
public static Bitmap CreateThumbnail(string lcFilename, int lnWidth, int lnHeight)
{
System.Drawing.Bitmap bmpOut = null;
try
{
Bitmap loBMP = new Bitmap(lcFilename);
ImageFormat loFormat = loBMP.RawFormat;
decimal lnRatio;
int lnNewWidth = 0;
int lnNewHeight = 0;
//*** If the image is smaller than a thumbnail just return it
if (loBMP.Width < lnWidth && loBMP.Height < lnHeight)
return loBMP;
if (loBMP.Width > loBMP.Height)
{
lnRatio = (decimal)lnWidth / loBMP.Width;
lnNewWidth = lnWidth;
decimal lnTemp = loBMP.Height * lnRatio;
lnNewHeight = (int)lnTemp;
}
else
{
lnRatio = (decimal)lnHeight / loBMP.Height;
lnNewHeight = lnHeight;
decimal lnTemp = loBMP.Width * lnRatio;
lnNewWidth = (int)lnTemp;
}
bmpOut = new Bitmap(lnNewWidth, lnNewHeight);
Graphics g = Graphics.FromImage(bmpOut);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.FillRectangle(Brushes.White, 0, 0, lnNewWidth, lnNewHeight);
g.DrawImage(loBMP, 0, 0, lnNewWidth, lnNewHeight);
loBMP.Dispose();
}
catch
{
return null;
}
return bmpOut;
}
// Thumbnail Generate
string largefilepath = "images/" + imageuploaded;
string largefilepath2 = "images/users/" + imageuploaded + "-160x160";
Bitmap bmp1 = new Bitmap(CreateThumbnail(largefilepath, 160, 160));
bmp1.Save(largefilepath2);
You have to Dispose your Graphics after it finishes its job. When you draw something on an image with Graphics, it is common to use using block but since it is already in the try/catch scope, it seems redundant here.
//1. <lcFilename> as path of large size file.
//2. <lnWidth> as width of required thumbnail.
//3. <lnHeight> as height of required thumbnail.
//The function returns a Bitmap object of the changed thumbnail image which you can save on the disk.
public static Bitmap CreateThumbnail(string lcFilename, int lnWidth, int lnHeight)
{
System.Drawing.Bitmap bmpOut = null;
try
{
Bitmap loBMP = new Bitmap(lcFilename);
ImageFormat loFormat = loBMP.RawFormat;
decimal lnRatio;
int lnNewWidth = 0;
int lnNewHeight = 0;
//*** If the image is smaller than a thumbnail just return it
if (loBMP.Width < lnWidth && loBMP.Height < lnHeight)
return loBMP;
if (loBMP.Width > loBMP.Height)
{
lnRatio = (decimal)lnWidth / loBMP.Width;
lnNewWidth = lnWidth;
decimal lnTemp = loBMP.Height * lnRatio;
lnNewHeight = (int)lnTemp;
}
else
{
lnRatio = (decimal)lnHeight / loBMP.Height;
lnNewHeight = lnHeight;
decimal lnTemp = loBMP.Width * lnRatio;
lnNewWidth = (int)lnTemp;
}
bmpOut = new Bitmap(lnNewWidth, lnNewHeight);
Graphics g = Graphics.FromImage(bmpOut);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.FillRectangle(Brushes.White, 0, 0, lnNewWidth, lnNewHeight);
g.DrawImage(loBMP, 0, 0, lnNewWidth, lnNewHeight);
// Dispose Graphics so that it releases all the resources it's holding to draw on that image.
g.Dispose();
/* or you could use Graphics as below.. but it seems redundant, because it is already in the try / catch block.
using ( Graphics g = Graphics.FromImage(bmpOut))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.FillRectangle(Brushes.White, 0, 0, lnNewWidth, lnNewHeight);
g.DrawImage(loBMP, 0, 0, lnNewWidth, lnNewHeight);
}
*/
loBMP.Dispose();
}
catch
{
return null;
}
return bmpOut;
}
// Thumbnail Generate
string largefilepath = "images/" + imageuploaded;
string largefilepath2 = "images/users/" + imageuploaded + "-160x160";
Bitmap bmp1 = new Bitmap(CreateThumbnail(largefilepath, 160, 160));
bmp1.Save(largefilepath2);
The problem is you have a try..catch inside your method and this is swallowing the exception, and you are returning null from there, Hence the exception that you have reported.
Option 1
My suggestion is to either do something with the exception such as log it, this way you know something went wrong, like now. And handle the instance where a null value can be returned by the method, as follows:
string largefilepath = "images/" + imageuploaded;
string largefilepath2 = "images/users/" + imageuploaded + "-160x160";
Bitmap bmp1 = new Bitmap(CreateThumbnail(largefilepath, 160, 160));
if (bmp1 == null) {
// there was an exception, check the logs
}
else {
bmp1.Save(largefilepath2);
}
Option 2:
Or remove the try catch completely from the method and move it out as follows:
Note: the following code assumes you have removed the try...catch from the CreateThumbnail method.
try {
//Where imageUploaded is the name of the image with the extension, e.g. "samplePic.jpg"
string largefilepath = #"c:\images\" + imageuploaded;
string largefilepath2 = #"c:\images\users\" + System.IO.Path.GetFileNameWithoutExtension(imageuploaded) + "-160x160" + System.IO.Path.GetExtension(largefilepath);
Bitmap bmp1 = new Bitmap(CreateThumbnail(largefilepath, 160, 160));
bmp1.Save(largefilepath2);
}
catch (Exception ex) {
//do something with the exception
}