Reading QR code in Xamarin Forms With Zxing - c#

I am trying to import a QR code from a .png file and decode it using Zxing.Net.Mobile and ZXing.Net.Mobile.Forms.
If I scan the QR code using the ZXing.Mobile.MobileBarcodeScanner class, the decoding works as required, however, when importing it from a file, the Qr code reader (ZXing.QrCode.QRCodeReader()) decode function always returns null.
As I'm using Xamarin Forms; each platform handles the bitmap/image creation and the portable part handle the rest (Zxing BinaryBitmap creation and decoding).
//Store rawBytes and image demensions
PotableBitmap bMap = DependencyService.Get<IBitmap>().FileToBitmap(filePath);
RGBLuminanceSource source = new RGBLuminanceSource(bMap.RgbBytes, bMap.Width, bMap.Height, RGBLuminanceSource.BitmapFormat.RGB32);
HybridBinarizer binarized = new HybridBinarizer(source);
BinaryBitmap bitmap = new BinaryBitmap(binarized);
var reader = new ZXing.QrCode.QRCodeReader();
data = reader.decode(qrCodeBitmap); // This is always null
The DependencyService will call the platform specific function, at the moment I am working with Andorid so, the function is as follows:
public PortableBitmap FileToBitmap(string ms)
{
var bytes = File.ReadAllBytes(ms);
Android.Graphics.Bitmap bMap = BitmapFactory.DecodeByteArray(bytes, 0, bytes.Length);
int[] intArray = new int[bMap.Width * bMap.Height];
bMap.GetPixels(intArray, 0, bMap.Width, 0, 0, bMap.Width, bMap.Height)
List<byte> result = new List<byte>();
foreach (int intRgb in intArray)
{
Color pixelColor = new Color(intRgb);
result.Add(pixelColor.R);
result.Add(pixelColor.G);
result.Add(pixelColor.B);
}
return new PortableBitmap(result.ToArray(), bMap.Width, bMap.Height);
}
I have looked through some of the posts on SO that are having the same problem and have tried the following:
Using BitmapLuminanceSource: still returns null and requires the use of another library
Using different bitmap formats for the RGBLuminanceSource: RGB32, BGR32, ARGB32, ABGR32 (each time changing the FileToBitmap function)
Tried the different Binarizer, GlobalHistogramBinarizer()
Checked that the file is being read correctly by reading and wrinting it back to a file.
I have tried using the MultiFormatReader() with the Pure barcode and try harder hints
I have also debugged the libraries source code and from what I understand it just can't find the QR code in the imported image. No exception is thrown.
Here is where the return null is made:
private FinderPattern[] selectBestPatterns()
{
int startSize = possibleCenters.Count;
if (startSize < 3)
{
// Couldn't find enough finder patterns
return null; // It returns here
}
...
The online Zxing decoder can decode the QR code I'm testing correctly. Here is my test QR code:

I solved that problem, with this method in the Android implementation to return an RGBLuminanceSource from the path of the image
public RGBLuminanceSource GetRGBLuminanceSource(string imagePath)
{
if (File.Exists(imagePath))
{
Bitmap bitmap = BitmapFactory.DecodeFile(imagePath);
List<byte> rgbBytesList = new List<byte>();
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
var c = new Color(bitmap.GetPixel(x, y));
rgbBytesList.AddRange(new[] { c.A, c.R, c.G, c.B });
}
}
byte[] rgbBytes = rgbBytesList.ToArray();
return new RGBLuminanceSource(rgbBytes, bitmap.Height, bitmap.Width, RGBLuminanceSource.BitmapFormat.ARGB32);
}
return null;
}

Related

How to query the bit depth of a PNG?

I have a PNG file which has 8-bit color depth as evidenced by file properties:
Yes, when I open the file
var filePath = "00050-w600.png";
var bitmap = new Bitmap(filePath);
Console.WriteLine(bitmap.PixelFormat);
I get Format32bppArgb. I also looked in the PropertyIdList and PropertyItems properties but didn't see anything obvious.
So how do I extract the Bit Depth from the PNG?
P.S. None of the framework methods seem to work. System.Windows.Media.Imaging.BitmapSource might work but it's only in WPF and .NET Core 3. I need this for .NET 4.x and .NET Core 2.x.
P.P.S. I just needed to know whether the PNG is 8 bit or not, so I wrote a sure fire method to check if anyone needs it - should work in any framework.
public static bool IsPng8BitColorDepth(string filePath)
{
const int COLOR_TYPE_BITS_8 = 3;
const int COLOR_DEPTH_8 = 8;
int startReadPosition = 24;
int colorDepthPositionOffset = 0;
int colorTypePositionOffset = 1;
try
{
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
fs.Position = startReadPosition;
byte[] buffer = new byte[2];
fs.Read(buffer, 0, 2);
int colorDepthValue = buffer[colorDepthPositionOffset];
int colorTypeValue = buffer[colorTypePositionOffset];
return colorDepthValue == COLOR_DEPTH_8 && colorTypeValue == COLOR_TYPE_BITS_8;
}
}
catch (Exception)
{
return false;
}
}
Color Allowed Interpretation
Type Bit Depths
0 1,2,4,8,16 Each pixel value is a grayscale level.
2 8,16 Each pixel value is an R,G,B series.
3 1,2,4,8 Each pixel value is a palette index;
a PLTE chunk must appear.
4 8,16 Each pixel value is a grayscale level,
followed by an alpha channel level.
6 8,16 Each pixel value is an R,G,B series,
followed by an alpha channel level.

C# check images are equal with tolerance

I have this code where I send images from a thermal camera. getImage() returns the actual image that is provided by the camera. There is no possibility to check directly if the camera can provide a 'new' image, so I did this method to compare two images:
class ImageCompare
{
public enum CompareResult
{
CompareOK,
SizeMismatch,
PixelMismatch
};
public static CompareResult CompareImages(Image i1, Image i2)
{
CompareResult cr = CompareResult.CompareOK;
if (i1.Size != i2.Size)
{
cr = CompareResult.SizeMismatch;
}
else
{
ImageConverter ic = new ImageConverter();
byte[] btImage1 = new byte[1];
btImage1 = (byte[])ic.ConvertTo(i1, btImage1.GetType());
byte[] btImage2 = new byte[1];
btImage2 = (byte[])ic.ConvertTo(i2, btImage2.GetType());
//compute hashes
SHA256Managed shaM = new SHA256Managed();
byte[] hash1 = shaM.ComputeHash(btImage1);
byte[] hash2 = shaM.ComputeHash(btImage2);
for (int i = 0; i < hash1.Length && i < hash2.Length
&& cr == CompareResult.CompareOK; i++)
{
if (hash1[i] != hash2[i])
cr = CompareResult.PixelMismatch;
}
}
return cr;
}
}
and here is how I use this class:
private static void HandleImageSending(Socket client, Socket s)
{
int sent;
int imageCount = 0;
long totalSize = 0;
try
{
while (true)
{
Console.WriteLine("Starting sending...");
Image old = getImage();
byte[] bmpBytes;
using (Image bmp = getImage())
using (MemoryStream ms = new MemoryStream())
{
if (ImageCompare.CompareImages(bmp, old) == ImageCompare.CompareResult.CompareOK)
{
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
bmpBytes = ms.ToArray();
sent = SendVarData(client, bmpBytes);
imageCount++;
totalSize += sent;
old = bmp;
}
}
}
}
catch (Exception e)
{ ... }
So my problem is that comparing by hash results in
'different' images in about 19 of 20 cases. Since the camera provides only 8 fps, there must be something wrong.
Is there a posibilty of comparing with a kind of tolerance, so maybe lets say 5 or 10 percent of the compared new image may differ to the old?
Since this is used on a mini PC, I would like to use as less CPU load as possible.
Is there anyone who can help me out here?
indexing the image (and decreasing the size) should give the same result for similar images
using
Bitmap imgtarget = imgsource.Clone(
new Rectangle(0, 0, imgsource.Width, imgsource.Height),
PixelFormat.Format8bppIndexed);
from another stackoverflow

Using TiffBitmapEncoder with Gray32Float

I'm trying to create a 32 BPP gray scale tiff using this code which I found on MSDN
BitmapSource image = BitmapSource.Create(
width,
height,
96,
96,
PixelFormats.Gray32Float,
null,
pixels,
stride);
FileStream stream = new FileStream("test file.tif", FileMode.Create);
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Compression = TiffCompressOption.None;
var bitmapFrame = BitmapFrame.Create(image);
encoder.Frames.Add(bitmapFrame);
encoder.Save(stream);
The file gets created and the image looks correct when I open it, but the file properties says that it is a 16 BPP (0-65536) image not a 32 bit floating point as specified by the Gray32Float parameter.
I've confirmed the file format is 16 BPP by looking at the file properties in windows explorer and by opening the file in ImageJ
I can create 32 BPP tiffs in Paint.Net and ImageJ, to confirm that format is supported.
Anyone know why the .Net TiffBitmapEncoder is creating the wrong type?
Under the hood, .Net uses the Windows Imaging Component (WIC). WIC supports reading of TIFFs in Gray32Float (GUID_WICPixelFormat32bppGrayFloat in WIC) but not writing. Take a look at the WIC Native Pixel Formats Overview. I had the same experience discovering the image was written as Gray16.
This is very frustrating. I've been attempting to writes some scientific data using Gray32Float, but I have not been successful.
Old question, but I tried, and almost made it, but still - doesn't work correctly:
What I have here is a solution which saves as 32bit, using TiffLib, but the value range is somehow not correct.
I save an image in float range of -0.5 to 3, and imageJ reads it as 32 bit, BUT the range is ~-1000K to ~3000K...
I tried using TiffLib adding the following functions:
public static void Write32BitTiff_(string path, int W, int H, float[] data, ref byte[] FileData, int numPage = 0)
{
var numBytes = sizeof(float);
var size = H * W * numBytes;
byte[] arr = null;
arr = new byte[size];
var ctr = 0;
byte[] floatVal;
for (int i = 0; i < size; i += numBytes)
{
try
{
float val = data[ctr++];
floatVal = BitConverter.GetBytes(val);
for (int j = 0; j < numBytes; j++)
arr[i + j] = floatVal[j];
}
catch (IndexOutOfRangeException)
{
break;
}
catch (Exception eee) { }
}
Tiff t = openTiff(path, W, H, numPage, numBytes * 8);
t.WriteRawStrip(0, arr, size);
t.Close();
t.Dispose();
}
Where "OpenTiff" looks like this:
private static Tiff openTiff(string path, int W, int H, int pageNum, int numBits, bool overrideFile = false)
{
Tiff t;
int numberOfPages;
if (!File.Exists(path) || overrideFile )
{
t = Tiff.Open(path, "w");
numberOfPages = 1;
}
else
{
var start = DateTime.Now;
t = Tiff.Open(path, "a");
numberOfPages = t.NumberOfDirectories() + 1; ;
numberOfPages = (pageNum > numberOfPages) ? pageNum : numberOfPages;
}
t.SetField(TiffTag.IMAGEWIDTH, W);
t.SetField(TiffTag.IMAGELENGTH, H);
const int NUM_CHANNELS = 1;//for RGB set 3. for ARGB set 4, not sure supported.
t.SetField(TiffTag.SAMPLESPERPIXEL, NUM_CHANNELS);
t.SetField(TiffTag.BITSPERSAMPLE, numBits);
t.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);
t.SetField(TiffTag.SUBFILETYPE, FileType.PAGE);
t.SetField(TiffTag.PAGENUMBER, pageNum, numberOfPages);
t.SetDirectory((short)pageNum);
}
So if this might help someone, or if someone could find the "bug" with it - this would be great!

Easiest way to read 2-channel samples into array from WaveStream

I've been struggling with this for quite some time now and I couldn't find a working solution.
I have a wav file (16 bit PCM: 44kHz 2 channels) and I want to extract samples into two arrays for each of the two channels. As far as I know the direct method for this does not exist in NAudio library, so I tried to run the following code to read a few of interlaced samples but the buffer array stays empty (just a bunch of zeros):
using (WaveFileReader pcm = new WaveFileReader(#"file.wav"))
{
byte[] buffer = new byte[10000];
using (WaveStream aligned = new BlockAlignReductionStream(pcm))
{
aligned.Read(buffer, 0, 10000);
}
}
Any help on this will be much appreciated.
BlockAlignReductionStream is unnecessary. Here's one simple way to read out of your buffer and into separate 16 bit left and right sample buffers.
using (WaveFileReader pcm = new WaveFileReader(#"file.wav"))
{
int samplesDesired = 5000;
byte[] buffer = new byte[samplesDesired * 4];
short[] left = new short[samplesDesired];
short[] right = new short[samplesDesired];
int bytesRead = pcm.Read(buffer, 0, 10000);
int index = 0;
for(int sample = 0; sample < bytesRead/4; sample++)
{
left[sample] = BitConverter.ToInt16(buffer, index);
index += 2;
right[sample] = BitConverter.ToInt16(buffer, index);
index += 2;
}
}

How to display TIFF (in form of Byte[]) on Silverlight Image control

I created a window service to put all of my TIFF files into database and stored them as Byte[].
Now I want to be able to display them through Silverlight Image control
So i use the Converter during binding XAML in order to convert the Byte[] to Bitmap because the Image.Source only accept eitheir URI (I don't have the file stored on server so can't use this method) or Bitmap.
BitmapImage bmi = new BitmapImage();
if (value != null)
{
ImageGallery imageGallery = value as ImageGallery;
byte[] imageContent = imageGallery.ImageContent;
string imageType = imageGallery.ImageType;
using (MemoryStream ms = new MemoryStream(imageContent))
{
bmi.SetSource(ms);
}
}
return bmi;
However, I get the exception at bmi.SetSource(ms) because Silverlight only supports JPEG and PNG images.
So I did more research and knew that i should convert the bytes of TIFF to bytes of JPEG or PNG then it will work.
To do that I tried two methods:
Doing the conversion on server: in my RIA service call, after retrieving the ImageGallery, I loop through the available image to convert the bytes of TIFF to the bytes of JPEG.
BUT IT DOESN'T WORK....
Can you tell me where I did wrong?
public IQueryable<ImageGallery> GetImageGalleries()
{
var imageGalleries = this.ObjectContext.ImageGalleries.OrderBy(i=>i.ImageName);
foreach (ImageGallery imageGallery in imageGalleries)
{
if (imageGallery.ImageType == ".tif" || imageGallery.ImageType == ".tiff")
{
//Convert the Tiff byte array format into JPEG stream format
System.Drawing.Bitmap dImg = new System.Drawing.Bitmap(new MemoryStream(imageGallery.ImageContent));
MemoryStream ms = new MemoryStream();
dImg.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
//then convert the JPEG stream format into JPEG byte array format
byte[] buf = new byte[ms.Length];
ms.Read(buf, 0, buf.Length);
//Changing the format tiff byte[] of ImageGallery to jpeg byte[]
imageGallery.ImageContent = buf;
}
}
return imageGalleries;
}
The other solution is to use LibTiff.Net library to convert directly the Byte[] of TIFF to WritableBitmap directly on Silverlight.
However, after digging through their sample application or using Reflector to see the source code functions, I still can't figure out how to use their library to convert the bytes of TIFF to WritableBitmap JPEG (or PNG) because their sample only show the API for using the search the TIFF in a file directory. In my case, I don't have an existing file on server.
Can someone help me how to show the TIFF file on Image control of Silverlight?
I searched the forum but didn't find any solid answer for this.
thanks
I think the LibTiff will be the way to go. Ulitmately the Tiff.ClientData accepts a Stream that is the tiff data. If your tiff data really is a byte[] then you just need a MemoryStream around it. More likely at some point the byte[] is pulled from a stream so you probably don't even need this intermedatory byte[] / MemoryStream.
Reference LibTiff.net
Add this class:
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Media.Imaging;
using BitMiracle.LibTiff.Classic;
namespace CoreTechs.X9
{
public static class TiffUtility
{
public static Tiff CreateTiff(this byte[] bytes)
{
MemoryStream ms = new MemoryStream(bytes);
Tiff tiff = Tiff.ClientOpen("in-memory", "r", ms, new TiffStream());
return tiff;
}
public static IEnumerable<WriteableBitmap> ConvertToWriteableBitmaps(this Tiff tiff)
{
if (tiff == null)
throw new ArgumentNullException("tiff", "tiff is null.");
short dirs = tiff.NumberOfDirectories();
for (int i = 0; i < dirs; i++)
{
if (tiff.SetDirectory((short)i))
{
int tileCount = tiff.NumberOfTiles();
int stripCount = tiff.NumberOfStrips();
var frameWidthField = tiff.GetField(TiffTag.IMAGEWIDTH);
var frameHeightField = tiff.GetField(TiffTag.IMAGELENGTH);
var compressionField = tiff.GetField(TiffTag.COMPRESSION);
var xResolutionField = tiff.GetField(TiffTag.XRESOLUTION);
var yResolutionField = tiff.GetField(TiffTag.YRESOLUTION);
var samplesPerPixelField = tiff.GetField(TiffTag.SAMPLESPERPIXEL);
int frameWidth = frameWidthField != null && frameWidthField.Length > 0 ? frameWidthField[0].ToInt() : 0;
int frameHeight = frameHeightField != null && frameHeightField.Length > 0 ? frameHeightField[0].ToInt() : 0;
var compression = compressionField != null && compressionField.Length > 0 ? (Compression)compressionField[0].Value : Compression.NONE;
var xResolution = xResolutionField != null && xResolutionField.Length > 0 ? new double?(xResolutionField[0].ToDouble()) : null;
var yResolution = yResolutionField != null && yResolutionField.Length > 0 ? new double?(yResolutionField[0].ToDouble()) : null;
var samplesPerPixel = samplesPerPixelField != null && samplesPerPixelField.Length > 0 ? samplesPerPixelField[0].ToString() : String.Empty;
if (xResolution != null && yResolution == null)
{
yResolution = xResolution;
}
var buffer = new int[frameWidth * frameHeight];
tiff.ReadRGBAImage(frameWidth, frameHeight, buffer);
var bmp = new WriteableBitmap(frameWidth, frameHeight);
for (int y = 0; y < frameHeight; y++)
{
var ytif = y * frameWidth;
var ybmp = (frameHeight - y - 1) * frameWidth;
for (int x = 0; x < frameWidth; x++)
{
var currentValue = buffer[ytif + x];
// Shift the Tiff's RGBA format to the Silverlight WriteableBitmap's ARGB format
bmp.Pixels[ybmp + x] = Tiff.GetB(currentValue) | Tiff.GetG(currentValue) << 8 | Tiff.GetR(currentValue) << 16 | Tiff.GetA(currentValue) << 24;
}
}
yield return bmp;
}
}
}
}
}
Use the exension methods like this:
byte[] myHappyTiffData = GetMyTiffBytesFromSomewhere();
WriteableBitmap bmp = myHappyTiffData.CreateTiff().ConvertToWriteableBitmaps().FirstOrDefault();
myImageControl.Source = bmp;
We began with LibTiff as a solution for our media manager. I wouldn't recommend it.
As you can see it creates a WriteableBitmap for each page. WB is the most performance hampering, leaking object you can use in Silverlight, so if you got more then 1 single page tiff your app will run out of memory faster then you can say Avada Kedavra.
There are viewers that appearently can load a large multipage tiff without killing your app (and browser and computer), for a decent license fee, but at this point I got nothing that allows you to decode a tiff an extract the pages.
Runner ups:
http://www.accusoft.com/
http://www.atalasoft.com/products/dotimage

Categories