[Solved] display images\QR codes on a 3.2 tft screen

hi guys

Im trying to display bitmap images on a itead3.2s screen. i have the shield and a mega and i just cant seem to display images on it correctly and the images when i do convert them with imageconverter565 they are too large for global variables.

im looking for a way to send a image via serial and display it . does anyone have any knowledge on how this can be done.

thanks in advance

Sending 150Kb of image(320*240) would be painfully slow, have you not considered using the SD slot on the back of the display and put your images on SD card? If you do, I have a library which can draw full screen images quite quickly.

Regards,

Graham

I made an addon to the UTFT library to display images in a custom compressed format. It's perfect for small graphics like buttons or whatever. The images are converted to this format with Paint.NET with the help of a custom plugin (which can also be used as an alternative to ImageConverter565).

If you are interested, I will have to fix 2, 3 things before I can give it to you (it's been like 2 years since I made that and it's not really ready..) :wink:

i cant use the sd card, as like i said i need to be able to send the image in byte format across serial, so im using c# to make a windows app that can send images to the arduino via serial and display it on screen, thats the idea so sd card wont be a viable route.

Guix you dont have a addon for utft that can write just plain byte[] data to screen by any chance ;).

im actually trying to get a qr code on screen to be exact but i generate the qr's on windows app and send over serial to arduino then hopefully onto screen, so the image is converted into a byte[] and sent to the arduino.

any ideas on achieving this, ive spent many hours trying to figure out how to get a qr code image converted and displayed onto the lcd.

also the image size on average is about 2.5kb for most of the generated qr codes.

but for some reason when i use 565converter they become huge 160 000 byte images??

To start with, there is no way you are ending up with 160,000 byte files! At most 3202402=153600!!

And since it is my understanding QR codes are square, that should be 2402402=115,200 bytes MAXIMUM....

So I just downloaded a couple of QR codes, they are only 120*120, which gives me 28,800 bytes when converted using UTFT imageconverter565, so the question has to be asked, what are YOU doing?

Regardless of your shortcomings using the converter I will have a think if my library can be converted to accept serial input.....

Regards,

Graham

EDIT: I hope guix can help you, because my library don't appear to like serial :frowning: sorry

If you want to use QR codes only, then it should be pretty easy and fast to send by serial, considering it's only a few pixels that can only have 2 colors so can be coded with only 1 bit per pixel... A QR code of medium size (29*29) = 841 bits = 106 bytes. The hardest part will be to write a function in your sketch to draw squares instead of pixels, but that shouldn't be too hard either :wink:

okay so heres the deal , i used a 290 x 290 which gave me the 168 200 bytes. which i know is the wrong size, but its just the one i was using as a sample. then i also used a 40 x 40 which then i tried to display.

also the converter generates this type :

const unsigned short char30[0x900] PROGMEM

now how to i use this with the utft drawBitmap function, it complains about converting from const unsigned short int* to a unsigned int*.

and if i change the type to this:

unsigned int char30[0x900]

i get a corrupted image on screen so how do i use this then?

so guix , your suggesting writing a method which draws out the qr code bit for bit in a for loop basicly, correct?

is there no simpler way of just converting a bitmap to byte[] in c# code and then sending over serial and storing it in a byte[] in arduino and drawing to tft with a quick library where you just pass the raw array into it?

i know i managed to get this working with a nokia 5110 lcd, i sent the byte via serial and stored in a int[] i think and sent that into a draw function provided by the lcd library and that worked out fine and displayed only issue was the resolution of the lcd was to low so qr code density was a issue, i could only store a few characters?

Create a new tab in the IDE called char30.c, paste in the array definition using type const unsigned short char30[0x900] PROGMEM

Then in your main sketch, use the line

extern unsigned int char30[0x900];

Regards,

Graham

jaydeeSale:
is there no simpler way of just converting a bitmap to byte[] in c# code and then sending over serial and toring it in a byte[] in arduino and drawing to tft with a quick library where you just pass the raw array into it?

Yes, I am no star programmer but even I wrote a bitmap to raw converter in C using visual studio so I don't see why you can't do that as part of your app.

Regards,

Graham

Edit: Or you could 'cheat' and just call Henning's command line version of the converter which handles most image formats you can throw at it :wink:

HA! So it niggled me that I couldn't get my library to deal with Serial input, I don't like stuff beating me :disappointed_relieved:

It is not fully 'automated' (yet), but I have a working draw routine that takes it's input from Serial!! :grin: :wink: @460800 baud, using a 120*120 (28,800 bytes) raw image takes just about 1s to draw, across DUE Native port 660ms, I think that is quite acceptable :slight_smile:

I have a problem, IF we just randomly select any old raw file which does not contain dimensions, would it be possible to deduce it somehow? What I mean is, if the image is square, we can calculate x and y as the sqrt of the image size / 2, but what if the image is not square? What assumptions can we make? I might be being a bit dense but I can't think how this might be possible....

Are you using AVR or ARM based board?

Regards,

Graham

You said you generate the QR to .bmp. If I were you I would instead generate the QR as a serie of bits, where a bit set mean white dot and unset mean black dot.

This is a 29*29 qr code found on wikipedia,

that I converted as described above:

80 BF 25 C0 57 DA F5 89 DA 90 22 51 5D 55 24 0A
61 8B 7C 49 73 1F A0 AA 0A F8 AF E3 FF 1B 18 44
F0 4E 95 CD 6D 26 B2 BD 34 30 03 06 52 C8 D2 E8
10 61 3A 80 B3 A4 92 E3 B8 E6 14 D4 13 26 FF EC
3B 02 EE D5 BB BF 4E 9D 4A 62 7A 40 FE 9D CF 1D
A0 C4 2A F1 A5 65 67 A2 3D 04 46 B4 78 9F 8A A2
02 03 DF 2C 0E 0E F8 E6 C5 00

Send that to arduino with serial, store them in an array*, then all you have to do is make a function to draw each of those bits as a white or black square.

*You could have your draw function read from serial directly, but I believe you will have to slow down the bauds because those displays are much slower to draw than serial data will arrive... I could be wrong since ghlawrence reported that it works :wink:

Yep Ghlawrence can confirm it works! :wink: :stuck_out_tongue:

Included in the Archive is my UTFT_SdRaw library modified to cope with Serial, a Processing sketch to squirt the image to Arduino, and a demo Arduino sketch.

It is not a complete solution, but it should help you on your way.

Regards,

Graham

PS Be aware the images for the Library examples were removed due to limitations on the Forum's upload limit. But the 3 parts you need to test this are all included.

PPS As it stands, images MUST be square!

UTFT_SdRaw_Serial.zip (273 KB)

So I decided to play with guix' idea. The results are quite interesting!

I wrote a routine called qrserial, which is actually nothing to do with Serial yet! It takes an array as provided by guix and then draws it with a variable multiplier (multiplier = number of pixels on screen per QR bit).

I appreciate UTFT's drawPixel command is not the fastest!! but the results are listed below :-

Multiplier Effective pixels Time (ms)
1 29 * 29 35
2 58 * 58 138
3 87 * 87 307
4 116 * 116 545
5 145 * 145 851

If you know you will always be drawing to a black screen, the black pixels don't need to be drawn which yields the following improvements :-

Multiplier Effective pixels Time (ms)
1 29 * 29 16
2 58 * 58 63
3 87 * 87 139
4 116 * 116 247
5 145 * 145 385

Those figures use an array hard coded in the sketch, so that is as fast as it could be without Serial delays (not taking into account the inefficient use of UTFT.drawPixel!).

Taking things to the logical conclusion I then made the source array sent over serial from processing :-

Serial speed Time (ms)
460800 386 - 387
115200 387 - 390
57600 388 - 391
28800 390 - 393
14400 395 - 397

As you can see, this bears out guix statement that the display is slower than serial. The actual impact on render speed is hardly affected by the actual serial speed. Result was rendered without the black pixels being drawn.

Then I decided to do a comparison with my timings to send a RAW image using my previously modified version of UTFT_SdRaw and send the same QR code as 145*145 ready rendered RAW image.

Serial speed Time (ms)
115200 3577
460800 1319

So there you have it. All timings done on a DUE using CTE TFT/Touch/SD shield and ITDB32S display.

Now the question is, what method or speed do you want to use :wink: ? Well done guix +1 for the idea!

Thanks to both of you for giving me something interesting to play with! ;D 8)

Regards,

Graham

Note: Rename qr3bits.raw.txt to qr3bits.raw

The qrbits_serial.ino contains local and serial versions of the qr renderer. The Processing sketch is designed to send the array file (qr3bits.raw) to the Arduino sketch. It should give you a good start point to help you on your way with your project :smiley:

qr3bits.raw.txt (106 Bytes)

qrbits_Serial.ino (4.26 KB)

array_uploader.pde (2.65 KB)

wow you guys have really run away with this :wink: , thanks for all the info guys and thanks graham for all the time and effort and the samples, im sure they will go along way to helping me. i will give all of this a try later tonight when im home and see what i can make of this.

thanks again guys awesome info to go on.

So some feedback, i tested out the libraries you gave Graham and they are working for the first time i actually have the qr codes on screen., so thanks again for that.

only problem now is trying to convert the image in c# to that hex format, i think c# does some funny things when it converts to and from hex and arrays etc. if i use the hex that guix transformed the qr code into i cant seem to get it back into a bitmap format for use in my code, so i think the formatting is slightly out when c# converts it back into a bitmap from a byte[].

i can successfully convert my image to and from a bitmap to a hex string and then to a byte array, and back again to display it on my windows app, but i cant get guix's hex string into a usable image.

so guix could you maybe share the code you used to convert the qr code in that hex string?

jaydeeSale:
so guix could you maybe share the code you used to convert the qr code in that hex string?

Manually by hand I assume. Zoom in to X5 on the qr3_annotated.png. Thats how I do it. So starting at the top left corner you have 00000001 = 0x80, 11111101 = 0xbf, 10100100 = 0x25 etc you need to reverse the string of bits!

But you said you are generating your own QR codes, so surely you already have the arrays?

jaydeeSale:
only problem now is trying to convert the image in c# to that hex format, i think c# does some funny things when it converts to and from hex and arrays etc.

More likely the programmer than the language causing the problems ;).

jaydeeSale:
if i use the hex that guix transformed the qr code into i cant seem to get it back into a bitmap format for use in my code, so i think the formatting is slightly out when c# converts it back into a bitmap from a byte[].

I already gave you the routine to do that!! I have no knowledge or interest in C# or I might have done it just for lols.

jaydeeSale:
i can successfully convert my image to and from a bitmap to a hex string and then to a byte array, and back again to display it on my windows app, but i cant get guix's hex string into a usable image.

Then we can only assume you are doing something wrong, because 'guix hex string' as you call it is nothing clever and is an ACCURATE representation of the QR code we used as an example!

Regards,

Graham

PS, If you were less coy about your code maybe we would be in a better position to help you??!!

Qr-3_annotated.png

I didn't do manually :), I quickly wrote a plugin for Paint.Net (C#)

Basically...

byte bitCounter = 0;
byte outByte = 0;

for ( int y = 0; y < sizeY; y++ ) // for each row
{
    for ( int x = 0; x < sizeX; x++ ) // for each line
    {
        bgra8888 = surface[x, y]; // color of current pixel
        rgb565 = packRGB888toRGB565( bgra8888.R, bgra8888.G, bgra8888.B ); // converted to rgb565

        if ( rgb565 ) // if any color but black
            outByte |= (byte)( 1 << bitCounter ); // set bit

        if ( bitCounter++ >= 7 ) // if byte is full
        {
            output.WriteByte( outByte ); // write to stream
            outByte = 0; // reset it
            bitCounter = 0; // and reset counter
        }
    }
}

output.WriteByte( outByte ); // write last byte to stream

Of course the image from wikipedia was modified: I removed the borders and reduced the size to 29*29 pixels. The content of the output file is exactly the same as "qr3bits.raw.txt" from ghlawrence :wink:

@ghlawrence, instead of using drawPixel, use fillRect, it will probably draw much faster, because much less call to setXY :wink:

guix:
I didn't do manually :), I quickly wrote a plugin for Paint.Net (C#)

Good for you! I found it easy enough doing it the old fashioned way and plugging the results in to hexedit. I achieved the same results :stuck_out_tongue:

guix:
@ghlawrence, instead of using drawPixel, use fillRect, it will probably draw much faster, because much less call to setXY :wink:

Yes, if I was doing it for myself I might have gone on to optimise it, but it was only proof of concept and the speeds I thought were acceptable anyway. Of Course he is using a MEGA which will have devastating effects on the draw speed.

@guix, I have a question for you, what if the source bitmap represents a QR pixel in 8*9 pixels, how would that upset your method? ;

I just generated a QR code on qr-generator.com and the ouput is aliased, so after reduction of colour depth, like I just said, the pixel shape is 8*9 on screen pixels per QR bit. I was tempted to have a play and write a routine to convert a bmp to qr array similar to what you did, but then came across this issue.

Regards,

Graham

So after what guix said about rectangles....... Holly smoke batman!!!

ghlawrence2000:
If you know you will always be drawing to a black screen, the black pixels don't need to be drawn which yields the following improvements :-

Multiplier Effective pixels Time (ms)
1 29 * 29 16
2 58 * 58 63
3 87 * 87 139
4 116 * 116 247
5 145 * 145 385

Those figures use an array hard coded in the sketch, so that is as fast as it could be without Serial delays (not taking into account the inefficient use of UTFT.drawPixel!).

Becomes :-

Multiplier Effective pixels Time (ms)
1 29 * 29 10
2 58 * 58 10
3 87 * 87 10
4 116 * 116 11
5 145 * 145 13

!!!!!!!!!!!!

So here is the modified qrlocal routine :-

void qrlocal(int x, int y, int sx, int sy, int scale, unsigned char* array)
{
  int bits = 0;
  int bytes = 0;
  int rowbits = 0;
  int rowcount = 0;
  int myx = x, myy = y;
  while (1)
  {
    if (((array[bytes] >> bits) & 0x01) == 0) {
      /*    // Uncomment if you will not be drawing to a black screen
            myGLCD.setColor(0, 0, 0);
            myGLCD.fillRect(myx,myy,myx+scale-1,myy+scale-1);
      */
    }
    else
    {
      myGLCD.setColor(255, 255, 255);
      myGLCD.fillRect(myx, myy, myx + scale - 1, myy + scale - 1);
    }
    myx += scale;
    bits++;
    rowbits++;
    if (rowbits == sx) {
      myy += scale;
      myx = x;
      rowcount++;
      rowbits = 0;
    }
    if (rowcount == sy) break;
    if (bits == 8) {
      bytes += 1;
      bits = 0;
    }
  }
}

Still on a DUE, I accept that is not a fair comparison to a MEGA but never the less, every little helps as they say!

So I was curious and just fished out my old rotting dust collecting MEGA, and it all comes back to me why it is gathering dust!! :stuck_out_tongue:

Multiplier Effective pixels Time (ms)
1 29 * 29 76
2 58 * 58 79
3 87 * 87 83
4 116 * 116 69
5 145 * 145 93

Regards,

Graham