I can't get this working with Unity -- Any suggestions or demos?

Sep 19, 2012 at 1:45 PM
Edited Sep 19, 2012 at 1:45 PM

I'd like to be able to encode and decode QR and Barcodes using this library, and while encoding works great, I can't get decoding to work at all, even when plugging a newly encoded QRcode into it.

Here's my code:

public Texture2D encoded;
public string Text;

void Start () {
	encoded = new Texture2D(256,256); //create texture
}

void Update () {
	

        //Encode QR Code
	ZXing.Common.BitMatrix bm = (new ZXing.QrCode.QRCodeWriter().encode(Text,BarcodeFormat.QR_CODE,256,256));
	for(int y = 0 ; y < bm.Height ; y ++){
		for(int x = 0 ; x < bm.Width ; x ++){
			bm.flip(x,y);
		}
	}
	
	Color32[] col = new Color32[ bm.Width * bm.Height ];
			
	for(int y = 0 ; y < bm.Height ; y ++){
		ZXing.Common.BitArray ba = bm.getRow(y,null);
		int[] bits = ba.Array;
		
		for( int x = 0 ; x < bits.Length ; x++ ){
			for(int i = 0 ; i < 32 ; i ++){

				int bit = (bits[x] >> i) & 1;
				
				col [ 256 * y + x * 32 + i ] = new Color32((byte)(255 * bit),(byte)(255 * bit),(byte)(255 * bit), 255);
				//col [ 256 * y + x * 32 + i ] = new Color32(255,0,0, 255);
				
			}
		}
		
	}
	
	encoded.SetPixels32(col);
	encoded.Apply(); //Texture now displays QR Code upside down
	
	
	//DECODE
	try{
		//convert to rgb array
		byte[] bcol = new byte[256 * 256 * 3];
		
		for(int i = 0 ; i < 256*256 ; i += 3 ){
			
			bcol[3*i] = col[i].r;//(byte)(( col[i].r + col[i].g + col[i].g + col[i].b ) >> 2 );
			bcol[3*i+1] = col[i].g;
			bcol[3*i+2] = col[i].b;
		}
		
		
		BarcodeReader br = new BarcodeReader();
		print(br.Decode(bcol, 256, 255)); //this returns null
		
		
		RGBLuminanceSource ls = new RGBLuminanceSource(bcol, 256, 256);
		ZXing.Common.HybridBinarizer hb = new ZXing.Common.HybridBinarizer( ls );

		print(new ZXing.QrCode.QRCodeReader().decode(new BinaryBitmap(hb)).BarcodeFormat); //this returns null
		

	}catch(ZXing.ReaderException e){
		print("Fail");
	}
}

So when decoding the QR Code, the decode functions both return null when I'm expecting an ZXing object -- "Fail" is never printed.

Am I missing something? Do I need to add something else? Are there any demos of this dll working with a texture that I could take a look at?

Thanks,

G

Coordinator
Sep 19, 2012 at 2:18 PM

You can find a unity demo client with webcam access in the source code repository:
https://zxingnet.svn.codeplex.com/svn/trunk/Clients/UnityDemo

In your example I don't understand the meaning of "bm.flip(x,y);". For what is it? Do you want to flip the bitmap? First line should be last line after that?

If so you have to flip it back before decoding. Or you have to set AutoRotate to true (BarcodeReader).

Can you provide a full unity example which I can debug on my maschine?

 

 

Btw. I removed your double post.


 

 

 

Sep 19, 2012 at 3:37 PM

Thanks for your fast response - sorry about the double post, my internet was slow and I didn't know it went through.

"bm.flip(x,y)" -- This flips every bit in the bitmatrix, ie 1 -> 0. The QR code was inverted from what I expected (black background, white code), so I inverted the matrix to have a white background and black code. There are obviously better ways to do it now that I look at it again, but either way I've removed that portion. So the image is not being flipped or rotated in any way after being encoded, and the problem persists.

 

Here is the entirety of the class that I wrote:

using UnityEngine;
using System.Collections;

using ZXing;

public class QRTest : MonoBehaviour {
	
	public Texture2D encoded; //texture with encoded QR code
	public string Text = "http://www.google.com/"; //text encoded to the qr code
	
	//Create the texture
	void Start () {
		encoded = new Texture2D(256,256);
	}
	
	//Encode and decode the barcode
	void Update () {
		
		/* ENCODE */
		//get the bit matrix for the QR code
		ZXing.Common.BitMatrix bm = (new ZXing.QrCode.QRCodeWriter().encode(Text,BarcodeFormat.QR_CODE,256,256));
		Color32[] col = new Color32[ bm.Width * bm.Height ];
		
		//fill the color array with values from the bitmatrix
		for(int y = 0 ; y < bm.Height ; y ++){ // row
			//get the row of bits
			ZXing.Common.BitArray ba = bm.getRow(y,null);
			int[] bits = ba.Array;
			
			//write each bit in the row to a color
			for( int x = 0 ; x < bits.Length ; x++ ){ // column
				for(int i = 0 ; i < 32 ; i ++){
					
					int bit = (bits[x] >> i) & 1;
					col [ 256 * y + x * 32 + i ] = new Color32((byte)(255 * bit),(byte)(255 * bit),(byte)(255 * bit), 255);	
					
				}
			}
		}
		
		//write the colors to the texture
		encoded.SetPixels32(col);
		encoded.Apply();
		
		/* DECODE */
		try{
			
			//3 bytes for each color
			byte[] bcol = new byte[256 * 256 * 3];
			 
			//cycle through the color array created before and fill in the R,G,B values
			for(int i = 0 ; i < 256*256 ; i += 3 ){
				
				bcol[3*i] = col[i].r;//(byte)(( col[i].r + col[i].g + col[i].g + col[i].b ) >> 2 );
				bcol[3*i+1] = col[i].g;
				bcol[3*i+2] = col[i].b;
			}
			
			//try to decode using the general barcode decoder
			BarcodeReader br = new BarcodeReader();
			print ("Barcode :");
			print(br.Decode(bcol, 256, 256)); //prints null
			
			//try to decode using the QR code decoder
			RGBLuminanceSource ls = new RGBLuminanceSource(bcol, 256, 256);
			ZXing.Common.HybridBinarizer hb = new ZXing.Common.HybridBinarizer( ls );
			print ("QRCode :");
			print( new ZXing.QrCode.QRCodeReader().decode(new BinaryBitmap(hb))); //prints null
			
		}catch{
			print("Fail");
		}
	}
}

The only other thing in the project is your ZXing.Unity.dll, .pdb, and .xml provided on this repo (though I think only the dll is needed). I just attach the component to the main camera and it tries to encode/decode every frame.

"Text" is the string that it encodes into the QR code and "encoded" is the texture that it writes the QR code to, so you can see and edit both in the editor.

 

Thanks again for taking a look at this 

Coordinator
Sep 19, 2012 at 8:02 PM

Please try the following changes:

  • generate a non-inverted barcode image (instead of using the flip method)
    int bit = (bits[x] >> i) & 1;  ---->  int bit = ((bits[x] >> i) & 1) ^ 1;
  • correct calculation of the byte array for the decoder
             //cycle through the color array created before and fill in the R,G,B values
             for (int i = 0; i < 256 * 256; i+=3)  <--- i+=3 is wrong
             {
                bcol[3 * i] = col[i].r;//(byte)(( col[i].r + col[i].g + col[i].g + col[i].b ) >> 2 );
                bcol[3 * i + 1] = col[i].g;
                bcol[3 * i + 2] = col[i].b;
             }
    ---->
             //cycle through the color array created before and fill in the R,G,B values
             for (int i = 0; i < 256 * 256; i++)
             {
                bcol[3 * i] = col[i].r;//(byte)(( col[i].r + col[i].g + col[i].g + col[i].b ) >> 2 );
                bcol[3 * i + 1] = col[i].g;
                bcol[3 * i + 2] = col[i].b;
             }

Additional you can take a look of the classes Color32LuminanceSource and Color32BarcodeReader which I wrote for unity support in the unity demo client I mentioned above. With that classes decoding is reduced to a two-liner:

      var barcodeReader = new Color32BarcodeReader();
      var result = barcodeReader.Decode(c, W, H);

You only have to be carefully with the source Color32 array. Unity gives a vertically flipped image via webcam which Color32LuminanceSource automatically corrects. Your encoded barcode isn't vertically flipped.
In the future I will provide a renderer for Color32 images. The encoding of barcodes are then as easy as deoding.

Coordinator
Sep 19, 2012 at 8:06 PM

I looked at the encoded barcode in unity and this is vertically flipped, too. So you should change your encoding method in a way that it renders the Color32 from bottom to top. If you do so you will see a correct QRCode and you can use the mentioned Color32 classes from the demo.

Coordinator
Sep 19, 2012 at 8:50 PM

Now I added the classes Color32BarcodeWriter and Color32Renderer to the unity demo client.
If you use the classes you can now write the following if you want to encode something:

   void Update()
   {
      var color32 = Encode(Text, encoded.width, encoded.height);
      encoded.SetPixels32(color32);
      encoded.Apply();
   }

   private static Color32[] Encode(string textForEncoding, int width, int height)
   {
      var writer = new Color32BarcodeWriter
      {
         Format = BarcodeFormat.QR_CODE,
         Options = new QrCodeEncodingOptions
         {
            Height = height,
            Width = width
         }
      };
      return writer.Write(textForEncoding);
   }

Coordinator
Sep 19, 2012 at 9:13 PM
Edited Sep 19, 2012 at 9:13 PM

To be complete the unity demo client in the repository shows working sample code for you question now.

Coordinator
Sep 20, 2012 at 7:59 PM

Next version of ZXing.Net will have Color32 support built in. That means BarcodeReader can use Color32 arrays directly and BarcodeWriter will return a Color32 array.

Sep 20, 2012 at 8:20 PM

Wow, dumb mistake on my part, it was the i += 3 issue. Thanks again for helping me with this.

Apr 14, 2014 at 8:16 AM
I tried the latest example for Unity3d, which is basically the same discussed here but I have two problems

1) no barcode is recnognized no matter how I show it. The weird stuff is that if I take a picture of the barcode from the same camera and use ZXing routine offline, then it recognizes it.

2) when I deploy it on IOS or Android the screen orientation is messed up as the camera would rotate the input. For instance, if the cell is in portrait, the image is shown as if it was taken in landscape.

I cannot get out of this mess and I used the code as it is ... :( Help!
May 29, 2014 at 4:27 PM
I am prone to use free solutions since many exist.

PL

Sent from my iPad