core/vil/file_formats/vil_jpeg.cxx
Go to the documentation of this file.
00001 // This is core/vil/file_formats/vil_jpeg.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 // \date   17 Feb 2000
00009 // \verbatim
00010 //  Modifications
00011 //     11 Oct 2002 Ian Scott - converted to vil
00012 //     30 Mar 2007 Peter Vanroose - replaced deprecated vil_new_image_view_j_i_plane()
00013 //\endverbatim
00014 
00015 #include "vil_jpeg.h"
00016 #include "vil_jpeg_source_mgr.h"
00017 #include "vil_jpeg_decompressor.h"
00018 #include "vil_jpeg_destination_mgr.h"
00019 #include "vil_jpeg_compressor.h"
00020 
00021 #include <vcl_cassert.h>
00022 #include <vcl_iostream.h>
00023 #include <vcl_cstring.h> // memcpy()
00024 #include <vxl_config.h> // vxl_byte
00025 
00026 #include <vil/vil_stream.h>
00027 #include <vil/vil_image_view.h>
00028 #include <vil/vil_exception.h>
00029 
00030 //: the file probe, as a C function.
00031 bool vil_jpeg_file_probe(vil_stream *vs)
00032 {
00033   char magic[2];
00034   vs->seek(0L);
00035   vil_streampos n = vs->read(magic, sizeof(magic));
00036 
00037   if (n != sizeof(magic)) {
00038     vcl_cerr << __FILE__ << " : vil_stream::read() failed\n";
00039     return false;
00040   }
00041 
00042   // 0xFF followed by 0xD8
00043   return (magic[0] == char(0xFF)) && (magic[1] == char(0xD8));
00044 }
00045 
00046 // static data
00047 static char const jpeg_string[] = "jpeg";
00048 
00049 //--------------------------------------------------------------------------------
00050 // class vil_jpeg_file_format
00051 
00052 char const* vil_jpeg_file_format::tag() const
00053 {
00054   return jpeg_string;
00055 }
00056 
00057 //:
00058 vil_image_resource_sptr  vil_jpeg_file_format::make_input_image(vil_stream *vs)
00059 {
00060   return vil_jpeg_file_probe(vs) ? new vil_jpeg_image(vs) : 0;
00061 }
00062 
00063 vil_image_resource_sptr
00064   vil_jpeg_file_format::make_output_image(vil_stream* vs,
00065                                           unsigned nx,
00066                                           unsigned ny,
00067                                           unsigned nplanes,
00068                                           enum vil_pixel_format format)
00069 {
00070   if (format != VIL_PIXEL_FORMAT_BYTE)
00071   {
00072     vcl_cout<<"ERROR! vil_jpeg_file_format::make_output_image()\n"
00073             <<"Pixel format should be byte, but is "<<format<<" instead.\n";
00074     return 0;
00075   }
00076   return new vil_jpeg_image(vs, nx, ny, nplanes, format);
00077 }
00078 
00079 //--------------------------------------------------------------------------------
00080 
00081 // class vil_jpeg_image
00082 
00083 vil_jpeg_image::vil_jpeg_image(vil_stream *s)
00084   : jc(0)
00085   , jd(new vil_jpeg_decompressor(s))
00086   , stream(s)
00087 {
00088   stream->ref();
00089 }
00090 
00091 bool vil_jpeg_image::get_property(char const * /*tag*/, void * /*prop*/) const
00092 {
00093   // This is not an in-memory image type, nor is it read-only:
00094   return false;
00095 }
00096 
00097 void vil_jpeg_image::set_quality(int quality)
00098 {
00099   if( jc )
00100     jc->set_quality(quality);
00101 }
00102 
00103 vil_jpeg_image::vil_jpeg_image(vil_stream *s,
00104                                unsigned nx,
00105                                unsigned ny,
00106                                unsigned nplanes,
00107                                enum vil_pixel_format format)
00108   : jc(new vil_jpeg_compressor(s))
00109   , jd(0)
00110   , stream(s)
00111 {
00112   if (format != VIL_PIXEL_FORMAT_BYTE)
00113     vcl_cerr << "Sorry -- pixel format " << format << " not yet supported\n";
00114   assert(format == VIL_PIXEL_FORMAT_BYTE); // FIXME.
00115 
00116   stream->ref();
00117 
00118   // use same number of components as prototype, obviously.
00119   jc->jobj.input_components = nplanes;
00120 
00121   // store size
00122   jc->jobj.image_width = nx;
00123   jc->jobj.image_height = ny;
00124 #ifdef DEBUG
00125   vcl_cerr << "w h = " << nx << ' ' << ny << '\n';
00126 #endif
00127 }
00128 
00129 vil_jpeg_image::~vil_jpeg_image()
00130 {
00131   // FIXME: I suspect there's a core leak here because jpeg_destroy() does not
00132   // free the vil_jpeg_stream_source_mgr allocated in vil_jpeg_stream_xxx_set()
00133   if (jd)
00134     delete jd;
00135   jd = 0;
00136   if (jc)
00137     delete jc;
00138   jc = 0;
00139   stream->unref();
00140   stream = 0;
00141 }
00142 
00143 //--------------------------------------------------------------------------------
00144 
00145 //: decompressing from the vil_stream to a section buffer.
00146 vil_image_view_base_sptr vil_jpeg_image::get_copy_view(unsigned x0,
00147                                                        unsigned nx,
00148                                                        unsigned y0,
00149                                                        unsigned ny) const
00150 {
00151   if (!jd) {
00152     vcl_cerr << "attempted get_copy_view() failed -- no jpeg decompressor\n";
00153     return 0;
00154   }
00155 #ifdef DEBUG
00156   vcl_cerr << "get_copy_view " << ' ' << x0 << ' ' << nx << ' ' << y0 << ' ' << ny << '\n';
00157 #endif
00158 
00159   // number of bytes per pixel
00160   unsigned bpp = jd->jobj.output_components;
00161 
00162   vil_memory_chunk_sptr chunk = new vil_memory_chunk(bpp * nx * ny, pixel_format());
00163 
00164   for (unsigned int i=0; i<ny; ++i) {
00165     JSAMPLE const *scanline = jd->read_scanline(y0+i);
00166     if (!scanline)
00167       return 0; // failed
00168 
00169     vcl_memcpy(reinterpret_cast<char*>(chunk->data()) + i*nx*bpp, &scanline[x0*bpp], nx*bpp);
00170   }
00171 
00172   return new vil_image_view<vxl_byte>(chunk, reinterpret_cast<vxl_byte *>(chunk->data()), nx, ny, bpp, bpp, bpp*nx, 1);
00173 }
00174 
00175 //--------------------------------------------------------------------------------
00176 
00177 //: compressing a section onto the vil_stream.
00178 bool vil_jpeg_image::put_view(const vil_image_view_base &view,
00179                               unsigned x0, unsigned y0)
00180 {
00181 
00182   if (!view_fits(view, x0, y0))
00183   {
00184     vil_exception_warning(vil_exception_out_of_bounds("vil_jpeg_image::put_view"));
00185     return false;
00186   }
00187 
00188   if (!jc) {
00189     vcl_cerr << "attempted put_view() failed -- no jpeg compressor\n";
00190     return false;
00191   }
00192 
00193   if (view.pixel_format() != VIL_PIXEL_FORMAT_BYTE)
00194   {
00195     vcl_cerr << "vil_jpeg_image::put_view() failed -- can only deal with byte images\n";
00196     return false;
00197   }
00198 
00199   const vil_image_view<vxl_byte>& view2 =
00200     static_cast<const vil_image_view<vxl_byte>&>(view);
00201 
00202   // "compression makes no sense unless the section covers the whole image."
00203   // Relaxed slightly.. awf.
00204   // It will work if you send entire scan lines sequentially
00205   if (x0 != 0 || view2.ni() != jc->jobj.image_width) {
00206     vcl_cerr << __FILE__ << " : Can only compress complete scanlines\n";
00207     return false;
00208   }
00209   if (y0 != jc->jobj.next_scanline) {
00210     vcl_cerr << __FILE__ << " : Scanlines must be sent sequentially\n";
00211     return false;
00212   }
00213 
00214   // write each scanline
00215   if ((view2.planestep() == 1 || view2.nplanes() == 1) && view2.istep() == jc->jobj.input_components)
00216   {
00217     assert(view2.istep() > 0);
00218     assert(view2.istep() == jc->jobj.input_components); // bytes per pixel in the section
00219     for (unsigned int j=0; j<view2.nj(); ++j) {
00220       JSAMPLE const *scanline = (JSAMPLE const*)
00221         &view2(0,j);
00222       if (!jc->write_scanline(y0+j, scanline))
00223         return false;
00224     }
00225   }
00226   else
00227   {
00228     vil_memory_chunk_sptr chunk = new vil_memory_chunk(view2.ni()*view2.nplanes(), vil_pixel_format_component_format(vil_pixel_format_of(vxl_byte())));
00229     vil_image_view<vxl_byte> line = vil_image_view<vxl_byte>(chunk, reinterpret_cast<vxl_byte*>(chunk->data()), view2.ni(), 1, view2.nplanes(), view2.nplanes(), view2.nplanes()*view2.ni(), 1);
00230     JSAMPLE *scanline = line.top_left_ptr();
00231 
00232     for (unsigned int j=0; j<view2.nj(); ++j)
00233     {
00234       // arrange data into componentwise form.
00235       for (unsigned i = 0; i < view2.ni(); ++i)
00236         for (unsigned p = 0; p < view2.nplanes(); ++p)
00237           line(i,0,p) = view2(i,j,p);
00238       if (!jc->write_scanline(y0+j, scanline))
00239         return false;
00240     }
00241   }
00242 
00243   return true;
00244 }
00245 
00246 //--------------------------------------------------------------------------------
00247 
00248 
00249 unsigned vil_jpeg_image::ni() const
00250 {
00251   if (jd) return jd->jobj.output_width;
00252   if (jc) return jc->jobj.image_width;
00253   return 0;
00254 }
00255 
00256 unsigned vil_jpeg_image::nj() const
00257 {
00258   if (jd) return jd->jobj.output_height;
00259   if (jc) return jc->jobj.image_height;
00260   return 0;
00261 }
00262 
00263 unsigned vil_jpeg_image::nplanes() const
00264 {
00265   if (jd) return jd->jobj.output_components;
00266   if (jc) return jc->jobj.input_components;
00267   return 0;
00268 }
00269 
00270 
00271 vil_pixel_format vil_jpeg_image::pixel_format() const
00272 {
00273   return VIL_PIXEL_FORMAT_BYTE;
00274 }
00275 
00276 
00277 char const *vil_jpeg_image::file_format() const
00278 {
00279   return jpeg_string;
00280 }
00281 
00282 //--------------------------------------------------------------------------------