Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 10 of 10

Thread: Reading R8875 BMP image files

  1. #1
    Member
    Join Date
    Dec 2017
    Location
    Ohio
    Posts
    76

    Reading R8875 BMP image files

    Can someone share code that can read and display a BMP file on a RA8875-type display. I'm using Teensy 4.1 and trying to display a BMP image from the onboard SD reader.

    Thanks!

  2. #2
    This code is from my printscreen library for and ILI9341--and relies on a writeRect. If your lib has that call, this code will probably work. I've not tested it to work on your display but I use it frequently to display 24-bit BMPs from and SD card. This is for SD.h. but can be modified for SdFat.h.

    If your display lib has a call called readPixel(), i hve code for reading a screen and saving a BMP to the SD card.

    You could save this to a .h file and call directly or embed the code in your .ino (of course replace the d->blabla with YourDislayObject.blabla

    hope this helps

    Code:
    bool inline DrawBMP24(ILI9341_t3 *d, int cs, const char *FileName, uint8_t x = 0, uint16_t y = 0) {
    
    	File     bmpFile;
    	int      bmpWidth, bmpHeight;			// W+H in pixels
    	int      w, h, row, col;
    	uint8_t  bmpDepth;					// Bit depth (currently must be 24)
    	uint32_t bmpImageoffset;				// Start of image data in file
    	uint32_t rowSize;						// Not always = bmpWidth; may have padding
    	uint8_t  sdbuffer[3 * 8];				// pixel buffer (R+G+B per pixel)
    	uint8_t  buffidx = sizeof(sdbuffer);	// Current position in sdbuffer
    	boolean  flip    = true;				// BMP is stored bottom-to-top
    	uint8_t  r, g, b;						// holders for red green blue
    	uint32_t pos = 0;						// file position
    	uint16_t awColors[320];				// hold colors for one row at a time...
    	uint16_t Read16;						// file read placeholder
    	uint32_t Read32;						// file read placeholder
    
    
    	// let's not test begin, reason is if you create a file SD exists and will fail here
    	// just use any existing object
    	// we will trap file open next
    	SD.begin(cs);
      
    	bmpFile = SD.open(FileName, FILE_READ);
    
    	if (!bmpFile){
    		//Serial.print("SD.open: ");
    		//Serial.println(bmpFile);
    		return false;
    	}
    
    
    	if ((x >= d->width()) || (y >= d->height())) {
    	return false;
    	}
    
      // Parse BMP header
    
      ((uint8_t *)&Read16)[0] = bmpFile.read(); 
      ((uint8_t *)&Read16)[1] = bmpFile.read(); 
    
      if (Read16 == 0x4D42) { 
    	// ignore read
    	((uint8_t *)&Read32)[0] = bmpFile.read(); 
    	((uint8_t *)&Read32)[1] = bmpFile.read();
    	((uint8_t *)&Read32)[2] = bmpFile.read();
    	((uint8_t *)&Read32)[3] = bmpFile.read(); 
    	// ignore read
    	((uint8_t *)&Read32)[0] = bmpFile.read(); 
    	((uint8_t *)&Read32)[1] = bmpFile.read();
    	((uint8_t *)&Read32)[2] = bmpFile.read();
    	((uint8_t *)&Read32)[3] = bmpFile.read(); 
    
    	// read offset
    	((uint8_t *)&Read32)[0] = bmpFile.read(); 
    	((uint8_t *)&Read32)[1] = bmpFile.read();
    	((uint8_t *)&Read32)[2] = bmpFile.read();
    	((uint8_t *)&Read32)[3] = bmpFile.read(); 
    	bmpImageoffset = Read32; 
    
    	// ignore read
        ((uint8_t *)&Read32)[0] = bmpFile.read(); 
    	((uint8_t *)&Read32)[1] = bmpFile.read();
    	((uint8_t *)&Read32)[2] = bmpFile.read();
    	((uint8_t *)&Read32)[3] = bmpFile.read(); 
    
    	// read width
    	((uint8_t *)&Read32)[0] = bmpFile.read(); 
    	((uint8_t *)&Read32)[1] = bmpFile.read();
    	((uint8_t *)&Read32)[2] = bmpFile.read();
    	((uint8_t *)&Read32)[3] = bmpFile.read(); 
    	bmpWidth  = Read32;
    
    	// read height
    	((uint8_t *)&Read32)[0] = bmpFile.read(); 
    	((uint8_t *)&Read32)[1] = bmpFile.read();
    	((uint8_t *)&Read32)[2] = bmpFile.read();
    	((uint8_t *)&Read32)[3] = bmpFile.read(); 
    	bmpHeight = Read32;
    
    	// get planes
    	((uint8_t *)&Read16)[0] = bmpFile.read(); 
    	((uint8_t *)&Read16)[1] = bmpFile.read();
    
        if (Read16 == 1) { // # planes -- must be '1'
    
    		// read depth
    		((uint8_t *)&Read16)[0] = bmpFile.read(); 
    		((uint8_t *)&Read16)[1] = bmpFile.read();
    		bmpDepth = Read16; // bits per pixel
    
    		// read compression
    		((uint8_t *)&Read32)[0] = bmpFile.read(); 
    		((uint8_t *)&Read32)[1] = bmpFile.read();
    		((uint8_t *)&Read32)[2] = bmpFile.read();
    		((uint8_t *)&Read32)[3] = bmpFile.read(); 
    
    
          if ((bmpDepth == 24) && (Read32 == 0)) { // 0 = uncompressed
    
    
    		  // if you got this far, legit image file
            rowSize = (bmpWidth * 3 + 3) & ~3;
    
            if (bmpHeight < 0) {
              bmpHeight = -bmpHeight;
              flip      = false;
            }
    
            w = bmpWidth;
            h = bmpHeight;
            if ((x + w - 1) >= d->width())  w = d->width()  - x;
            if ((y + h - 1) >= d->height()) h = d->height() - y;
    
            for (row = 0; row < h; row++) { // For each scanline...
              if (flip) // Bitmap is stored bottom-to-top order (normal BMP)
                pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
              else     // Bitmap is stored top-to-bottom
                pos = bmpImageoffset + row * rowSize;
              if (bmpFile.position() != pos) { // Need seek?
                bmpFile.seek(pos);
                buffidx = sizeof(sdbuffer); // Force buffer reload
              }
    
              for (col = 0; col < w; col++) { // For each pixel...
                // Time to read more pixel data?
                if (buffidx >= sizeof(sdbuffer)) { // Indeed
                  bmpFile.read(sdbuffer, sizeof(sdbuffer));
                  buffidx = 0; // Set index to beginning
                }
               
                b = sdbuffer[buffidx++];
                g = sdbuffer[buffidx++];
                r = sdbuffer[buffidx++];
                awColors[col] = d->color565(r, g, b);
              } 
    
              d->writeRect(0, row, w, 1, awColors);
    
            }
          }
    	  else {
    		 return false;
    	  }
        }
    	else {
    		 return false;
    	}
      }
    
      bmpFile.close();
    
      return true;
      
    }

  3. #3
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    11,382
    For what it is worth, @mjs513 and I were playing around with a picture viewer sketch, that
    could read in BMP files as well as JPEG and PNG files and we have it, such that it could be configured to run
    on several different displays (ILI9341, ILI9488, ST7735/89, RA8875 and RA8876).

    We were having fun with it, so for example with BMP files we have code that can scale it to fit the display
    For PNG/JPEG files it uses optional libraries.

    It is also setup to optionally use the USB Types including MTP.

    The code is up at: https://github.com/KurtE/mtp_tft_picture_view

  4. #4
    Member
    Join Date
    Dec 2017
    Location
    Ohio
    Posts
    76
    Thanks, Kris. I'll give this a try!

  5. #5
    Member
    Join Date
    Dec 2017
    Location
    Ohio
    Posts
    76
    Thanks, Kurt. If I get this to work on the RA8875, I'll post it here.

  6. #6
    Member
    Join Date
    Dec 2017
    Location
    Ohio
    Posts
    76
    Kurt: After supplying a couple of missing header files and adjusting comments for the RA8875, your code displays my image perfectly, including scaling for a 5" display. Thanks a boatload for letting me use your code. BTW, I would like to use your code in my T41-EP Open Source project. That's a SDR transceiver for amateur radio operators. Both the hardware.software are open source and the Teensy 4.1 drives the entire system. This is the prototype of the radio:
    Click image for larger version. 

Name:	Figure00-001Small.jpg 
Views:	12 
Size:	89.4 KB 
ID:	29873
    I would also like to feature the code in a revised edition of our book (Amazon B09WYP1ST8) if that okay. It is really a nice piece of software.

  7. #7
    Member
    Join Date
    Dec 2017
    Location
    Ohio
    Posts
    76
    Kurt: I failed to notice in my previous reply that the "block artifact" appears in the upper-left corner of the display. I mentioned this in an earlier post and solved it by supplying two missing arguments from the tft.begin() method call. That did not fix it here, however, as you can see below:
    Click image for larger version. 

Name:	WorldMapBlock.jpg 
Views:	12 
Size:	107.4 KB 
ID:	29876
    Any ideas?

  8. #8
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    11,382
    It has been a very long time since I played much with the RA8875.

    What a vaguely remembered was when I saw this, it had something like a hardware cursor turned on. And I needed to do something to turn it off.

    @mjs513 and others, do you remember any more about this?

    As far as using any of this code. As far as I am concerned, I have not problems at all. Except the standard, of the code is as is, and that there are no guarantees or warrantees...

    Note: The original BMP code was done by Adafruit and they had examples in most of their display drivers. Note: @mjs513 and myself did update it significantly. But I still left the mentions at the start.

    The PNG and JPEG stuff are Arduino libraries by @bitbank2, with whatever restrictions it may have (Apache 2)

  9. #9
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,539
    Ditto on how long its been since using a RA8875.

    I don't remember ever seeing a block artifact during testing to be honest.

    In looking at existing example (RA8875/Examples/_Teensy3/basicTextFunctions/basicTextFunctions.ino) I did notice this command:

    Code:
    tft.showCursor(NOCURSOR, false); //deactivate cursor
    You can give it a try to see if gets rid of it, if that is the issue.

  10. #10
    Member
    Join Date
    Dec 2017
    Location
    Ohio
    Posts
    76
    KurtE: Thanks for the OK on using the code. To keep things simple, I'm striping out all but the BMP code. I will, of course, give you, mjs513, and Adafruit credits for the code. I would like to use your full names in the book, if that's okay. You can email me at jack52443 at yahoo dot com.
    mjs5113: Came down this morning to work on the code and the artifact is gone! The only thing different was this morning there was a cold boot. I'll keep you suggestion in the back of my mind!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •