diff --git a/bob/io/image/cpp/gif.cpp b/bob/io/image/cpp/gif.cpp index 57f7bcafed0f11d295fcaf848a5c5806693f6c12..e6cb0b4baccf61e67b02425529f6a8b428d63fe8 100644 --- a/bob/io/image/cpp/gif.cpp +++ b/bob/io/image/cpp/gif.cpp @@ -395,6 +395,8 @@ static void im_load_color(boost::shared_ptr<GifFileType> in_file, bob::io::base: // screen is device independent - it's the screen defined by the // GIF file parameters. std::vector<boost::shared_array<GifPixelType> > screen_buffer; + // The second buffer is just used if the image has already been read + boost::shared_array<GifPixelType> temp_buffer(new GifPixelType[in_file->SWidth]); // Size in bytes one row. int size = in_file->SWidth*sizeof(GifPixelType); @@ -415,52 +417,71 @@ static void im_load_color(boost::shared_ptr<GifFileType> in_file, bob::io::base: GifByteType *extension; int InterlacedOffset[] = { 0, 4, 2, 1 }; // The way Interlaced image should. int InterlacedJumps[] = { 8, 8, 4, 2 }; // be read - offsets and jumps... - int row, col, width, height, count, ext_code; - int error = DGifGetRecordType(in_file.get(), &record_type); - if(error == GIF_ERROR) - GifErrorHandler("DGifGetRecordType", error); - switch(record_type) { - case IMAGE_DESC_RECORD_TYPE: - error = DGifGetImageDesc(in_file.get()); - if (error == GIF_ERROR) GifErrorHandler("DGifGetImageDesc", error); - row = in_file->Image.Top; // Image Position relative to Screen. - col = in_file->Image.Left; - width = in_file->Image.Width; - height = in_file->Image.Height; - if(in_file->Image.Left + in_file->Image.Width > in_file->SWidth || - in_file->Image.Top + in_file->Image.Height > in_file->SHeight) - { - throw std::runtime_error("GIF: the dimensions of image larger than the dimensions of the canvas."); - } - if(in_file->Image.Interlace) { - // Need to perform 4 passes on the images: - for(int i=count=0; i<4; ++i) - for(int j=row+InterlacedOffset[i]; j<row+height; j+=InterlacedJumps[i]) { - ++count; - error = DGifGetLine(in_file.get(), &screen_buffer[j][col], width); - if(error == GIF_ERROR) GifErrorHandler("DGifGetLine", error); + int row, col, width, height, ext_code; + bool terminated = false; + bool image_found = false; + do{ + int error = DGifGetRecordType(in_file.get(), &record_type); + if(error == GIF_ERROR) + GifErrorHandler("DGifGetRecordType", in_file->Error); + switch(record_type) { + case IMAGE_DESC_RECORD_TYPE: + error = DGifGetImageDesc(in_file.get()); + if (error == GIF_ERROR) GifErrorHandler("DGifGetImageDesc", in_file->Error); + row = in_file->Image.Top; // Image Position relative to Screen. + col = in_file->Image.Left; + width = in_file->Image.Width; + height = in_file->Image.Height; + if(in_file->Image.Left + in_file->Image.Width > in_file->SWidth || + in_file->Image.Top + in_file->Image.Height > in_file->SHeight) + { + throw std::runtime_error("GIF: the dimensions of image larger than the dimensions of the canvas."); + } + if(in_file->Image.Interlace) { + // Need to perform 4 passes on the images: + for(int i=0; i<4; ++i) + for(int j=row+InterlacedOffset[i]; j<row+height; j+=InterlacedJumps[i]) { + if (image_found) + // image buffer already filled; read in into junk buffer + error = DGifGetLine(in_file.get(), &temp_buffer[col], width); + else + // read into image buffer + error = DGifGetLine(in_file.get(), &screen_buffer[j][col], width); + if(error == GIF_ERROR) GifErrorHandler("DGifGetLine", in_file->Error); + } + } + else { + for(int i=0; i<height; ++i) { + if (image_found) + // image buffer already filled; read in into junk buffer + error = DGifGetLine(in_file.get(), &temp_buffer[col], width); + else + // read into image buffer + error = DGifGetLine(in_file.get(), &screen_buffer[row++][col], width); + if(error == GIF_ERROR) GifErrorHandler("DGifGetLine", in_file->Error); } - } - else { - for(int i=0; i<height; ++i) { - error = DGifGetLine(in_file.get(), &screen_buffer[row++][col], width); - if(error == GIF_ERROR) GifErrorHandler("DGifGetLine", error); } - } - break; - case EXTENSION_RECORD_TYPE: - // Skip any extension blocks in file: - error = DGifGetExtension(in_file.get(), &ext_code, &extension); - if (error == GIF_ERROR) GifErrorHandler("DGifGetExtension", error); - while(extension != NULL) { - error = DGifGetExtensionNext(in_file.get(), &extension); - if(error == GIF_ERROR) GifErrorHandler("DGifGetExtensionNext", error); - } - break; - case TERMINATE_RECORD_TYPE: - break; - default: // Should be trapped by DGifGetRecordType. - break; + image_found = true; + break; + case EXTENSION_RECORD_TYPE: + // Skip any extension blocks in file: + error = DGifGetExtension(in_file.get(), &ext_code, &extension); + if (error == GIF_ERROR) GifErrorHandler("DGifGetExtension", in_file->Error); + while(extension != NULL) { + error = DGifGetExtensionNext(in_file.get(), &extension); + if(error == GIF_ERROR) GifErrorHandler("DGifGetExtensionNext", in_file->Error); + } + break; + case TERMINATE_RECORD_TYPE: + terminated = true; + break; + default: // Should be trapped by DGifGetRecordType. + break; + } + } while (!terminated); + + if (!image_found){ + std::runtime_error("GIF: image does not contain an image section"); } // Lets dump it - set the global variables required and do it: @@ -553,15 +574,15 @@ static void im_save_color(const bob::io::base::array::interface& b, boost::share error = EGifPutScreenDesc(out_file.get(), width, height, ExpNumOfColors, 0, OutputColorMap); - if (error == GIF_ERROR) GifErrorHandler("EGifPutScreenDesc", error); + if (error == GIF_ERROR) GifErrorHandler("EGifPutScreenDesc", out_file->Error); error = EGifPutImageDesc(out_file.get(), 0, 0, width, height, false, NULL); - if (error == GIF_ERROR) GifErrorHandler("EGifPutImageDesc", error); + if (error == GIF_ERROR) GifErrorHandler("EGifPutImageDesc", out_file->Error); GifByteType *ptr = output_buffer.get(); for(int i=0; i<height; ++i) { error = EGifPutLine(out_file.get(), ptr, width); - if (error == GIF_ERROR) GifErrorHandler("EGifPutImageDesc", error); + if (error == GIF_ERROR) GifErrorHandler("EGifPutImageDesc", out_file->Error); ptr += width; } diff --git a/bob/io/image/data/test.gif b/bob/io/image/data/test.gif new file mode 100644 index 0000000000000000000000000000000000000000..8c770fb7b60d43b03b89dc695425e811339963b3 Binary files /dev/null and b/bob/io/image/data/test.gif differ diff --git a/bob/io/image/test.py b/bob/io/image/test.py index 7e21f38bf2c5d09f90fb3fe3f89810814a00d463..b86b27a34d7cb4472d4041415015215a339c9bd8 100644 --- a/bob/io/image/test.py +++ b/bob/io/image/test.py @@ -105,9 +105,15 @@ def test_netpbm(): # because of re-compression +def notest_gif(): + transcode(test_utils.datafile('test.gif', __name__)) + + def test_image_load(): # test that the generic bob.io.image.load function works as expected - for filename in ('test.jpg', 'cmyk.jpg', 'test.pbm', 'test_corrupted.pbm', 'test.pgm', 'test_corrupted.pgm', 'test.ppm', 'test_corrupted.ppm', 'img_rgba_color.png'): + for filename in ('test.jpg', 'cmyk.jpg', 'test.pbm', 'test_corrupted.pbm', + 'test.pgm', 'test_corrupted.pgm', 'test.ppm', 'test_corrupted.ppm', + 'img_rgba_color.png', 'test.gif'): full_file = test_utils.datafile(filename, __name__) # load with just image name i1 = bob.io.image.load(full_file)