Skip to content

Commit 908cccc

Browse files
committed
stb: Make all files readable from stdin
Fixes #150
1 parent dae0a4f commit 908cccc

File tree

1 file changed

+31
-15
lines changed

1 file changed

+31
-15
lines changed

src/stb-image-source.cc

+31-15
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "stb-image-source.h"
1717

1818
#define STB_IMAGE_IMPLEMENTATION
19+
#include <unistd.h>
20+
1921
#include <algorithm>
2022
#include <csignal>
2123
#include <cstdint>
@@ -39,9 +41,9 @@ static constexpr int kDesiredChannels = 4; // RGBA, our framebuffer format
3941
namespace timg {
4042
class STBImageSource::PreprocessedFrame {
4143
public:
42-
PreprocessedFrame(const uint8_t *image_data, int source_w, int source_h,
43-
int target_w, int target_h, const Duration &delay,
44-
const DisplayOptions &opt)
44+
PreprocessedFrame(const uint8_t *image_data, size_t source_w,
45+
size_t source_h, size_t target_w, size_t target_h,
46+
const Duration &delay, const DisplayOptions &opt)
4547
: delay_(delay), framebuffer_(target_w, target_h) {
4648
const size_t len = source_w * source_h * 4;
4749
Framebuffer source_img(source_w, source_h); // TODO: avoid copy.
@@ -89,14 +91,26 @@ bool STBImageSource::LoadAndScale(const DisplayOptions &options,
8991
}
9092
#endif
9193

92-
FILE *img_file = (filename() == "-")
93-
? fdopen(STDIN_FILENO, "rb")
94-
: stbi__fopen(filename().c_str(), "rb");
94+
stbi__context context;
9595

96-
if (!img_file) return false;
96+
FILE *img_file = nullptr;
97+
std::string mem_buffer;
9798

98-
stbi__context context;
99-
stbi__start_file(&context, img_file);
99+
if (filename() == "-") {
100+
// For stdin, we need to fill a buffer, as stb needs seek functionality.
101+
char buffer[4096];
102+
ssize_t r;
103+
while ((r = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) {
104+
mem_buffer.append(buffer, r);
105+
}
106+
stbi__start_mem(&context, (const uint8_t *)mem_buffer.data(),
107+
mem_buffer.size());
108+
}
109+
else {
110+
img_file = stbi__fopen(filename().c_str(), "rb");
111+
if (!img_file) return false;
112+
stbi__start_file(&context, img_file);
113+
}
100114

101115
int channels;
102116
int target_width = 0;
@@ -108,7 +122,7 @@ bool STBImageSource::LoadAndScale(const DisplayOptions &options,
108122
memset(&gdata, 0, sizeof(gdata));
109123
uint8_t *data;
110124
while ((data = stbi__gif_load_next(&context, &gdata, &channels,
111-
kDesiredChannels, 0))) {
125+
kDesiredChannels, nullptr))) {
112126
if (data == (const uint8_t *)&context) break;
113127
orig_width_ = gdata.w;
114128
orig_height_ = gdata.h;
@@ -124,7 +138,8 @@ bool STBImageSource::LoadAndScale(const DisplayOptions &options,
124138
STBI_FREE(gdata.background);
125139
}
126140
else {
127-
int w, h;
141+
int w = 0;
142+
int h = 0;
128143
uint8_t *data = stbi__load_and_postprocess_8bit(
129144
&context, &w, &h, &channels, kDesiredChannels);
130145
if (!data) {
@@ -149,7 +164,7 @@ bool STBImageSource::LoadAndScale(const DisplayOptions &options,
149164
? (int)frames_.size()
150165
: std::min(frame_count, (int)frames_.size());
151166

152-
fclose(img_file);
167+
if (img_file) fclose(img_file);
153168

154169
return !frames_.empty();
155170
}
@@ -159,12 +174,13 @@ void STBImageSource::SendFrames(const Duration &duration, int loops,
159174
const Renderer::WriteFramebufferFun &sink) {
160175
int last_height = -1; // First image emit will not have a height.
161176
const bool is_animation = frames_.size() > 1;
162-
if (frames_.size() == 1 || !is_animation)
177+
if (frames_.size() == 1 || !is_animation) {
163178
loops = 1; // If there is no animation, nothing to repeat.
164-
179+
}
165180
// Not initialized or negative value wants us to loop forever.
166181
// (note, kNotInitialized is actually negative, but here for clarity
167-
const bool loop_forever = (loops < 0) || (loops == timg::kNotInitialized);
182+
const bool loop_forever =
183+
(loops < 0) || (loops == timg::kNotInitialized); // NOLINT
168184

169185
timg::Duration time_from_first_frame;
170186
bool is_first = true;

0 commit comments

Comments
 (0)