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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
//
// Test program for Fl_Anim_GIF_Image::copy().
//
#include <FL/Fl_Anim_GIF_Image.H>
#include <FL/Fl_Image.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <stdlib.h>
static Fl_Anim_GIF_Image *orig = 0;
static bool draw_grid = true;
static int events(int event_) {
if (event_ == FL_SHORTCUT && Fl::first_window()) {
if (Fl::event_key()=='g') {
draw_grid = !draw_grid;
printf("grid: %s\n", (draw_grid ? "ON" : "OFF"));
}
else if (Fl::event_key()=='b') {
if (Fl_Image::scaling_algorithm() != FL_RGB_SCALING_BILINEAR)
Fl_Image::scaling_algorithm(FL_RGB_SCALING_BILINEAR);
else
Fl_Image::scaling_algorithm(FL_RGB_SCALING_NEAREST);
printf("bilenear: %s\n", (Fl_Image::scaling_algorithm() != FL_RGB_SCALING_BILINEAR ? "OFF" : "ON"));
}
else
return 0;
Fl::first_window()->redraw();
}
return 1;
}
class Canvas : public Fl_Box {
typedef Fl_Box Inherited;
public:
Canvas(int x, int y, int w, int h) :
Inherited(x, y, w, h) {}
void draw() FL_OVERRIDE {
if (draw_grid) {
// draw a transparency grid as background
static const Fl_Color C1 = fl_rgb_color(0xcc, 0xcc, 0xcc);
static const Fl_Color C2 = fl_rgb_color(0x88, 0x88, 0x88);
static const int SZ = 8;
for (int y = 0; y < h(); y += SZ) {
for (int x = 0; x < w(); x += SZ) {
fl_color(x%(SZ * 2) ? y%(SZ * 2) ? C1 : C2 : y%(SZ * 2) ? C2 : C1);
fl_rectf(x, y, 32, 32);
}
}
}
// draw the current image frame over the grid
Inherited::draw();
}
void do_resize(int W, int H) {
if (image() && (image()->w() != W || image()->h() != H)) {
Fl_Anim_GIF_Image *animgif = (Fl_Anim_GIF_Image *)image();
animgif->stop();
image(0);
// delete already copied images
if (animgif != orig ) {
delete animgif;
}
Fl_Anim_GIF_Image *copied = (Fl_Anim_GIF_Image *)orig->copy(W, H);
if (!copied->valid()) { // check success of copy
Fl::warning("Fl_Anim_GIF_Image::copy() %d x %d failed", W, H);
}
else {
printf("resized to %d x %d\n", copied->w(), copied->h());
}
copied->canvas(this, Fl_Anim_GIF_Image::DONT_RESIZE_CANVAS);
}
window()->cursor(FL_CURSOR_DEFAULT);
}
static void do_resize_cb(void *d) {
Canvas *c = (Canvas *)d;
c->do_resize(c->w(), c->h());
}
void resize(int x, int y, int w, int h) FL_OVERRIDE {
Inherited::resize(x, y, w, h);
// decouple resize event from actual resize operation
// to avoid lockups..
Fl::remove_timeout(do_resize_cb, this);
Fl::add_timeout(0.1, do_resize_cb, this);
window()->cursor(FL_CURSOR_WAIT);
}
};
int main(int argc, char *argv[]) {
// setup play parameters from args
const char *fileName = 0;
bool bilinear = false;
bool optimize = false;
bool uncache = false;
bool debug = false;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-b")) // turn bilinear scaling on
bilinear = true;
else if (!strcmp(argv[i], "-o")) // turn optimize on
optimize = true;
else if (!strcmp(argv[i], "-g")) // disable grid
draw_grid = false;
else if (!strcmp(argv[i], "-u")) // uncache
uncache = true;
else if (!strcmp(argv[i], "-d")) // debug
debug = true;
else if (argv[i][0] != '-' && !fileName) {
fileName = argv[i];
}
else if (argv[i][0] == '-') {
printf("Invalid argument: '%s'\n", argv[i]);
exit(1);
}
}
if (!fileName) {
fprintf(stderr, "Test program for animated copy.\n");
fprintf(stderr, "Usage: %s fileName [-b]ilinear [-o]ptimize [-g]rid [-u]ncache\n", argv[0]);
exit(0);
}
Fl_Anim_GIF_Image::min_delay = 0.1; // set a minumum delay for playback
Fl_Double_Window win(640, 480);
// prepare a canvas for the animation
// (we want to show it in the center of the window)
Canvas canvas(0, 0, win.w(), win.h());
win.resizable(win);
win.size_range(1, 1);
win.end();
win.show();
// create/load the animated gif and start it immediately.
// We use the 'DONT_RESIZE_CANVAS' flag here to tell the
// animation not to change the canvas size (which is the default).
int flags = Fl_Anim_GIF_Image::Fl_Anim_GIF_Image::DONT_RESIZE_CANVAS;
if (optimize) {
flags |= Fl_Anim_GIF_Image::OPTIMIZE_MEMORY;
printf("Using memory optimization (if image supports)\n");
}
if (debug) {
flags |= Fl_Anim_GIF_Image::DEBUG_FLAG;
}
orig = new Fl_Anim_GIF_Image(/*name_=*/ fileName,
/*canvas_=*/ &canvas,
/*flags_=*/ flags );
// check if loading succeeded
printf("%s: valid: %d frames: %d uncache: %d\n",
orig->name(), orig->valid(), orig->frames(), orig->frame_uncache());
if (orig->valid()) {
win.copy_label(fileName);
// print information about image optimization
int n = 0;
for (int i = 0; i < orig->frames(); i++) {
if (orig->frame_x(i) != 0 || orig->frame_y(i) != 0) n++;
}
printf("image has %d optimized frames\n", n);
Fl_Image::scaling_algorithm(FL_RGB_SCALING_NEAREST);
if (bilinear) {
Fl_Image::scaling_algorithm(FL_RGB_SCALING_BILINEAR);
printf("Using bilinear scaling - can be slow!\n");
// NOTE: this can be *really* slow with large sizes, if FLTK
// has to resize on its own without hardware scaling enabled.
}
orig->frame_uncache(uncache);
if (uncache) {
printf("Caching disabled - watch cpu load!\n");
}
// set initial size to fit into window
double ratio = orig->valid() ? (double)orig->w() / orig->h() : 1;
int W = win.w() - 40;
int H = int(W / ratio);
printf("original size: %d x %d\n", orig->w(), orig->h());
win.size(W, H);
Fl::add_handler(events);
return Fl::run();
}
}
|