refactoring code for better recursion - c#

I am trying to write some code that will look into a pdf file and call the Process method (to find a qr code image in the pdf) if not found then it rotates the file and runs the Process method again. Currently I don't think that what I have actually checks the file after being rotated but checks the same original file in its original format. How can I pass in the rotated image properly into the Process method:
using (var fullImg = new Bitmap(workGif))
{
var bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, 375, 375), fullImg.PixelFormat);
Bitmap result = fullImg;
if (Process(bandImg) == null)
{
fullImg.RotateFlip(RotateFlipType.Rotate270FlipNone);
bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, 375, 375), fullImg.PixelFormat);
if (Process(bandImg) == null)
{
fullImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, 375, 375), fullImg.PixelFormat);
if (Process(bandImg) == null)
{
fullImg.RotateFlip(RotateFlipType.Rotate180FlipNone);
bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, 375, 375), fullImg.PixelFormat);
//Process(bandImg);
string QRinfo = Process(bandImg);
MessageBox.Show(QRinfo);
string[] qcode = QRinfo.Split('/');
string gid = qcode[qcode.Count() - 1];
Guid pgGuid = new Guid(gid);
var ar = dc.Assessments.FirstOrDefault(c => c.ID == pgGuid);
if (ar != null)
{
var p = inputDocument.Pages[pg];
string opdName = FILESTORELOCATION + pgGuid.ToString() + ".pdf";
PdfDocument opd = new PdfDocument(opdName);
opd.Pages.Add(p);
opd.Close();
ar.StoragePath = opdName;
ar.LastUploadedDT = DateTime.UtcNow;
ar.UploadedByUserID = uploadingUser;
dc.SubmitChanges();
}
}
}
}
Process Method:
public string Process(Bitmap bitmap)
{
var reader = new com.google.zxing.qrcode.QRCodeReader();
try
{
LuminanceSource source = new RGBLuminanceSource(bitmap, bitmap.Width, bitmap.Height);
var binarizer = new HybridBinarizer(source);
var binBitmap = new BinaryBitmap(binarizer);
return reader.decode(binBitmap).Text;
}
catch (Exception e)
{
return null;
}
}

If you wanted a recursive solution check this (untested code of course):
string ReadQrCode(Bitmap img, int n = 0) {
if(n == 4) return null;
var bandImg = img.Clone(new System.Drawing.Rectangle(0, 0, 375, 375),
img.PixelFormat);
string text = Process(bandImg);
if(text == null) {
img.RotateFlip(RotateFlipType.Rotate90FlipNone);
text = ReadQrCode(img, n + 1);
}
return Text;
}
Example:
string qrCode;
using (var fullImg = new Bitmap(workGif)) {
qrCode = ReadQrCode(bandImg);
}
EXPLANATION:
Recursion is not needed to solve this kind of problem actually, indeed, as Alexei Levenkov pointed out in his comment below, a loop is much easier and clear:
string text = null;
for(int i = 0; i < 4; i++) {
var bandImg = img.Clone(new System.Drawing.Rectangle(0, 0, 375, 375),
img.PixelFormat);
text = Process(bandImg)
if(text != null) break;
else img.RotateFlip(RotateFlipType.Rotate90FlipNone);
}
In the recursive solution n behaves like the counter does in the loop, this means that recursion will have a depth of four calls (at most) just like the loop will iterate four times (at most).

Related

Getting wrong dimension image after cutting image from center

I am trying to crop image from center and want to generate image with 100 * 46 dimensions but i am getting image with 46 * 17 dimension.
Code:
SaveCroppedImage(Image.FromStream(file.InputStream), 100, 46, "MyfilePath", true);
public void SaveCroppedImage(Image image, UInt16 thumbWidth, UInt16 thumbHeight, string filePath, Boolean checkDimension)
{
if (checkDimension && image.Width > image.Height)
{
var tmp = thumbHeight;
thumbHeight = thumbWidth;
thumbWidth = tmp;
}
if (image.Width > thumbWidth || image.Height > thumbHeight)
{
float scaleWidth = 1;
float scaleHeight = 1;
float scale = 1;
scaleWidth = ((float)thumbWidth / (float)image.Width);
scaleHeight = ((float)thumbHeight / (float)image.Height);
if (scaleWidth < scaleHeight)
{
scale = scaleWidth;
}
else
{
scale = scaleHeight;
}
thumbWidth = (UInt16)Math.Round(image.Width * scale, 0);
thumbHeight = (UInt16)Math.Round(image.Height * scale, 0);
}
if (thumbWidth > image.Width)
thumbWidth = (UInt16)image.Width;
if (thumbHeight > image.Height)
thumbHeight = (UInt16)image.Height;
//System.Drawing.Image thumb = image.GetThumbnailImage(thumbWidth, thumbHeight, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
System.Drawing.Image thumb = new System.Drawing.Bitmap(thumbWidth, thumbHeight);
System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(thumb);
gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(0, 0, thumbWidth, thumbHeight);
gr.DrawImage(image, rectDestination, 0, 0, image.Width, image.Height, System.Drawing.GraphicsUnit.Pixel);
//
// get raw format
System.Drawing.Imaging.ImageFormat format = image.RawFormat;
//
// get encoder
System.Drawing.Imaging.ImageCodecInfo info = null;
foreach (System.Drawing.Imaging.ImageCodecInfo ici in System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders())
{
if (System.Drawing.Imaging.ImageFormat.Jpeg.Equals(format))
{
info = ici;
break;
}
else if (System.Drawing.Imaging.ImageFormat.Gif.Equals(format))
{
info = ici;
break;
}
else if (System.Drawing.Imaging.ImageFormat.Png.Equals(format))
{
info = ici;
break;
}
else if (System.Drawing.Imaging.ImageFormat.Bmp.Equals(format))
{
info = ici;
break;
}
else if (System.Drawing.Imaging.ImageFormat.Tiff.Equals(format))
{
info = ici;
break;
}
else if (System.Drawing.Imaging.ImageFormat.Wmf.Equals(format))
{
info = ici;
break;
}
}
// check if we found the right encoder, otherwise use the rawformat and save
using (var stream = new MemoryStream())
{
if (info == null)
{
thumb.Save(stream, format);
}
else
{
//
// create parameters and save
System.Drawing.Imaging.EncoderParameters encParams = new System.Drawing.Imaging.EncoderParameters(1);
encParams.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
thumb.Save(stream, info, encParams);
}
stream.Seek(0, SeekOrigin.Begin);
StoreFile(stream, filePath);
image.Dispose();
}
gr.Dispose();
}
private static Boolean StoreFile(Stream fileStream, String filePath, Boolean overwriteIfExists = true)
{
if (fileStream.CanSeek) fileStream.Seek(0, SeekOrigin.Begin);
var fileWasWritten = false;
try
{
using (var stream = File.Open(filePath, FileMode.Create, FileAccess.Write))
{
if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin);
fileStream.CopyTo(stream);
}
fileWasWritten = true;
}
catch
{
return false;
}
return fileWasWritten;
}
My sample input image:Trial Image
Output Image:
I am trying to save image that format only which user image has.For Eg:If user selected image is in png format then i would like to save image in
png format only and if image is in jpg format then save image in jpg format.
I have tried code from below link but code from below link produces very bad quality image:
Reference
As the Image width is always bigger than the height this condition always is true
if (checkDimension && image.Width > image.Height)
and switches the dimensions of your result image.
If you wanted this to check for the image oriantation you could do something like:
var oriantationthumb = (thumbWidth/(float)thumbHeight) > 1;
var oriantationImage = (imageWidth/(float)imageHeight) > 1;
if(oriantationthumb != oriantationImage)
{
//exchange
}

FileLabels are not visible

I try to capture desktop screenshot using SharpDX. My application is able to capture screenshot but without labels in Windows Explorer.
I tryed 2 solutions but without change. I tried find in documentation any information, but without change.
Here is mi code:
public void SCR()
{
uint numAdapter = 0; // # of graphics card adapter
uint numOutput = 0; // # of output device (i.e. monitor)
// create device and factory
var device = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware);
var factory = new Factory1();
// creating CPU-accessible texture resource
var texdes = new SharpDX.Direct3D11.Texture2DDescription
{
CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.Read,
BindFlags = SharpDX.Direct3D11.BindFlags.None,
Format = Format.B8G8R8A8_UNorm,
Height = factory.Adapters1[numAdapter].Outputs[numOutput].Description.DesktopBounds.Height,
Width = factory.Adapters1[numAdapter].Outputs[numOutput].Description.DesktopBounds.Width,
OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None,
MipLevels = 1,
ArraySize = 1
};
texdes.SampleDescription.Count = 1;
texdes.SampleDescription.Quality = 0;
texdes.Usage = SharpDX.Direct3D11.ResourceUsage.Staging;
var screenTexture = new SharpDX.Direct3D11.Texture2D(device, texdes);
// duplicate output stuff
var output = new Output1(factory.Adapters1[numAdapter].Outputs[numOutput].NativePointer);
var duplicatedOutput = output.DuplicateOutput(device);
SharpDX.DXGI.Resource screenResource = null;
SharpDX.DataStream dataStream;
Surface screenSurface;
var i = 0;
var miliseconds = 2500000;
while (true)
{
i++;
// try to get duplicated frame within given time
try
{
SharpDX.DXGI.OutputDuplicateFrameInformation duplicateFrameInformation;
duplicatedOutput.AcquireNextFrame(miliseconds, out duplicateFrameInformation, out screenResource);
}
catch (SharpDX.SharpDXException e)
{
if (e.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
{
// this has not been a successful capture
// thanks #Randy
// keep retrying
continue;
}
else
{
throw e;
}
}
device.ImmediateContext.CopyResource(screenResource.QueryInterface<SharpDX.Direct3D11.Resource>(), screenTexture);
screenSurface = screenTexture.QueryInterface<Surface>();
// screenSurface.Map(SharpDX.DXGI.MapFlags.Read, out dataStream);
int width = output.Description.DesktopBounds.Width;
int height = output.Description.DesktopBounds.Height;
var boundsRect = new System.Drawing.Rectangle(0, 0, width, height);
var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None);
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);
bitmap.Save(string.Format(#"d:\scr\{0}.png", i));
}
// var image = FromByte(ToByte(dataStream));
//var image = getImageFromDXStream(1920, 1200, dataStream);
//image.Save(string.Format(#"d:\scr\{0}.png", i));
// dataStream.Close();
//screenSurface.Unmap();
screenSurface.Dispose();
screenResource.Dispose();
duplicatedOutput.ReleaseFrame();
}
}
After few hours of research and googling i found working solution:
From:
PixelFormat.Format32bppArgb
To:
PixelFormat.Format32bppRgb

creating a loop instead of repeating if statements

I am having trouble wrapping my head around this and wanted some input on this. So I am reading in a scanned PDF document that has a QR code in it which is always located on the top left corner of the document.
Due to the fact that scanning files might change the orientation of the document I am checking the top left corner of the document to see if it has the QR code and if not I will rotate the document and check the left corner again. Purpose of this because in the QR code is on the left top corner then the document is in proper format for my requirements.
How could I change my following code so that it gets the document checks for a QR code - if not found rotate the whole document check again and continue until the QR code has been found. Also should I just rotate by 90 in a loop rather than 90 - 180 - 270.
using (var fullImg = new Bitmap(workGif))
{
var bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, 375, 375), fullImg.PixelFormat);
Bitmap result = fullImg;
if (Process(bandImg) == null)
{
fullImg.RotateFlip(RotateFlipType.Rotate270FlipNone);
bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, result.Width, result.Height), fullImg.PixelFormat);
if (Process(bandImg) == null)
{
fullImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, result.Width, result.Height), fullImg.PixelFormat);
if (Process(bandImg) == null)
{
fullImg.RotateFlip(RotateFlipType.Rotate180FlipNone);
bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, result.Width, result.Height), fullImg.PixelFormat);
}
}
}
bandImg.Save(#"C:\NewImageTest.png");
string QRinfo = Process(bandImg);
MessageBox.Show(QRinfo);
}
Process Method
I pass the image in this method to check and see if there is a QR code to be read.
public string Process(Bitmap bitmap)
{
var reader = new com.google.zxing.qrcode.QRCodeReader();
try
{
LuminanceSource source = new RGBLuminanceSource(bitmap, bitmap.Width, bitmap.Height);
var binarizer = new HybridBinarizer(source);
var binBitmap = new BinaryBitmap(binarizer);
return reader.decode(binBitmap).Text;
}
catch (Exception e)
{
return null;
}
}
Woudn't something like this work for you? There are only four possible orientations of the document, so you have to loop at most four times. Each loop you rotate the image by 90 degrees. Once you've established that the QR code is in the top-left corner, you can break out of the loop. Then you can process the QR code or do whatever you want with it.
public void Do(string workGif)
{
// ...
string qrInfo;
using (var fullImg = new Bitmap(workGif))
{
for (int i = 0; i < 4; i++)
{
// Does the image contain a QR code?
qrInfo = Process(fullImg);
if (qrInfo = null)
// No QR code found. Rotate the image.
fullImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
else
// QR code found. Break out of the loop.
break;
}
if (qrInfo == null)
{
throw new InvalidOperationException(
"The document contains no QR code.");
}
}
MessageBox.Show(qrInfo);
// ...
}
You can move the code that takes the corner image of the source image to the Process method.
private Image GetCornerImage(Image sourceImage)
{
return sourceImage.Clone(new Rectangle(0, 0, 375, 375), sourceImage.PixelFormat);
}
public string Process(Bitmap bitmap)
{
var cornerImg = GetCornerImage(bitmap);
var reader = new com.google.zxing.qrcode.QRCodeReader();
LuminanceSource source = new RGBLuminanceSource(
cornerImg, cornerImg.Width, cornerImg.Height);
var binarizer = new HybridBinarizer(source);
var binBitmap = new BinaryBitmap(binarizer);
return reader.decode(binBitmap).Text;
}
This should work fine ;
using (var fullImg = new Bitmap(workGif))
{
var bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, 375, 375), fullImg.PixelFormat);
int i = 0;
while(Process(bandImg) == null)
{
if (i == 1)
fullImg.RotateFlip(RotateFlipType.Rotate270FlipNone);
else if (i == 2)
fullImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
else if (i== 3)
fullImg.RotateFlip(RotateFlipType.Rotate180FlipNone);
/*
Another way in which Rotation Degree can be done
First time it rotate by 270, then by 180 & then by 90
int i must be initialized with 1
int degree_to_rotate = 360 - ((4 - i) * 90)
*/
bandImg = fullImg.Clone(new System.Drawing.Rectangle(0, 0, result.Width, result.Height), fullImg.PixelFormat);
i++;
}
bandImg.Save(#"C:\NewImageTest.png");
string QRinfo = Process(bandImg);
MessageBox.Show(QRinfo);
}
If you are doing the same checks in every rotation, there is no reason not to use a loop. Just make sure you keep track of the number of rotations performed or you will be stuck in an infinite loop.

drawing a rectangle for a bitmap clone

I have a bitmap in which i clone and specify a rectangle - the current rectangle has certain width and height values which i've used for checking the rectangle for a QR code. I noticed this checks the top left corner. I would i be able to alter this to check for top right corner, bottom right and left corners of the same size(width and height)?
Bitmap result = fullImg.Clone(new System.Drawing.Rectangle(0, 0, 375, 375), fullImg.PixelFormat);
Any help is greatly appreciated.
for (int pg = 0; pg < inputDocument.PageCount; pg++)
{
string workGif = workingFilename.Replace(".pdf", string.Format(".{0}.gif", pg + 1));
GhostscriptWrapper.GeneratePageThumb(workingFilename, workGif, pg + 1, 300, 300); // size (last two params) does not seem to have any effect
using (var fullImg = new Bitmap(workGif))
{
Bitmap result = fullImg.Clone(new System.Drawing.Rectangle(0, 0, 375, 375), fullImg.PixelFormat);
string QRinfo = Process(result);
MessageBox.Show(QRinfo);
string[] qcode = QRinfo.Split('/');
string gid = qcode[qcode.Count() - 1];
Guid pgGuid = new Guid(gid);
}
}
Process Method for qr
public string Process(Bitmap bitmap)
{
var reader = new com.google.zxing.qrcode.QRCodeReader();
try
{
LuminanceSource source = new RGBLuminanceSource(bitmap, bitmap.Width, bitmap.Height);
var binarizer = new HybridBinarizer(source);
var binBitmap = new BinaryBitmap(binarizer);
return reader.decode(binBitmap).Text;
}
catch (Exception e)
{
return e.Message;
}
}
If the QRCodes are ALWAYS on the corners, you can use a picturebox for the Bitmap, and then rotate it using the RotateFlip method:
Bitmap bp = new Bitmap("myImage.jpg");
pictureBox1.Image = bp;
bp.RotateFlip(RotateFlipType.Rotate90FlipNone);
pictureBox1.Invalidate();

Clean up the surface on WaterMark of an Image

There is an image for the surface, and a text is written on the image for 184 rows of date..
Thus, it is expected to see 184 different text written image files are generated with all the same background images. (The code is declared below...)
The problem is that the first text is written for all 184 different data.. I think I have to remove something in the loop. But what is that ??
for (int i = 0; i < dt.Rows.Count; i++) {
date = Convert.ToDateTime(dt.Rows[i]["PAYMENT_DATE"]);
branchCode = Convert.ToInt32(dt.Rows[i]["BRANCH_CODE"]);
refNum = Convert.ToInt32(dt.Rows[i]["REF_NUM"]);
accountNumber = Convert.ToInt32(dt.Rows[i]["ACCOUNT_NUMBER"]);
email = dt.Rows[i]["EMAIL"].ToString();
tableCode = dt.Rows[i]["CUSTOMER_TABLE_CODE"].ToString();
TranLogKey logKey = new TranLogKey(date, branchCode, refNum);
TranLogEntry entry = Log.SelectLogEntry(logKey, false);
if (Intertech.Core.Framework.Context.CurrentContext.LogEntry == null)
Intertech.Core.Framework.Context.CurrentContext.LogEntry = entry;
try {
receiptText = TransactionManager.GenerateReceipt(true, logKey, null, null, accountNumber, false);
}
catch (Exception exp) {
continue;
}
if (receiptText != null) {
if (receiptText.IndexOf("SURETTİR\r\n") != -1)
receiptText = receiptText.Substring(receiptText.IndexOf("SURETTİR\r\n") + 10).Trim();
if (receiptText.IndexOf("İşlemi Yapan") != -1)
receiptText = receiptText.Substring(0, receiptText.IndexOf("İşlemi Yapan"));
if (receiptText.IndexOf("MÜŞTERİ İMZASI") != -1)
receiptText = receiptText.Substring(0, receiptText.IndexOf("MÜŞTERİ İMZASI"));
Bitmap bmp = (Bitmap)Bitmap.FromFile(imageDir);
Graphics g = Graphics.FromImage(bmp);
SizeF size;
Font font = new Font("Courier New", 8, FontStyle.Regular);
byte ALPHA = 200;
size = g.MeasureString(receiptText, font);
Bitmap waterbmp = new Bitmap((int)size.Width, (int)size.Height);
Graphics waterg = Graphics.FromImage(waterbmp);
waterg.DrawString(receiptText, font, new SolidBrush(System.Drawing.Color.Black), 2, 2);
DrawWatermark(ref waterbmp, ref bmp, LeftIndex, TopIndex, ALPHA);
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
try {
GoServices.Core.SendMailOutside("The Portugal Life", "info#portugal.tr.friendship.pt",
"blgnklc#skype-account.com", " e-Wish " + email, "", new string[] { "dekont.jpg" }, new object[] { ms.ToArray() });
LogNotificationState("K", refNum, accountNumber, 2, true, null, tableCode);
}
catch (Exception ex) {
LogNotificationState("K", 0, -1, 2, false, ex, tableCode);
}
}
private static void DrawWatermark(ref Bitmap watermark_bm, ref Bitmap result_bm, int x, int y, byte ALPHA) {
System.Drawing.Color clr;
int py, px;
for (py = 0; py <= watermark_bm.Height - 1; py++) {
for (px = 0; px <= watermark_bm.Width - 1; px++) {
clr = watermark_bm.GetPixel(px, py);
if (clr.A != 0 || clr.R != 0 || clr.G != 0 || clr.B != 0)
watermark_bm.SetPixel(px, py, System.Drawing.Color.FromArgb(ALPHA, clr.R, clr.G, clr.B));
}
}
Graphics gr = Graphics.FromImage(result_bm);
gr.DrawImage(watermark_bm, x, y);
}
I would look at how you are creating the bitmap.
Bitmap bmp = (Bitmap)Bitmap.FromFile(imageDir);
does this line need to be in there everytime, i.e is imagedir the same all the time?
Do you dispose of the generated bitmap after creating it?
what happens in this function:
DrawWatermark(ref waterbmp, ref bmp, LeftIndex, TopIndex, ALPHA);
You seem to then save the bmp file but not dispose of it?
I have seen some strange behaviour from GDI+ so I would start here.

Categories

Resources