forked from hzeller/rpi-rgb-led-matrix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
image-example.cc
160 lines (136 loc) · 4.98 KB
/
image-example.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// -*- 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
#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);
// Initialize the RGB matrix with
RGBMatrix::Options matrix_options;
rgb_matrix::RuntimeOptions runtime_opt;
if (!rgb_matrix::ParseOptionsFromFlags(&argc, &argv,
&matrix_options, &runtime_opt)) {
return usage(argv[0]);
}
if (argc != 2)
return usage(argv[0]);
const char *filename = argv[1];
signal(SIGTERM, InterruptHandler);
signal(SIGINT, InterruptHandler);
RGBMatrix *matrix = RGBMatrix::CreateFromOptions(matrix_options, runtime_opt);
if (matrix == NULL)
return 1;
ImageVector images = LoadImageAndScaleImage(filename,
matrix->width(),
matrix->height());
switch (images.size()) {
case 0: // failed to load image.
break;
case 1: // Simple example: one image to show
CopyImageToCanvas(images[0], matrix);
while (!interrupt_received) sleep(1000); // Until Ctrl-C is pressed
break;
default: // More than one image: this is an animation.
ShowAnimatedImage(images, matrix);
break;
}
matrix->Clear();
delete matrix;
return 0;
}