Closed dglaude closed 3 years ago
While I did not narrow down what is wrong, I made a demo that does not require a MLX90640 and just require a PyGamer. This code is 'fake_mlx90640_pygamer+sd.py' and it produce a valid 'picture2.bmp' and a faulty 'screen2.bmp'. It might be possible to make an even smaller example of code that produce that leaking of pixel and unreadable text.
Here is a small code sample exposing the first problem = the leaking the last column of pixels. There is another problem with the label.
### Adafruit_CircuitPython_BitmapSaver_minimal.py
import time
import board
import busio
import displayio
import adafruit_fancyled.adafruit_fancyled as fancy
import digitalio
import adafruit_sdcard
import storage
from adafruit_bitmapsaver import save_pixels
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
cs = digitalio.DigitalInOut(board.SD_CS)
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
number_of_colors = 64 # Number of color in the gradian
palette = displayio.Palette(number_of_colors) # Palette with all our colors
# gradian for fancyled palette generation
grad = [(0.00, fancy.CRGB(0, 0, 255)), (1.00, fancy.CRGB(255, 0, 0))] # Blue - Red
fancy_palette = fancy.expand_gradient(grad, number_of_colors)
for c in range(number_of_colors):
palette[c] = fancy_palette[c].pack()
image_bitmap = displayio.Bitmap(32, 24, number_of_colors)
image_tile= displayio.TileGrid(image_bitmap, pixel_shader=palette)
image_group = displayio.Group(scale=4)
image_group.append(image_tile)
group = displayio.Group(max_size = 8)
group.append(image_group)
board.DISPLAY.show(group)
for h in range(24):
for w in range(32):
image_bitmap[w, (23-h)] = h + w
save_pixels('/sd/picture5.bmp', image_bitmap, palette)
save_pixels('/sd/screen5.bmp')
while True:
time.sleep(1)
Hi @dglaude were you ever able to figure out why this was happening?
I did not try to reproduce anymore, and I did not check in the code of the library either. I made code to reproduce the problem, it should be easy to reproduce.
Le jeu. 18 juin 2020 à 01:51, dherrada notifications@github.com a écrit :
Hi @dglaude https://github.com/dglaude were you ever able to figure out why this was happening?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/adafruit/Adafruit_CircuitPython_BitmapSaver/issues/8#issuecomment-645685102, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEUJDHHM7I524VXPJSOASSDRXFJGJANCNFSM4KSFYM3A .
I ran into something similar to what @dglaude mentions above. I found a way around it, and maybe that hints to the issue.
I am using the bitmap save directly from the display.
Here is what I got initially, that shows a "streaky" error above the graphics:
I added a black bitmap background to the display behind the image and got this:
To me, it looks like if the display doesn't have any content (transparent?), then it repeats the pixel color values from the previous row. That is a hint into what is going on.
Whenever the data is written into result_buffer
from the display, if there is no Group, TileGrid or VectorIO object at that pixel location, then nothing gets overwritten, so the buffer is not updated in that location and the previous buffer value is retained at that pixel position.
The fundamental issue is in the CircuitPython displayio core functions for fill_area
. If an area isn't "owned" by a Group, TileGrid or VectorIO object, then nothing is written into the buffer with fill_area
.
A quick fix inside of this library is to reinitialize the result_buffer
to all zeros before each call to fill_area
. I added a single line:
result_buffer = bytearray(2048)
as the first line in the else
statement.
Here's my updated code for _write_pixels
in the file adafruit_bitmapsaver.py
:
def _write_pixels(output_file, pixel_source, palette):
saving_bitmap = isinstance(pixel_source, Bitmap)
width, height = _rotated_height_and_width(pixel_source)
row_buffer = bytearray(_bytes_per_row(width))
result_buffer = bytearray(2048)
for y in range(height, 0, -1):
buffer_index = 0
if saving_bitmap:
for x in range(width):
pixel = pixel_source[x, y - 1]
color = palette[pixel]
for _ in range(3):
row_buffer[buffer_index] = color & 0xFF
color >>= 8
buffer_index += 1
else:
result_buffer = bytearray(2048)
data = pixel_source.fill_row(y - 1, result_buffer)
for i in range(width):
pixel565 = (data[i * 2] << 8) + data[i * 2 + 1]
for b in _rgb565_to_bgr_tuple(pixel565):
row_buffer[buffer_index] = b & 0xFF
buffer_index += 1
output_file.write(row_buffer)
gc.collect()
Great, this issue is more than one year old and you found an explanation.
Solution was merged in: https://github.com/adafruit/Adafruit_CircuitPython_BitmapSaver/pull/14
Solution was merged in: #14
It appears that this issue should be closed as resolved from the previous comment.
@hugodahl Thanks @kmatch98 closing
I followed the guide ( https://learn.adafruit.com/saving-bitmap-screenshots-in-circuitpython/overview ) to take a screencapture.
However the result does not match exactly what is in screen.
My code to demonstrate this problem is in this repo: https://github.com/dglaude/CircuitPython_MLX90640_PyGamer_Plus
I believe there are two problems with the above image:
Unfortunately this code require a MLX90640 thermal camera, but I am sure the camera output can be faked to trigger this problem without that hardware.
PS: Notice that 'picture.bmp' is an OK output, but that specify a bitmap and a palette (rather that full screen version without those parameter).