Files
Your Name fb389bec03 update
2025-03-30 19:31:36 +02:00

194 lines
6.3 KiB
C++

// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
//
// Example how to display an image, including animated images using
// ImageMagick. For a full utility that does a few more things, have a look
// at the led-image-viewer in ../utils
//
// Showing an image is not so complicated, essentially just copy all the
// pixels to the canvas. How to get the pixels ? In this example we're using
// the graphicsmagick library as universal image loader library that
// can also deal with animated images.
// You can of course do your own image loading or use some other library.
//
// This requires an external dependency, so install these first before you
// can call `make image-example`
// sudo apt-get update
// sudo apt-get install libgraphicsmagick++-dev libwebp-dev -y
// make image-example
/*
pour compiler:
g++ -I/var/www/moduleair_pro_4g/matrix/include -L/var/www/moduleair_pro_4g/matrix/lib /var/www/moduleair_pro_4g/matrix/imageScreen/test_image.cc -o /var/www/moduleair_pro_4g/matrix/imageScreen/test_image -lrgbmatrix
g++ -I/var/www/moduleair_pro_4g/matrix/include -L/var/www/moduleair_pro_4g/matrix/lib /var/www/moduleair_pro_4g/matrix/imageScreen/test_image.cc -o /var/www/moduleair_pro_4g/matrix/imageScreen/test_image -lrgbmatrix `GraphicsMagick++-config --cppflags --libs`
pour lancer:
sudo /var/www/moduleair_pro_4g/matrix/imageScreen/test_image /var/www/moduleair_pro_4g/matrix/imageScreen/ModuleAir128x64.png
*/
#include "led-matrix.h"
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <exception>
#include <Magick++.h>
#include <magick/image.h>
using rgb_matrix::Canvas;
using rgb_matrix::RGBMatrix;
using rgb_matrix::FrameCanvas;
// Make sure we can exit gracefully when Ctrl-C is pressed.
volatile bool interrupt_received = false;
static void InterruptHandler(int signo) {
interrupt_received = true;
}
using ImageVector = std::vector<Magick::Image>;
// Given the filename, load the image and scale to the size of the
// matrix.
// // If this is an animated image, the resutlting vector will contain multiple.
static ImageVector LoadImageAndScaleImage(const char *filename,
int target_width,
int target_height) {
ImageVector result;
ImageVector frames;
try {
readImages(&frames, filename);
} catch (std::exception &e) {
if (e.what())
fprintf(stderr, "%s\n", e.what());
return result;
}
if (frames.empty()) {
fprintf(stderr, "No image found.");
return result;
}
// Animated images have partial frames that need to be put together
if (frames.size() > 1) {
Magick::coalesceImages(&result, frames.begin(), frames.end());
} else {
result.push_back(frames[0]); // just a single still image.
}
for (Magick::Image &image : result) {
image.scale(Magick::Geometry(target_width, target_height));
}
return result;
}
// Copy an image to a Canvas. Note, the RGBMatrix is implementing the Canvas
// interface as well as the FrameCanvas we use in the double-buffering of the
// animted image.
void CopyImageToCanvas(const Magick::Image &image, Canvas *canvas) {
const int offset_x = 0, offset_y = 0; // If you want to move the image.
// Copy all the pixels to the canvas.
for (size_t y = 0; y < image.rows(); ++y) {
for (size_t x = 0; x < image.columns(); ++x) {
const Magick::Color &c = image.pixelColor(x, y);
if (c.alphaQuantum() < 256) {
canvas->SetPixel(x + offset_x, y + offset_y,
ScaleQuantumToChar(c.redQuantum()),
ScaleQuantumToChar(c.greenQuantum()),
ScaleQuantumToChar(c.blueQuantum()));
}
}
}
}
// An animated image has to constantly swap to the next frame.
// We're using double-buffering and fill an offscreen buffer first, then show.
void ShowAnimatedImage(const ImageVector &images, RGBMatrix *matrix) {
FrameCanvas *offscreen_canvas = matrix->CreateFrameCanvas();
while (!interrupt_received) {
for (const auto &image : images) {
if (interrupt_received) break;
CopyImageToCanvas(image, offscreen_canvas);
offscreen_canvas = matrix->SwapOnVSync(offscreen_canvas);
usleep(image.animationDelay() * 10000); // 1/100s converted to usec
}
}
}
int usage(const char *progname) {
fprintf(stderr, "Usage: %s [led-matrix-options] <image-filename>\n",
progname);
rgb_matrix::PrintMatrixFlags(stderr);
return 1;
}
int main(int argc, char *argv[]) {
Magick::InitializeMagick(*argv);
// Check if a filename was provided
if (argc != 2) {
fprintf(stderr, "Usage: %s <image-filename>\n", argv[0]);
return 1;
}
const char *filename = argv[1];
// Initialize with hardcoded defaults for your specific hardware
RGBMatrix::Options defaults;
defaults.hardware_mapping = "moduleair_pinout";
defaults.rows = 64;
defaults.cols = 128;
defaults.chain_length = 1;
defaults.parallel = 1;
defaults.row_address_type = 3;
defaults.show_refresh_rate = true;
defaults.brightness = 100;
defaults.pwm_bits = 1;
defaults.panel_type = "FM6126A";
defaults.disable_hardware_pulsing = false;
// Set up runtime options (still needed)
rgb_matrix::RuntimeOptions runtime_opt;
runtime_opt.gpio_slowdown = 4; // Adjust if needed for your Pi model
runtime_opt.daemon = 0;
runtime_opt.drop_privileges = 0; // Set to 1 if not running as root
// Handle Ctrl+C to exit gracefully
signal(SIGTERM, InterruptHandler);
signal(SIGINT, InterruptHandler);
// Create the matrix with our defaults
RGBMatrix *matrix = RGBMatrix::CreateFromOptions(defaults, runtime_opt);
if (matrix == NULL) {
fprintf(stderr, "Failed to create matrix\n");
return 1;
}
// Load and process the image
ImageVector images = LoadImageAndScaleImage(filename,
matrix->width(),
matrix->height());
// Display the image(s)
switch (images.size()) {
case 0: // failed to load image
fprintf(stderr, "Failed to load image\n");
break;
case 1: // single image to show
CopyImageToCanvas(images[0], matrix);
while (!interrupt_received) sleep(1); // Until Ctrl-C is pressed
break;
default: // animation with multiple frames
ShowAnimatedImage(images, matrix);
break;
}
// Clean up
matrix->Clear();
delete matrix;
return 0;
}