core/vil/file_formats/vil_png.cxx
Go to the documentation of this file.
00001 // This is core/vil/file_formats/vil_png.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // http://www.libpng.org/pub/png/libpng.html
00008 
00009 #include "vil_png.h"
00010 
00011 #include <vcl_cassert.h>
00012 #include <vcl_cstring.h>
00013 #include <vcl_iostream.h>
00014 #include <vcl_algorithm.h>
00015 
00016 #include <vil/vil_stream.h>
00017 #include <vil/vil_image_view.h>
00018 #include <vil/vil_property.h>
00019 #include <vil/vil_exception.h>
00020 
00021 #include <png.h>
00022 #if (PNG_LIBPNG_VER_MAJOR == 0)
00023 extern "You need a later libpng. You should rerun CMake, after setting VXL_FORCE_V3P_PNG to ON."
00024 #endif
00025 #include <vcl_cstdlib.h> // for vcl_exit()
00026 
00027 #include <vxl_config.h>
00028 
00029 // Constants
00030 #define SIG_CHECK_SIZE 4
00031 
00032 char const* vil_png_format_tag = "png";
00033 
00034 // Functions
00035 static bool problem(char const* msg)
00036 {
00037   vcl_cerr << "[vil_png: PROBLEM " <<msg << ']';
00038   return false;
00039 }
00040 
00041 vil_image_resource_sptr vil_png_file_format::make_input_image(vil_stream* is)
00042 {
00043   // Attempt to read header
00044   png_byte sig_buf [SIG_CHECK_SIZE];
00045   if (is->read(sig_buf, SIG_CHECK_SIZE) != SIG_CHECK_SIZE) {
00046     problem("Initial header fread");
00047     return 0;
00048   }
00049 
00050   if (png_sig_cmp (sig_buf, (png_size_t) 0, (png_size_t) SIG_CHECK_SIZE) != 0)
00051     return 0;
00052 
00053   return new vil_png_image(is);
00054 }
00055 
00056 vil_image_resource_sptr vil_png_file_format::make_output_image(vil_stream* vs,
00057                                                                unsigned nx,
00058                                                                unsigned ny,
00059                                                                unsigned nplanes,
00060                                                                enum vil_pixel_format format)
00061 {
00062   if (format != VIL_PIXEL_FORMAT_BYTE &&
00063       format != VIL_PIXEL_FORMAT_UINT_16)
00064   // FIXME || format != VIL_PIXEL_FORMAT_BOOL
00065 
00066   {
00067     vcl_cout<<"ERROR! vil_png_file_format::make_output_image()\n"
00068             <<"Pixel format should be byte, but is "<<format<<" instead.\n";
00069     return 0;
00070   }
00071 
00072   return new vil_png_image(vs, nx, ny, nplanes, format);
00073 }
00074 
00075 char const* vil_png_file_format::tag() const
00076 {
00077   return vil_png_format_tag;
00078 }
00079 
00080 /////////////////////////////////////////////////////////////////////////////
00081 
00082 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
00083 {
00084   vil_stream* f = static_cast<vil_stream*>(png_get_io_ptr(png_ptr));
00085   f->read(data, length);
00086 }
00087 
00088 static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
00089 {
00090   vil_stream* f = static_cast<vil_stream*>(png_get_io_ptr(png_ptr));
00091   f->write(data, length);
00092 }
00093 
00094 static void user_flush_data(png_structp /*png_ptr*/)
00095 {
00096   // IOFile* f = (IOFile*)png_get_io_ptr(png_ptr);
00097   // urk.  how to flush?
00098 }
00099 
00100 struct vil_jmpbuf_wrapper
00101 {
00102   jmp_buf jmpbuf;
00103 };
00104 
00105 static vil_jmpbuf_wrapper pngtopnm_jmpbuf_struct;
00106 static bool jmpbuf_ok = false;
00107 
00108 // Must be  a macro - setjmp needs its stack frame to live
00109 #define png_setjmp_on(ACTION) \
00110   do {\
00111     jmpbuf_ok = true;\
00112     if (setjmp (pngtopnm_jmpbuf_struct.jmpbuf) != 0) {\
00113       problem("png_setjmp_on");\
00114       ACTION;\
00115     }\
00116   } while (false);
00117 #define png_setjmp_off() (jmpbuf_ok = false)
00118 
00119 // this function, aside from the extra step of retrieving the "error
00120 // pointer" (below) and the fact that it exists within the application
00121 // rather than within libpng, is essentially identical to libpng's
00122 // default error handler.  The second point is critical:  since both
00123 // setjmp() and longjmp() are called from the same code, they are
00124 // guaranteed to have compatible notions of how big a jmp_buf is,
00125 // regardless of whether _BSD_SOURCE or anything else has (or has not)
00126 // been defined.
00127 //
00128 static void pngtopnm_error_handler (png_structp png_ptr, png_const_charp msg)
00129 {
00130   vcl_cerr << "vil_png:  fatal libpng error: " << msg << '\n';
00131 
00132   if (!jmpbuf_ok) {
00133     // Someone called the error handler when the setjmp was wrong
00134     vcl_cerr << "vil_png: jmpbuf is pretty far from ok.  returning\n";
00135     // vcl_abort();
00136     return;
00137   }
00138 
00139   vil_jmpbuf_wrapper  *jmpbuf_ptr = static_cast<vil_jmpbuf_wrapper*>(png_get_error_ptr(png_ptr));
00140   if (jmpbuf_ptr == NULL) {         // we are completely hosed now
00141     vcl_cerr << "pnmtopng:  EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n";
00142     vcl_exit(99);
00143   }
00144 
00145   longjmp(jmpbuf_ptr->jmpbuf, 1);
00146 }
00147 
00148 struct vil_png_structures
00149 {
00150   bool reading_;
00151   png_struct *png_ptr;
00152   png_info *info_ptr;
00153   png_byte **rows;
00154   int channels;
00155   bool ok;
00156 
00157   vil_png_structures(bool reading)
00158   {
00159     reading_ = reading;
00160     png_ptr = 0;
00161     info_ptr = 0;
00162     rows = 0;
00163     channels = 0;
00164     ok = false;
00165 
00166     png_setjmp_on(return);
00167 
00168     if (reading)
00169       png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &pngtopnm_jmpbuf_struct, pngtopnm_error_handler, NULL);
00170     else
00171       png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, &pngtopnm_jmpbuf_struct, pngtopnm_error_handler, NULL);
00172 
00173     if (!png_ptr) {
00174       problem("cannot allocate LIBPNG structure");
00175       return;
00176     }
00177 
00178     info_ptr = png_create_info_struct (png_ptr);
00179     if (!info_ptr) {
00180       png_destroy_read_struct(&png_ptr, NULL, NULL);
00181       problem("cannot allocate LIBPNG structures");
00182       return;
00183     }
00184 
00185     ok = true;
00186 
00187     // Now jmpbuf is broken, hope noone calls png....
00188     png_setjmp_off();
00189   }
00190 
00191   bool alloc_image()
00192   {
00193     rows = new png_byte* [png_get_image_height(png_ptr, info_ptr)];
00194     if (rows == 0)
00195       return ok = problem("couldn't allocate space for image");
00196 
00197     unsigned long linesize;
00198     if (png_get_bit_depth(png_ptr, info_ptr) == 16)
00199       linesize = 2 * png_get_image_width(png_ptr, info_ptr);
00200     else
00201       linesize = png_get_image_width(png_ptr, info_ptr);
00202 
00203     if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA)
00204       linesize *= 2;
00205     else
00206       if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB)
00207         linesize *= 3;
00208       else
00209         if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB_ALPHA)
00210           linesize *= 4;
00211 
00212     unsigned int height = png_get_image_height(png_ptr,info_ptr);
00213     // Alloc the whole thing at once
00214     rows[0] = new png_byte[linesize * height];
00215     if (!rows[0])
00216       return ok = problem("couldn't allocate space for image");
00217 
00218     // Re-point rows.
00219     for (unsigned int y = 1; y < height; ++y)
00220       rows[y] = rows[0] + y * linesize;
00221 
00222     return true;
00223   }
00224 
00225   png_byte** get_rows()
00226   {
00227     if (reading_) {
00228       if (!rows) {
00229         if (alloc_image()) {
00230           png_setjmp_on(return 0);
00231           png_read_image (png_ptr, rows);
00232           png_read_end (png_ptr, info_ptr);
00233           png_setjmp_off();
00234         }
00235       }
00236     }
00237     else {
00238       assert(rows != 0);
00239     }
00240 
00241     return rows;
00242   }
00243 
00244   ~vil_png_structures()
00245   {
00246     png_setjmp_on(goto del);
00247     if (reading_) {
00248       // Reading - just delete
00249       png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
00250     }
00251     else {
00252       // Writing - save the rows
00253       png_write_image(png_ptr, rows);
00254       png_write_end(png_ptr, info_ptr);
00255 
00256       png_destroy_write_struct (&png_ptr, &info_ptr);
00257     }
00258     png_setjmp_off();
00259 
00260    del:
00261     if (rows) {
00262       delete [] rows[0];
00263       delete [] rows;
00264     }
00265   }
00266 };
00267 
00268 
00269 /////////////////////////////////////////////////////////////////////////////
00270 
00271 vil_png_image::vil_png_image(vil_stream* is)
00272 : vs_(is),
00273   p_(new vil_png_structures(true))
00274 {
00275   vs_->ref();
00276   read_header();
00277 }
00278 
00279 bool vil_png_image::get_property(char const *key, void * value) const
00280 {
00281   if (vcl_strcmp(vil_property_quantisation_depth, key)==0)
00282   {
00283     if (value)
00284       *static_cast<unsigned int*>(value) = bits_per_component_;
00285     return true;
00286   }
00287 
00288   return false;
00289 }
00290 
00291 vil_png_image::vil_png_image(vil_stream *s,
00292                              unsigned nx,
00293                              unsigned ny,
00294                              unsigned nplanes,
00295                              enum vil_pixel_format format)
00296 : vs_(s),
00297   width_(nx),
00298   height_(ny),
00299   components_(nplanes),
00300   format_(format),
00301   p_(new vil_png_structures(false))
00302 {
00303   if (format == VIL_PIXEL_FORMAT_BOOL) bits_per_component_ = 1;
00304   else bits_per_component_ = vil_pixel_format_sizeof_components(format) * 8;
00305 
00306   vs_->ref();
00307   write_header();
00308   assert(format == VIL_PIXEL_FORMAT_BYTE ||
00309          format == VIL_PIXEL_FORMAT_UINT_16);
00310   // FIXME || format == VIL_PIXEL_FORMAT_BOOL
00311 }
00312 
00313 vil_png_image::~vil_png_image()
00314 {
00315   delete p_;
00316   vs_->unref();
00317 }
00318 
00319 
00320 char const* vil_png_image::file_format() const
00321 {
00322   return vil_png_format_tag;
00323 }
00324 
00325 bool vil_png_image::read_header()
00326 {
00327   if (!p_->ok)
00328     return false;
00329 
00330   png_setjmp_on(return false);
00331 
00332   vs_->seek(0L);
00333   png_byte sig_buf [SIG_CHECK_SIZE];
00334   if (vs_->read(sig_buf, SIG_CHECK_SIZE) != SIG_CHECK_SIZE) {
00335     png_setjmp_off();
00336     return problem("Initial header fread");
00337   }
00338 
00339   if (png_sig_cmp (sig_buf, (png_size_t) 0, (png_size_t) SIG_CHECK_SIZE) != 0) {
00340     png_setjmp_off();
00341     return problem("png_sig_cmp");
00342   }
00343 
00344   //
00345   // First read info
00346   png_set_read_fn(p_->png_ptr, vs_, user_read_data);
00347   png_set_sig_bytes (p_->png_ptr, SIG_CHECK_SIZE);
00348   png_read_info (p_->png_ptr, p_->info_ptr);
00349 
00350 
00351   png_byte const color_type = png_get_color_type(p_->png_ptr, p_->info_ptr);
00352   png_byte const bit_depth = png_get_bit_depth(p_->png_ptr, p_->info_ptr);   // valid values are 1, 2, 4, 8, or 16
00353   bool is_bool_image = false;
00354 
00355 #if 1
00356   if (color_type == PNG_COLOR_TYPE_PALETTE) {
00357     assert( bit_depth <= 8 );    // valid bit depth 1, 2, 4, 8
00358     png_set_palette_to_rgb(p_->png_ptr);
00359   }
00360   if (color_type == PNG_COLOR_TYPE_GRAY) {
00361     if (bit_depth==1) { //treat 1-bit image as bool image
00362       is_bool_image = true;
00363       png_set_packing(p_->png_ptr);  // This code expands pixels per byte without changing the values of the pixels"
00364     }
00365     else if (bit_depth < 8)  // treat these images as 8-bit greyscale image
00366       png_set_expand_gray_1_2_4_to_8(p_->png_ptr);
00367   }
00368   if (png_get_valid(p_->png_ptr, p_->info_ptr, PNG_INFO_tRNS)) {
00369     int channels = png_get_channels(p_->png_ptr, p_->info_ptr);
00370     assert( channels == 1 || channels == 3 );
00371     png_set_tRNS_to_alpha(p_->png_ptr);
00372   }
00373 #else
00374   // According to manual:
00375   // "This code expands ... per byte without changing the values of the pixels"
00376   // But this is not desired if it has palette
00377   if (png_get_bit_depth(p_->png_ptr, p_->info_ptr) < 8)
00378     png_set_packing (p_->png_ptr);
00379 #endif
00380 
00381 #if VXL_LITTLE_ENDIAN
00382   // PNG stores data MSB
00383   if ( png_get_bit_depth(p_->png_ptr, p_->info_ptr) > 8 )
00384     png_set_swap(p_->png_ptr);
00385 #endif
00386 
00387   png_color_8p sig_bit;
00388   if (png_get_valid(p_->png_ptr, p_->info_ptr, PNG_INFO_sBIT) && png_get_sBIT(p_->png_ptr, p_->info_ptr, &sig_bit)) {
00389     png_byte max_bits = sig_bit->red;
00390     max_bits = vcl_max( max_bits, sig_bit->green );
00391     max_bits = vcl_max( max_bits, sig_bit->blue );
00392     max_bits = vcl_max( max_bits, sig_bit->gray );
00393     max_bits = vcl_max( max_bits, sig_bit->alpha );
00394     png_set_shift(p_->png_ptr, sig_bit);
00395   }
00396 
00397   //
00398   //  Update the info after putting in all these transforms
00399   //  From this point on, the info reflects not the raw image,
00400   //  but the image after transform and to be read.
00401   png_read_update_info(p_->png_ptr, p_->info_ptr);
00402 
00403   this->width_ = png_get_image_width(p_->png_ptr, p_->info_ptr);
00404   this->height_ = png_get_image_height(p_->png_ptr, p_->info_ptr);
00405   this->components_ = p_->channels = png_get_channels(p_->png_ptr, p_->info_ptr);
00406   this->bits_per_component_ = png_get_bit_depth(p_->png_ptr, p_->info_ptr);
00407 
00408   // Set bits_per_component_ back to 1 for bool image
00409   if (is_bool_image)
00410     this->bits_per_component_ = 1;
00411 
00412   if (this->bits_per_component_ == 1)     format_ = VIL_PIXEL_FORMAT_BOOL;
00413   else if (this->bits_per_component_==8)  format_ = VIL_PIXEL_FORMAT_BYTE;
00414   else if (this->bits_per_component_==16) format_ = VIL_PIXEL_FORMAT_UINT_16;
00415   else return problem("Bad bit depth");
00416 
00417   // if (p->info_ptr->valid & PNG_INFO_bKGD) problem("LAZY AWF! PNG_INFO_bKGD");
00418   png_setjmp_off();
00419   return true;
00420 }
00421 
00422 bool vil_png_image::write_header()
00423 {
00424   if (!p_->ok)
00425     return false;
00426 
00427   png_setjmp_on( return false );
00428 
00429   vs_->seek(0L);
00430 
00431   png_set_write_fn(p_->png_ptr, vs_, user_write_data, user_flush_data);
00432 
00433   int color_type;
00434   if (components_ == 4)
00435     color_type = PNG_COLOR_TYPE_RGB_ALPHA;
00436   else if (components_ == 3)
00437     color_type = PNG_COLOR_TYPE_RGB;
00438   else if (components_ == 2)
00439     color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
00440   else
00441     color_type = PNG_COLOR_TYPE_GRAY;
00442 
00443   png_set_IHDR(p_->png_ptr, p_->info_ptr, width_, height_, bits_per_component_, color_type,
00444                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00445 
00446   png_write_info(p_->png_ptr, p_->info_ptr);
00447 
00448 #if VXL_LITTLE_ENDIAN
00449   // PNG stores data MSB
00450   if ( bits_per_component_ > 8 )
00451     png_set_swap(p_->png_ptr);
00452 #endif
00453 
00454   // Make memory image
00455   p_->channels = components_;
00456   p_->alloc_image();
00457 
00458   png_setjmp_off();
00459 
00460   return true;
00461 }
00462 
00463 vil_image_view_base_sptr vil_png_image::get_copy_view(unsigned x0,
00464                                                       unsigned nx,
00465                                                       unsigned y0,
00466                                                       unsigned ny) const
00467 {
00468   if (!p_->ok)
00469     return 0;
00470 
00471   // PNG lib wants everything in memory - the first get_rows reads the whole image.
00472   png_byte** rows = p_->get_rows();
00473   if (!rows) return 0;
00474 
00475   int bit_depth = bits_per_component_;  // value can be 1, 8, or 16
00476   int bytes_per_pixel = (bit_depth * p_->channels + 7) / 8;
00477   int bytes_per_row_dst = nx*nplanes() * vil_pixel_format_sizeof_components(format_);
00478 
00479   vil_memory_chunk_sptr chunk = new vil_memory_chunk(ny*bytes_per_row_dst, format_);
00480 
00481   if (nx == png_get_image_width(p_->png_ptr, p_->info_ptr))
00482   {
00483     assert(x0 == 0);
00484 
00485     if (bit_depth==1)
00486     {
00487       assert(format_==VIL_PIXEL_FORMAT_BOOL);
00488 
00489       vcl_memcpy(reinterpret_cast<char*>(chunk->data()), rows[y0], ny * bytes_per_row_dst);
00490       return new vil_image_view<bool>(chunk, reinterpret_cast<bool*>(chunk->data()),
00491         nx, ny, nplanes(), nplanes(), nplanes()*nx, 1);
00492     }
00493     else if (bit_depth==16)
00494     {
00495       assert(format_==VIL_PIXEL_FORMAT_UINT_16);
00496 
00497       vcl_memcpy(reinterpret_cast<char*>(chunk->data()), rows[y0], ny * bytes_per_row_dst);
00498       return new vil_image_view<vxl_uint_16>(chunk, reinterpret_cast<vxl_uint_16*>(chunk->data()),
00499         nx, ny, nplanes(), nplanes(), nplanes()*nx, 1);
00500     }
00501     else if (bit_depth ==8)
00502     {
00503       vcl_memcpy(reinterpret_cast<char*>(chunk->data()), rows[y0], ny * bytes_per_row_dst);
00504       return new vil_image_view<vxl_byte>(chunk, reinterpret_cast<vxl_byte*>(chunk->data()),
00505         nx, ny, nplanes(), nplanes(), nplanes()*nx, 1);
00506     }
00507     else return 0;
00508   }
00509   else   // not whole row
00510   {
00511     if (bit_depth==1)
00512     {
00513       assert(format_==VIL_PIXEL_FORMAT_BOOL);
00514 
00515       png_byte* dst = reinterpret_cast<png_byte*>(chunk->data());
00516       for (unsigned y = 0; y < ny; ++y, dst += bytes_per_row_dst)
00517         vcl_memcpy(dst, &rows[y0+y][x0*bytes_per_pixel], nx*bytes_per_pixel);
00518       return new vil_image_view<bool>(chunk, reinterpret_cast<bool*>(chunk->data()),
00519         nx, ny, nplanes(), nplanes(), nplanes()*nx, 1);
00520     }
00521     else if (bit_depth==16)
00522     {
00523       assert(format_==VIL_PIXEL_FORMAT_UINT_16);
00524 
00525       png_byte* dst = reinterpret_cast<png_byte*>(chunk->data());
00526       for (unsigned y = 0; y < ny; ++y, dst += bytes_per_row_dst)
00527         vcl_memcpy(dst, &rows[y0+y][x0*bytes_per_pixel], nx*bytes_per_pixel);
00528       return new vil_image_view<vxl_uint_16>(chunk, reinterpret_cast<vxl_uint_16*>(chunk->data()),
00529         nx, ny, nplanes(), nplanes(), nplanes()*nx, 1);
00530     }
00531     else if (bit_depth==8)
00532     {
00533       png_byte* dst = reinterpret_cast<png_byte*>(chunk->data());
00534       for (unsigned y = 0; y < ny; ++y, dst += bytes_per_row_dst)
00535         vcl_memcpy(dst, &rows[y0+y][x0*bytes_per_pixel], nx*bytes_per_pixel);
00536       return new vil_image_view<vxl_byte>(chunk, reinterpret_cast<vxl_byte*>(chunk->data()),
00537         nx, ny, nplanes(), nplanes(), nplanes()*nx, 1);
00538     }
00539     else return 0;
00540   }
00541 }
00542 
00543 bool vil_png_image::put_view(const vil_image_view_base &view,
00544                              unsigned x0, unsigned y0)
00545 {
00546   if (!view_fits(view, x0, y0))
00547   {
00548     vil_exception_warning(vil_exception_out_of_bounds("vil_png_image::put_view"));
00549     return false;
00550   }
00551 
00552   if (!p_->ok) return false;
00553 
00554   // PNG lib wants everything in memory - the writing isn't done till this image is deleted.
00555 
00556   png_byte** rows = p_->get_rows();
00557   if (!rows) return false;
00558 
00559   // int bytes_per_pixel = bit_depth  * p_->channels / 8;
00560   // int bytes_per_row_dst = view.ni()*bytes_per_pixel;
00561   if (bits_per_component_ == 8)
00562   {
00563     if (view.pixel_format() != VIL_PIXEL_FORMAT_BYTE) return false;
00564     const vil_image_view<vxl_byte> &view2 = static_cast<const vil_image_view<vxl_byte>&>(view);
00565     if (nplanes()==1)
00566     {
00567       for (unsigned y = 0; y < view.nj(); ++y)
00568         for (unsigned x=0; x < view.ni(); ++x)
00569           rows[y0+y][x0+x] = view2(x,y);
00570     }
00571     else if (nplanes()==2)
00572     {
00573       for (unsigned y = 0; y < view.nj(); ++y)
00574         for (unsigned x=0; x < view.ni(); ++x)
00575         {
00576           rows[y0+y][(x0+x)*2] = view2(x,y,0);
00577           rows[y0+y][(x0+x)*2+1] = view2(x,y,1);
00578         }
00579     }
00580     else if (nplanes()==3)
00581     {
00582       for (unsigned y = 0; y < view.nj(); ++y)
00583         for (unsigned x=0; x < view.ni(); ++x)
00584         {
00585           rows[y0+y][(x0+x)*3] = view2(x,y,0);
00586           rows[y0+y][(x0+x)*3+1] = view2(x,y,1);
00587           rows[y0+y][(x0+x)*3+2] = view2(x,y,2);
00588         }
00589     }
00590     else
00591     {
00592       assert(nplanes() == 4);
00593       for (unsigned y = 0; y < view.nj(); ++y)
00594         for (unsigned x=0; x < view.ni(); ++x)
00595         {
00596           rows[y0+y][(x0+x)*4] = view2(x,y,0);
00597           rows[y0+y][(x0+x)*4+1] = view2(x,y,1);
00598           rows[y0+y][(x0+x)*4+2] = view2(x,y,2);
00599           rows[y0+y][(x0+x)*4+3] = view2(x,y,3);
00600         }
00601     }
00602   }
00603   else if (bits_per_component_ == 16)
00604   {
00605     if (view.pixel_format() != VIL_PIXEL_FORMAT_UINT_16) return false;
00606     const vil_image_view<vxl_uint_16> &view2 = static_cast<const vil_image_view<vxl_uint_16>&>(view);
00607     if (nplanes()==1)
00608     {
00609       for (unsigned y = 0; y < view.nj(); ++y)
00610         for (unsigned x=0; x < view.ni(); ++x)
00611           *reinterpret_cast<vxl_uint_16*>(&rows[y0+y][(x0+x)*2]) = view2(x,y);
00612     }
00613     else if (nplanes() == 3)
00614     {
00615       for (unsigned y = 0; y < view.nj(); ++y)
00616         for (unsigned x=0; x < view.ni(); ++x)
00617         {
00618           *reinterpret_cast<vxl_uint_16*>(&rows[y0+y][(x0+x)*6]) = view2(x,y,0);
00619           *reinterpret_cast<vxl_uint_16*>(&rows[y0+y][(x0+x)*6+2]) = view2(x,y,1);
00620           *reinterpret_cast<vxl_uint_16*>(&rows[y0+y][(x0+x)*6+4]) = view2(x,y,2);
00621         }
00622     }
00623     else
00624     {
00625       assert(nplanes() == 4);
00626       for (unsigned y = 0; y < view.nj(); ++y)
00627         for (unsigned x=0; x < view.ni(); ++x)
00628         {
00629           *reinterpret_cast<vxl_uint_16*>(&rows[y0+y][(x0+x)*8]) = view2(x,y,0);
00630           *reinterpret_cast<vxl_uint_16*>(&rows[y0+y][(x0+x)*8+2]) = view2(x,y,1);
00631           *reinterpret_cast<vxl_uint_16*>(&rows[y0+y][(x0+x)*8+4]) = view2(x,y,2);
00632           *reinterpret_cast<vxl_uint_16*>(&rows[y0+y][(x0+x)*8+6]) = view2(x,y,3);
00633         }
00634     }
00635   }
00636   // FIXME else if (bit_depth=1)
00637   else return false;
00638 
00639   return true;
00640 }