00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
00009 #include "vil1_gif.h"
00010
00011 #include <vcl_cassert.h>
00012 #include <vcl_iomanip.h>
00013 #include <vcl_iostream.h>
00014 #include <vcl_cstring.h>
00015 #include <vcl_cctype.h>
00016
00017 #include <vil1/vil1_stream.h>
00018 #include <vil1/vil1_16bit.h>
00019 #include <vil1/vil1_property.h>
00020
00021 #ifndef VERBOSE // set this to 1 on the compile line if you want verbose output
00022 #define VERBOSE 0
00023 #endif
00024
00025 bool vil1_gif_probe(vil1_stream *s)
00026 {
00027
00028 s->seek(0L);
00029 char magic[6];
00030 s->read(magic, sizeof magic);
00031
00032 if (magic[0] != 0x47 ||
00033 magic[1] != 0x49 ||
00034 magic[2] != 0x46 )
00035 return false;
00036
00037 if (magic[3] != 0x38 ||
00038 magic[4] != 0x37 ||
00039 magic[5] != 0x61 ) {
00040 vcl_cerr << __FILE__ ": file format may be GIF, but is not v87\n";
00041
00042 return false;
00043 }
00044 return true;
00045 }
00046
00047 char const *vil1_gif_file_format::tag() const { return "gif"; }
00048
00049 vil1_image_impl *vil1_gif_file_format::make_input_image(vil1_stream *s)
00050 {
00051 if (! vil1_gif_probe(s))
00052 return 0;
00053 else
00054 return new vil1_gif_loader_saver(s);
00055 }
00056
00057 vil1_image_impl *vil1_gif_file_format::make_output_image(vil1_stream*, int, int, int, int, int, vil1_component_format)
00058 {
00059 vcl_cerr << "GIF writer not yet implemented\n";
00060 return 0;
00061 }
00062
00063 bool vil1_gif_loader_saver::get_property(char const *tag, void *prop) const
00064 {
00065 if (0==vcl_strcmp(tag, vil1_property_top_row_first))
00066 return prop ? (*(bool*)prop) = true : true;
00067
00068 if (0==vcl_strcmp(tag, vil1_property_left_first))
00069 return prop ? (*(bool*)prop) = true : true;
00070
00071 return false;
00072 }
00073
00074 vil1_gif_loader_saver::vil1_gif_loader_saver(vil1_stream *s_)
00075 : s(s_), is_grey(false)
00076 {
00077 s->ref();
00078 assert(vil1_gif_probe(s));
00079
00080 s->seek(6L);
00081
00082
00083 screen_width_ = vil1_16bit_read_little_endian(s);
00084 screen_height_ = vil1_16bit_read_little_endian(s);
00085 #if VERBOSE
00086 vcl_cerr << "screen width and height : "
00087 << screen_width_ << ' ' << screen_height_ << vcl_endl;
00088 #endif
00089
00090 unsigned char b;
00091
00092
00093
00094 {
00095 s->read(&b, 1L);
00096 #if VERBOSE
00097 vcl_cerr << "b = 0x" << vcl_hex << int(b) << vcl_dec << vcl_endl;
00098 #endif
00099
00100 int bits_of_colour_res;
00101 if (b & 0x80) {
00102 bits_of_colour_res = 1 + ((b & 0x70)>>4);
00103 #if VERBOSE
00104 vcl_cerr << "screen has global colour map\n"
00105 << "screen has " << bits_of_colour_res << " bits of colour resolution\n";
00106 #endif
00107 }
00108 else
00109 bits_of_colour_res = 0;
00110
00111
00112 if (b & 0x08) {
00113 vcl_cerr << "bit 3 is not zero\n";
00114 assert(!"bit 3 should be zero");
00115 }
00116
00117 int bits_per_pixel = 1 + (b & 0x07);
00118 #if VERBOSE
00119 vcl_cerr << "screen has " << bits_per_pixel << " bits per pixel\n";
00120 #endif
00121 if (bits_per_pixel != 8) {
00122 vcl_cerr << "cannot read GIF with != 8 bits per pixel.\n";
00123 assert(!"GIF with != 8 bits per pixel not implemented");
00124 }
00125
00126
00127 if (bits_of_colour_res > 0) {
00128 global_color_map = new vil1_gif_color_map( 0x1 << bits_per_pixel );
00129 #if VERBOSE
00130 vcl_cerr << "global colour map has size " << global_color_map->size << vcl_endl;
00131 #endif
00132 }
00133
00134
00135 s->read(&b, 1L);
00136 background_index = b;
00137 #if VERBOSE
00138 vcl_cerr << "background has colour index " << background_index << vcl_endl;
00139 #endif
00140
00141
00142 s->read(&b, 1L);
00143 if (b) {
00144 vcl_cerr << "not zero\n";
00145 assert(!"this byte should be zero");
00146 }
00147 }
00148
00149
00150
00151 #if VERBOSE
00152 vcl_cerr << "position is 0x" << vcl_hex << s->tell() << vcl_dec << vcl_endl;
00153 #endif
00154 if (global_color_map) {
00155 #if VERBOSE
00156 vcl_cerr << "read global colour map\n";
00157 #endif
00158 s->read(global_color_map->cmap, 3*global_color_map->size);
00159
00160 is_grey = true;
00161 for (int i=0; is_grey && i<global_color_map->size; ++i)
00162 if (global_color_map->cmap[3*i+0] !=
00163 global_color_map->cmap[3*i+1] ||
00164 global_color_map->cmap[3*i+1] !=
00165 global_color_map->cmap[3*i+2])
00166 is_grey = false;
00167
00168 #if VERBOSE
00169 for (int i=0; i<16; ++i)
00170 vcl_cerr << vcl_setw(3) << i << ' '
00171 << int((unsigned char) global_color_map->cmap[3*i+0]) << ' '
00172 << int((unsigned char) global_color_map->cmap[3*i+1]) << ' '
00173 << int((unsigned char) global_color_map->cmap[3*i+2]) << '\n';
00174 #endif
00175 }
00176
00177
00178
00179 while (true) {
00180 vil1_streampos offset = s->tell();
00181 #if VERBOSE
00182 vcl_cerr << "position is 0x" << vcl_hex << offset << vcl_dec << vcl_endl;
00183 #endif
00184
00185
00186 s->read(&b, 1L);
00187 if (b == ';')
00188 break;
00189 if (b != ',') {
00190 vcl_cerr << "unexpected character \'";
00191 if (vcl_isprint(b)) {
00192 vcl_cerr << b;
00193 } else {
00194 vcl_cerr << "[unprintable]";
00195 }
00196 vcl_cerr<< "\' (0x" << vcl_hex<< int(b) << vcl_dec<< ") in GIF stream\n";
00197 assert(!"expected GIF separator here");
00198 }
00199
00200 vil1_gif_image_record *ir = new vil1_gif_image_record;
00201 ir->offset = offset;
00202
00203 ir->x0 = vil1_16bit_read_little_endian(s);
00204 ir->y0 = vil1_16bit_read_little_endian(s);
00205 ir->w = vil1_16bit_read_little_endian(s);
00206 ir->h = vil1_16bit_read_little_endian(s);
00207 #if VERBOSE
00208 vcl_cerr << "x0 y0 w h = " << ir->x0 << ' ' << ir->y0 << ' '
00209 << ir->w << ' ' << ir->h << vcl_endl;
00210
00211 vcl_cerr << "position is 0x" << vcl_hex << s->tell() << vcl_dec << vcl_endl;
00212 #endif
00213
00214 s->read(&b, 1L);
00215 #if VERBOSE
00216 vcl_cerr << "b = 0x" << vcl_hex << int(b) << vcl_dec << vcl_endl;
00217
00218 vcl_cerr << "position is 0x" << vcl_hex << s->tell() << vcl_dec << vcl_endl;
00219 #endif
00220 if (b & 0x80) {
00221 int bits = 1 + (b & 0x07);
00222 #if VERBOSE
00223 vcl_cerr << "image has local colour map\n"
00224 << "read local colour map (" << bits << " bits per pixel)\n";
00225 #endif
00226 ir->color_map = new vil1_gif_color_map(0x1 << bits);
00227 s->read(ir->color_map->cmap, 3*ir->color_map->size);
00228 }
00229 else {
00230 #if VERBOSE
00231 vcl_cerr << "no local colour map\n";
00232 #endif
00233 ir->color_map = 0;
00234 }
00235 #if VERBOSE
00236 vcl_cerr << "position is 0x" << vcl_hex << s->tell() << vcl_dec << vcl_endl;
00237 #endif
00238
00239
00240 ir->interlaced = ( (b & 0x40) != 0 );
00241 #if VERBOSE
00242 vcl_cerr<< "image is "<< (ir->interlaced ? "interlaced\n" : "sequential\n");
00243 #endif
00244 if (ir->interlaced) {
00245 vcl_cerr << "can't read interlaced GIFs yet\n";
00246 assert(!"interlaced GIF reading not implemented");
00247 }
00248
00249
00250 if (b & 0x38) {
00251 vcl_cerr << "bits 543 are not zero\n";
00252 assert(!"incorrect bits 3,4,5");
00253 }
00254
00255
00256 if (ir->color_map) {
00257 ir->bits_per_pixel = 1 + (b & 0x07);
00258 #if VERBOSE
00259 vcl_cerr << "image has " << ir->bits_per_pixel << " bits per pixel\n";
00260 #endif
00261 if (ir->bits_per_pixel != 8) {
00262 vcl_cerr << "cannot cope with " << ir->bits_per_pixel << " bits per pixel\n";
00263 assert(!"bpp != 8 not implemented");
00264 }
00265 }
00266 else
00267 ir->bits_per_pixel = 0;
00268
00269
00270 ir->bitmap_start = s->tell();
00271
00272
00273 s->seek(ir->bitmap_start + ir->w * ir->h);
00274
00275 images.push_back(ir);
00276 break;
00277 }
00278
00279 #if VERBOSE
00280 vcl_cerr << "read " << images.size() << " image descriptors\n"
00281 << "------------ done : position = "
00282 << vcl_hex << s->tell() << vcl_dec << vcl_endl;
00283 #endif
00284 }
00285
00286 vil1_gif_loader_saver::~vil1_gif_loader_saver()
00287 {
00288 s->unref();
00289
00290 if (global_color_map) {
00291 delete global_color_map;
00292 global_color_map = 0;
00293 }
00294
00295 for (unsigned int i=0; i<images.size(); ++i) {
00296 vil1_gif_image_record *ir = static_cast<vil1_gif_image_record*>(images[i]);
00297 if (ir->color_map)
00298 delete ir->color_map;
00299 delete ir;
00300 }
00301 images.clear();
00302 }
00303
00304 char const *vil1_gif_loader_saver::file_format() const { return "gif"; }
00305
00306 vil1_image vil1_gif_loader_saver::get_plane(unsigned int p) const
00307 {
00308 if (p<images.size())
00309 return new vil1_gif_loader_saver_proxy(p, const_cast<vil1_gif_loader_saver*>(this));
00310 else
00311 return 0;
00312 }
00313
00314 bool vil1_gif_loader_saver::get_section(void *buf, int x0, int y0, int w, int h) const
00315 {
00316 if (planes() == 1)
00317 return get_section(0, buf, x0, y0, w, h);
00318 else
00319 return false;
00320 }
00321
00322 bool vil1_gif_loader_saver::put_section(void const *buf, int x0, int y0, int w, int h)
00323 {
00324 if (planes() == 1)
00325 return put_section(0, buf, x0, y0, w, h);
00326 else
00327 return false;
00328 }
00329
00330 bool vil1_gif_loader_saver::get_section(int , void* , int , int , int , int ) const
00331 {
00332 #if 1
00333
00334 vcl_cerr << "vil1_gif_loader_saver::get_section(): LZW decompression not yet implemented\n";
00335 #else
00336 assert(0<=image && image<images.size());
00337 char *char_buf = (char*) buf;
00338
00339 vil1_gif_image_record *ir = static_cast<vil1_gif_image_record*>(images[image]);
00340
00341 #if 0
00342 for (int i=0; i<h; ++i) {
00343 s->seek(ir->bitmap_start + x0 + ir->w*(y0 + i));
00344 s->read(char_buf + w*i, w);
00345 }
00346 #else
00347 unsigned char *tmp = new unsigned char [w];
00348
00349 vil1_gif_color_map *cm = ir->color_map ? ir->color_map : global_color_map;
00350
00351 for (int i=0; i<h; ++i) {
00352 s->seek(ir->bitmap_start + x0 + ir->w*(y0 + i));
00353 s->read(tmp, w);
00354 for (int j=0; j<w; ++j) {
00355 int index = int(tmp[j]);
00356 (char_buf + 3*w*i)[3*j + 0] = cm->cmap[3*index + 0];
00357 (char_buf + 3*w*i)[3*j + 1] = cm->cmap[3*index + 1];
00358 (char_buf + 3*w*i)[3*j + 2] = cm->cmap[3*index + 2];
00359 }
00360 }
00361
00362 delete [] tmp;
00363 #endif
00364 #endif
00365 return true;
00366 }