1 #include <algorithm>
2 #include <cmath>
3 #include <limits>
4 #include <cstdlib>
5 #include "vil_j2k_image.h"
6 //:
7 // \file
8 // vil_j2k: Written by Rob Radtke (rob@) and Harry Voorhees (hlv@) of
9 // Stellar Science Ltd. Co. (stellarscience.com) for
10 // Air Force Research Laboratory, 2005.
11 // Write capability added by J. Mundy, April 2009
12 // Do not remove the following notice
13 // Modifications approved for public Release, distribution unlimited
14 // DISTAR Case 14074
15 //
16
17 #include <NCSFile.h>
18
19 #include <cassert>
20 #ifdef _MSC_VER
21 # include "vcl_msvc_warnings.h"
22 #endif
23 #include "vil/vil_memory_chunk.h"
24 #include "vil/vil_image_view.h"
25 #include "vil/vil_load.h"
26 #include "vil/vil_open.h"
27 #include "vil/vil_new.h"
28 #include "NCSJPCVilIOStream.h"
29 #include <NCSTypes.h>
30
31 // Fix me - need to add UINT64 and INT64 - JLM
32 // Also note, float and double are defined but not handled by SDK 3.3
33 // they are reinterpreted as INT32 and INT64
34 NCSFileBandInfo
bandInfo(const vil_pixel_format & vilType)35 bandInfo(const vil_pixel_format & vilType)
36 {
37 NCSFileBandInfo info;
38 switch (vil_pixel_format_component_format(vilType))
39 {
40 case VIL_PIXEL_FORMAT_UINT_32: {
41 info.nBits = sizeof(vxl_uint_32) * 8;
42 info.bSigned = std::numeric_limits<vxl_uint_32>::is_signed;
43 info.szDesc = 0;
44 return info;
45 }
46 case VIL_PIXEL_FORMAT_INT_32: {
47 info.nBits = sizeof(vxl_int_32) * 8;
48 info.bSigned = std::numeric_limits<vxl_int_32>::is_signed;
49 info.szDesc = 0;
50 return info;
51 }
52 case VIL_PIXEL_FORMAT_UINT_16: {
53 info.nBits = sizeof(vxl_uint_16) * 8;
54 info.bSigned = std::numeric_limits<vxl_uint_16>::is_signed;
55 info.szDesc = 0;
56 return info;
57 }
58 case VIL_PIXEL_FORMAT_INT_16: {
59 info.nBits = sizeof(vxl_int_16) * 8;
60 info.bSigned = std::numeric_limits<vxl_int_16>::is_signed;
61 info.szDesc = 0;
62 return info;
63 }
64 case VIL_PIXEL_FORMAT_BYTE: {
65 info.nBits = sizeof(vxl_byte) * 8;
66 info.bSigned = std::numeric_limits<vxl_byte>::is_signed;
67 info.szDesc = 0;
68 return info;
69 }
70 case VIL_PIXEL_FORMAT_SBYTE: {
71 info.nBits = sizeof(vxl_sbyte) * 8;
72 info.bSigned = std::numeric_limits<vxl_sbyte>::is_signed;
73 info.szDesc = 0;
74 return info;
75 }
76 case VIL_PIXEL_FORMAT_FLOAT: {
77 info.nBits = sizeof(float) * 8;
78 info.bSigned = std::numeric_limits<float>::is_signed;
79 info.szDesc = 0;
80 return info;
81 }
82 case VIL_PIXEL_FORMAT_DOUBLE: {
83 info.nBits = sizeof(double) * 8;
84 info.bSigned = std::numeric_limits<double>::is_signed;
85 info.szDesc = 0;
86 return info;
87 }
88 case VIL_PIXEL_FORMAT_BOOL:
89 case VIL_PIXEL_FORMAT_COMPLEX_FLOAT:
90 case VIL_PIXEL_FORMAT_COMPLEX_DOUBLE:
91 case VIL_PIXEL_FORMAT_UINT_64:
92 case VIL_PIXEL_FORMAT_INT_64:
93 case VIL_PIXEL_FORMAT_UNKNOWN:
94 default: {
95 assert(0);
96 info.nBits = 0;
97 info.bSigned = false;
98 info.szDesc = 0;
99 return info;
100 }
101 }
102 }
103
104 //--------------------------------------------------------------------------------
105 // class vil_j2k_file_format
106
107 static char const j2k_string[] = "j2k";
108
109 char const *
tag() const110 vil_j2k_file_format::tag() const
111 {
112 return j2k_string;
113 }
114
115 vil_image_resource_sptr
make_input_image(vil_stream * vs)116 vil_j2k_file_format::make_input_image(vil_stream * vs)
117 {
118 vil_j2k_image * im = new vil_j2k_image(vs);
119 if (!im->is_valid())
120 {
121 delete im;
122 im = 0;
123 }
124 return im;
125 }
126
127
128 vil_image_resource_sptr
make_output_image(vil_stream * vs,unsigned ni,unsigned nj,unsigned nplanes,enum vil_pixel_format format)129 vil_j2k_file_format::make_output_image(vil_stream * vs,
130 unsigned ni,
131 unsigned nj,
132 unsigned nplanes,
133 enum vil_pixel_format format)
134 {
135 vil_j2k_image * j2k_img = new vil_j2k_image(vs, ni, nj, nplanes, format, compression_ratio_);
136 if (j2k_img->is_valid())
137 return static_cast<vil_image_resource *>(j2k_img);
138 return 0;
139 }
140
141 NCSEcwCellType
convertType(const vil_pixel_format & vilType)142 convertType(const vil_pixel_format & vilType)
143 {
144 switch (vil_pixel_format_component_format(vilType))
145 {
146 case VIL_PIXEL_FORMAT_UINT_64:
147 return NCSCT_UINT64;
148 case VIL_PIXEL_FORMAT_INT_64:
149 return NCSCT_INT64;
150 case VIL_PIXEL_FORMAT_UINT_32:
151 return NCSCT_UINT32;
152 case VIL_PIXEL_FORMAT_INT_32:
153 return NCSCT_INT32;
154 case VIL_PIXEL_FORMAT_UINT_16:
155 return NCSCT_UINT16;
156 case VIL_PIXEL_FORMAT_INT_16:
157 return NCSCT_INT16;
158 case VIL_PIXEL_FORMAT_BYTE:
159 return NCSCT_UINT8;
160 case VIL_PIXEL_FORMAT_SBYTE:
161 return NCSCT_INT8;
162 case VIL_PIXEL_FORMAT_FLOAT:
163 return NCSCT_IEEE4;
164 case VIL_PIXEL_FORMAT_DOUBLE:
165 return NCSCT_IEEE8;
166 case VIL_PIXEL_FORMAT_BOOL:
167 case VIL_PIXEL_FORMAT_COMPLEX_FLOAT:
168 case VIL_PIXEL_FORMAT_COMPLEX_DOUBLE:
169 case VIL_PIXEL_FORMAT_UNKNOWN:
170 default:
171 assert(0);
172 return NCSCT_UINT8;
173 }
174 }
175
176 // Note the J2K SDK defines IEEE4 and IEEE8 but they are not
177 // handled as float or double, they are reinterpreted as INT32 and INT64
178 vil_pixel_format
convertType(const NCSEcwCellType & ecwType)179 convertType(const NCSEcwCellType & ecwType)
180 {
181 switch (ecwType)
182 {
183 case NCSCT_UINT64:
184 return VIL_PIXEL_FORMAT_UINT_64;
185 case NCSCT_INT64:
186 return VIL_PIXEL_FORMAT_INT_64;
187 case NCSCT_UINT32:
188 return VIL_PIXEL_FORMAT_UINT_32;
189 case NCSCT_INT32:
190 return VIL_PIXEL_FORMAT_INT_32;
191 case NCSCT_UINT16:
192 return VIL_PIXEL_FORMAT_UINT_16;
193 case NCSCT_INT16:
194 return VIL_PIXEL_FORMAT_INT_16;
195 case NCSCT_UINT8:
196 return VIL_PIXEL_FORMAT_BYTE;
197 case NCSCT_INT8:
198 return VIL_PIXEL_FORMAT_SBYTE;
199 case NCSCT_IEEE4:
200 return VIL_PIXEL_FORMAT_FLOAT;
201 case NCSCT_IEEE8:
202 return VIL_PIXEL_FORMAT_DOUBLE;
203 default:
204 assert(0);
205 return VIL_PIXEL_FORMAT_UNKNOWN;
206 }
207 }
208
209 ////////////////////////////////////////////////////
210 // vil_j2k_image
211 ////////////////////////////////////////////////////
212
vil_j2k_image(const std::string & fileOrUrl)213 vil_j2k_image::vil_j2k_image(const std::string & fileOrUrl)
214 : vil_image_resource()
215 , mFileResource(new CNCSFile())
216 , mStr(0)
217 , mMaxLocalDimension(5000)
218 , // default value
219 mMaxRemoteDimension(640)
220 , // default value
221 mRemoteFile(false)
222 , mFinfo(0)
223 , mBandinfo(0)
224 , line_index_(0)
225 {
226 if (mFileResource->Open((char *)fileOrUrl.c_str(), false, false) != NCS_SUCCESS)
227 {
228 mFileResource = 0;
229 return;
230 }
231 if (fileOrUrl.substr(0, 7) == "ecwp://" || fileOrUrl.substr(0, 7) == "ECWP://")
232 {
233 mRemoteFile = true;
234 }
235 }
236
vil_j2k_image(vil_stream * is)237 vil_j2k_image::vil_j2k_image(vil_stream * is)
238 : vil_image_resource()
239 , mFileResource(new CNCSFile())
240 , mStr(new CNCSJPCVilIOStream())
241 , mMaxLocalDimension(5000)
242 , // default value
243 mMaxRemoteDimension(640)
244 , // default value
245 mRemoteFile(false)
246 , mFinfo(0)
247 , mBandinfo(0)
248 , line_index_(0)
249 {
250 mStr->Open(is);
251
252 if ((static_cast<CNCSJP2FileView *>(mFileResource))->Open(mStr) != NCS_SUCCESS)
253 {
254 mFileResource = 0;
255 return;
256 }
257 }
258
vil_j2k_image(vil_stream * vs,unsigned ni,unsigned nj,unsigned nplanes,enum vil_pixel_format format,unsigned compression_ratio)259 vil_j2k_image::vil_j2k_image(vil_stream * vs,
260 unsigned ni,
261 unsigned nj,
262 unsigned nplanes,
263 enum vil_pixel_format format,
264 unsigned compression_ratio)
265 : vil_image_resource()
266 , mFileResource(new CNCSFile())
267 , mStr(new CNCSJPCVilIOStream())
268 , mMaxLocalDimension(5000)
269 , // default value
270 mMaxRemoteDimension(640)
271 , // default value
272 mRemoteFile(false)
273 , mFinfo(new NCSFileViewFileInfoEx())
274 , line_index_(0)
275 {
276 mBandinfo = new NCSFileBandInfo[nplanes];
277 CNCSError Error;
278 for (unsigned i = 0; i < nplanes; ++i)
279 mBandinfo[i] = bandInfo(format);
280
281 // String names for each band, should specialize according to color space
282 mBandinfo[0].szDesc = "grey";
283 if (nplanes == 3)
284 {
285 mBandinfo[0].szDesc = "Red";
286 mBandinfo[1].szDesc = "Green";
287 mBandinfo[2].szDesc = "Blue";
288 }
289 NCSEcwCellType t = convertType(format);
290 NCSFileViewFileInfoEx finfo = *mFinfo;
291 finfo.pBands = mBandinfo;
292 finfo.nSizeX = ni;
293 finfo.nSizeY = nj;
294 finfo.nBands = nplanes;
295 finfo.eCellType = t;
296 finfo.nCompressionRate = compression_ratio;
297 finfo.eCellSizeUnits = ECW_CELL_UNITS_METERS;
298 finfo.fCellIncrementX = 1.0;
299 finfo.fCellIncrementY = 1.0;
300 finfo.fOriginX = 0.0;
301 finfo.fOriginY = 0.0;
302 finfo.szDatum = "RAW";
303 finfo.szProjection = "RAW";
304 finfo.fCWRotationDegrees = 0.0;
305 if (nplanes == 1)
306 finfo.eColorSpace = NCSCS_GREYSCALE;
307 else if (nplanes == 3)
308 finfo.eColorSpace = NCSCS_sRGB;
309 else
310 {
311 delete mFileResource;
312 mFileResource = 0;
313 }
314 Error = mFileResource->SetFileInfo(finfo);
315 if (Error != NCS_SUCCESS)
316 {
317 if (mFileResource)
318 delete mFileResource;
319 mFileResource = 0;
320 }
321 Error = mStr->Open(vs, true);
322 if (Error != NCS_SUCCESS)
323 {
324 if (mFileResource)
325 delete mFileResource;
326 mFileResource = 0;
327 }
328 CNCSJP2FileView * fview = static_cast<CNCSJP2FileView *>(mFileResource);
329 Error = fview->Open(static_cast<CNCSJPCIOStream *>(mStr));
330 if (Error != NCS_SUCCESS)
331 {
332 if (mFileResource)
333 delete mFileResource;
334 mFileResource = 0;
335 return;
336 }
337 }
338
~vil_j2k_image()339 vil_j2k_image::~vil_j2k_image()
340 {
341 if (mFileResource)
342 {
343 mFileResource->Close(true);
344 }
345 if (mStr)
346 delete mStr;
347 if (mBandinfo)
348 delete mBandinfo;
349 if (mFinfo)
350 delete mFinfo;
351 }
352
353 unsigned
nplanes() const354 vil_j2k_image::nplanes() const
355 {
356 assert(mFileResource);
357 return mFileResource->GetFileInfo()->nBands;
358 }
359
360 unsigned
ni() const361 vil_j2k_image::ni() const
362 {
363 assert(mFileResource);
364 return mFileResource->GetFileInfo()->nSizeX;
365 }
366
367 unsigned
nj() const368 vil_j2k_image::nj() const
369 {
370 assert(mFileResource);
371 return mFileResource->GetFileInfo()->nSizeY;
372 }
373
374 enum vil_pixel_format
pixel_format() const375 vil_j2k_image::pixel_format() const
376 {
377 assert(mFileResource);
378 return convertType(mFileResource->GetFileInfo()->eCellType);
379 }
380
381 char const *
file_format() const382 vil_j2k_image::file_format() const
383 {
384 return "j2k";
385 }
386
387 vil_image_view_base_sptr
get_copy_view_decimated(unsigned sample0,unsigned num_samples,unsigned line0,unsigned numLines,double i_factor,double j_factor) const388 vil_j2k_image::get_copy_view_decimated(unsigned sample0,
389 unsigned num_samples,
390 unsigned line0,
391 unsigned numLines,
392 double i_factor,
393 double j_factor) const
394 {
395 return get_copy_view_decimated_by_size(sample0,
396 num_samples,
397 line0,
398 numLines,
399 (unsigned int)(((double)num_samples) / i_factor),
400 (unsigned int)(((double)numLines) / j_factor));
401 }
402
403 vil_image_view_base_sptr
get_copy_view_decimated_by_size(unsigned sample0,unsigned num_samples,unsigned line0,unsigned numLines,unsigned int output_width,unsigned int output_height) const404 vil_j2k_image::get_copy_view_decimated_by_size(unsigned sample0,
405 unsigned num_samples,
406 unsigned line0,
407 unsigned numLines,
408 unsigned int output_width,
409 unsigned int output_height) const
410 {
411 if (!(mFileResource) || !((sample0 + num_samples - 1) < ni() && (line0 + numLines - 1) < nj()))
412 {
413 return 0;
414 }
415
416 // we want all bands mapped in the same order as they come in the input file
417 // eg. bandMap = {0,1,2,3...nBands}
418 INT32 nBands = nplanes();
419 INT32 * bandMap = (INT32 *)std::malloc(sizeof(UINT32) * nBands);
420 for (int i = 0; i < nBands; i++)
421 {
422 bandMap[i] = i;
423 }
424
425 // this guards us from returning an image that is too big for the computer's memory
426 //(or would take too long to download in the remote case).
427 // We don't want infinite hangs or application crashes.
428 unsigned int maxDim = mRemoteFile ? mMaxRemoteDimension : mMaxLocalDimension;
429 if (output_width > maxDim || output_height > maxDim)
430 {
431 unsigned int biggestDim = (std::max)(output_width, output_height);
432 double zoomFactor = ((double)maxDim) / ((double)biggestDim);
433 output_width = (unsigned int)(((double)output_width) * zoomFactor);
434 output_height = (unsigned int)(((double)output_height) * zoomFactor);
435 }
436
437 // set the view to be that specified by the function's input parameters
438 // note that we don't want ECW to do any scaling for us. That's why
439 // the box created by (sample0,line0) and (sample0+num_samples-1,line0+numLines-1) is made to be exactly
440 // num_samplesXnumLines.
441
442 NCSError setViewError = mFileResource->SetView(nBands,
443 bandMap,
444 output_width,
445 output_height,
446 (INT32)sample0,
447 (INT32)line0,
448 (INT32)(sample0 + num_samples - 1),
449 (INT32)(line0 + numLines - 1));
450 if (setViewError != NCS_SUCCESS)
451 {
452 free(bandMap);
453 return 0;
454 }
455
456 // number of samples times the bytes per sample in each band
457 double bitsPerSample = mFileResource->GetFileInfo()->pBands[0].nBits;
458 unsigned int bytesPerSample = (unsigned int)std::ceil(bitsPerSample / 8.0);
459 unsigned int singleBandLineSizeBytes = output_width * bytesPerSample;
460 unsigned int allBandLineSizeBytes = singleBandLineSizeBytes * nBands;
461 unsigned int dataPtrSizeBytes = allBandLineSizeBytes * output_height;
462 // void* data_ptr = std::malloc( dataPtrSizeBytes );
463 vil_memory_chunk_sptr data_ptr =
464 new vil_memory_chunk(dataPtrSizeBytes, convertType(mFileResource->GetFileInfo()->eCellType));
465 void ** linePtrPtr =
466 (void **)std::malloc(nBands * sizeof(int * /*all pointers have same size, so eg char* would work too*/));
467 // now read all the lines that we want
468 for (unsigned int currLine = 0; currLine < output_height; currLine++)
469 {
470 for (int currBand = 0; currBand < nBands; currBand++)
471 {
472 linePtrPtr[currBand] =
473 (void *)(((char *)data_ptr->data()) + currLine * allBandLineSizeBytes + currBand * singleBandLineSizeBytes);
474 }
475 NCSEcwReadStatus readStatus =
476 mFileResource->ReadLineBIL(mFileResource->GetFileInfo()->eCellType, nBands, linePtrPtr, 0);
477 if (readStatus != NCSECW_READ_OK)
478 {
479 free(bandMap);
480 free(linePtrPtr);
481 return 0;
482 }
483 }
484
485 // free our temp resources
486 free(bandMap);
487 free(linePtrPtr);
488
489 vil_image_view_base_sptr view = 0;
490 // now create our vil_image_view
491 // note that float and double are defaulted since the J2K SDK doesn't
492 // implement these types properly
493 switch (vil_pixel_format_component_format(data_ptr->pixel_format()))
494 {
495 #define macro(F, T) \
496 case F: \
497 view = new vil_image_view<T>(data_ptr, \
498 reinterpret_cast<T *>(data_ptr->data()), \
499 output_width, \
500 output_height, \
501 nBands, \
502 1, \
503 output_width * nBands, \
504 output_width); \
505 break
506 macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
507 macro(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
508 macro(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
509 macro(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
510 macro(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
511 macro(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
512 macro(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
513 macro(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
514 macro(VIL_PIXEL_FORMAT_BOOL, bool);
515 #undef macro
516 default:
517 std::cerr << "Pixel format not supported by ERMapper SDK\n";
518 assert(0);
519 break;
520 }
521
522 return view;
523 }
524
525 vil_image_view_base_sptr
get_copy_view(unsigned sample0,unsigned num_samples,unsigned line0,unsigned numLines) const526 vil_j2k_image::get_copy_view(unsigned sample0, unsigned num_samples, unsigned line0, unsigned numLines) const
527 {
528 return get_copy_view_decimated(sample0, num_samples, line0, numLines, 1.0, 1.0);
529 }
530
531 void
unsetMaxImageDimension(bool remote)532 vil_j2k_image::unsetMaxImageDimension(bool remote)
533 {
534 #undef max
535 setMaxImageDimension(std::numeric_limits<unsigned int>::max(), remote);
536 }
537
538 void
setMaxImageDimension(unsigned int widthOrHeight,bool remote)539 vil_j2k_image::setMaxImageDimension(unsigned int widthOrHeight, bool remote)
540 {
541 if (remote)
542 {
543 mMaxRemoteDimension = widthOrHeight;
544 }
545 else
546 {
547 mMaxLocalDimension = widthOrHeight;
548 }
549 }
550
551 vil_image_view_base_sptr
s_decode_jpeg_2000(vil_stream * vs,unsigned i0,unsigned ni,unsigned j0,unsigned nj,double i_factor,double j_factor)552 vil_j2k_image::s_decode_jpeg_2000(vil_stream * vs,
553 unsigned i0,
554 unsigned ni,
555 unsigned j0,
556 unsigned nj,
557 double i_factor,
558 double j_factor)
559 {
560 vil_j2k_image * j2k_image = new vil_j2k_image(vs);
561 // remove limit by default, since vil is not typically used remotely
562 // but more commonly with large image files - JLM Jan 07, 2012
563 j2k_image->unsetMaxImageDimension();
564 vil_image_view_base_sptr view = j2k_image->get_copy_view_decimated(i0, ni, j0, nj, i_factor, j_factor);
565 delete j2k_image;
566 return view;
567 }
568
569 vil_image_view_base_sptr
s_decode_jpeg_2000_by_size(vil_stream * vs,unsigned i0,unsigned ni,unsigned j0,unsigned nj,unsigned int output_width,unsigned int output_height)570 vil_j2k_image::s_decode_jpeg_2000_by_size(vil_stream * vs,
571 unsigned i0,
572 unsigned ni,
573 unsigned j0,
574 unsigned nj,
575 unsigned int output_width,
576 unsigned int output_height)
577 {
578 vil_j2k_image * j2k_image = new vil_j2k_image(vs);
579 vil_image_view_base_sptr view =
580 j2k_image->get_copy_view_decimated_by_size(i0, ni, j0, nj, output_width, output_height);
581 delete j2k_image;
582 return view;
583 }
584
585 template <class T>
586 static bool
write_line_BIL(vil_memory_chunk_sptr & chunk,unsigned ni,unsigned nplanes,unsigned istep,unsigned planestep,unsigned bytes_per_pixel,CNCSFile * f_resource,NCSEcwCellType t)587 write_line_BIL(vil_memory_chunk_sptr & chunk,
588 unsigned ni,
589 unsigned nplanes,
590 unsigned istep,
591 unsigned planestep,
592 unsigned bytes_per_pixel,
593 CNCSFile * f_resource,
594 NCSEcwCellType t)
595 {
596 T * cdata = reinterpret_cast<T *>(chunk->data());
597 T ** line_ptr = new T *[nplanes];
598 for (unsigned p = 0; p < nplanes; ++p)
599 line_ptr[p] = new T[ni * bytes_per_pixel];
600
601 for (unsigned p = 0; p < nplanes; ++p)
602 {
603 T * wline = line_ptr[p];
604 for (unsigned i = 0; i < ni; ++i)
605 {
606 *(wline + i) = *(cdata + i * istep + p * planestep);
607 }
608 }
609 bool good = true;
610 void ** outbuf = reinterpret_cast<void **>(line_ptr);
611 CNCSError writeError = f_resource->WriteLineBIL(t, nplanes, outbuf);
612 if (writeError != NCS_SUCCESS)
613 good = false;
614
615 for (unsigned p = 0; p < nplanes; ++p)
616 delete[] line_ptr[p];
617 delete[] line_ptr;
618 return good;
619 }
620
621
622 //: JPEG2K compress by inserting an image row (line) at a time
623 // When the full image has been inserted, call put_line with
624 // image_row == nj(). This call causes the resource to be closed
625 // and is no longer valid. The lines must be inserted in strict row order.
626 bool
put_line(const vil_image_view_base & im)627 vil_j2k_image::put_line(const vil_image_view_base & im)
628 {
629 if (!mFileResource)
630 return false;
631 vil_pixel_format format = this->pixel_format();
632 unsigned ni = this->ni(), nj = this->nj(), nplanes = this->nplanes();
633 if (line_index_ >= nj)
634 {
635 mFileResource->Close(true);
636 if (mFileResource)
637 delete mFileResource;
638 mFileResource = 0;
639 return true;
640 }
641 unsigned bytes_per_pixel = 0;
642 NCSEcwCellType t = convertType(format);
643 vil_memory_chunk_sptr chunk;
644 // now write out the image line
645 // note that float and double are defaulted since the J2K SDK doesn't
646 // implement these types properly
647 switch (vil_pixel_format_component_format(format))
648 {
649 #define macro(F, T) \
650 case F: { \
651 bytes_per_pixel = sizeof(T); \
652 const vil_image_view<T> & view = static_cast<const vil_image_view<T> &>(im); \
653 chunk = view.memory_chunk(); \
654 if (!write_line_BIL<T>(chunk, ni, nplanes, view.istep(), view.planestep(), bytes_per_pixel, mFileResource, t)) \
655 return false; \
656 } \
657 break
658 macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
659 macro(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
660 macro(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
661 macro(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
662 macro(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
663 macro(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
664 macro(VIL_PIXEL_FORMAT_BOOL, bool);
665 #undef macro
666 default:
667 std::cerr << "Pixel format not supported by ERMapper SDK\n";
668 assert(0);
669 break;
670 }
671 ++line_index_;
672 return true;
673 }
674
675 //: JPEG2K compress the view and of the full image and insert in resource
676 // The file is closed after putting the view into the resource
677 // and becomes an invalid resource.
678 bool
put_view(const vil_image_view_base & im)679 vil_j2k_image::put_view(const vil_image_view_base & im)
680 {
681 if (!this->view_fits(im, 0, 0))
682 return false;
683 if (!mFileResource)
684 return false;
685 unsigned ni = im.ni(), nj = im.nj();
686 vil_image_resource_sptr mem_res = vil_new_image_resource_of_view(im);
687 vil_image_view_base_sptr view;
688 for (unsigned j = 0; j < nj; ++j)
689 {
690 view = mem_res->get_copy_view(0, ni, j, 1);
691 if (!this->put_line(*view))
692 return false;
693 }
694 return true;
695 }
696
697 //: Check that a view will fit into the data at the given offset.
698 bool
view_fits(const vil_image_view_base & im,unsigned i0,unsigned j0)699 vil_j2k_image::view_fits(const vil_image_view_base & im, unsigned i0, unsigned j0)
700 {
701 unsigned ni_view = im.ni(), nj_view = im.nj(), nplanes_view = im.nplanes();
702 return i0 + 1 < ni_view && j0 + 1 < nj_view && ni_view <= this->ni() && nj_view <= this->nj() &&
703 nplanes_view <= this->nplanes();
704 }
705
706 //:
707 // Encode an entire image by loading the input resource from stream
708 // and compressing the input line by line by extracting an image view
709 // of a block of lines at a time, thus works for arbitrarily large images.
710 // The num_lines_block parameter is the number of image rows in the
711 // block which is read into memory from the resource
712 bool
s_encode_jpeg2000(vil_stream * vs,const char * out_filename,unsigned compression_ratio,unsigned num_lines_block,bool verbose)713 vil_j2k_image::s_encode_jpeg2000(vil_stream * vs,
714 const char * out_filename,
715 unsigned compression_ratio,
716 unsigned num_lines_block,
717 bool verbose)
718 {
719 vil_image_resource_sptr in_res = vil_load_image_resource_raw(vs);
720 if (!in_res)
721 return false;
722 unsigned ni = in_res->ni(), nj = in_res->nj(), nplanes = in_res->nplanes();
723 vil_pixel_format format = in_res->pixel_format();
724 vil_stream * os = vil_open(out_filename, "w");
725 if (!vs)
726 return false;
727 vil_j2k_file_format fmt;
728 fmt.set_compression_ratio(compression_ratio);
729 vil_image_resource_sptr res = fmt.make_output_image(os, ni, nj, nplanes, format);
730 if (!res)
731 return false;
732 vil_j2k_image * j2k_img = reinterpret_cast<vil_j2k_image *>(res.ptr());
733
734 // number of full blocks in image height
735 unsigned n_blocks = nj / num_lines_block;
736 unsigned jb = 0;
737 for (unsigned b = 0; b < n_blocks; b++, jb += num_lines_block)
738 {
739 // read a block from the file: width = ni, height = num_lines_block
740 vil_image_view_base_sptr block_view = in_res->get_view(0, ni, jb, num_lines_block);
741 if (!block_view)
742 return false;
743
744 // wrap the view in a memory resident resource
745 vil_image_resource_sptr block_res = vil_new_image_resource_of_view(*block_view);
746
747 // compress the block, line by line
748 for (unsigned j = 0; j < num_lines_block; ++j)
749 {
750 vil_image_view_base_sptr line_view = block_res->get_copy_view(0, ni, j, 1);
751 if (!j2k_img->put_line(*line_view))
752 return false;
753 if (verbose)
754 if (j % 100 == 0) // output a dot every 100 lines
755 std::cout << '.';
756 }
757 }
758 // output the remaining lines left over after loading block-sized chunks
759 unsigned remaining_lines = nj - jb;
760 if (remaining_lines)
761 {
762 vil_image_view_base_sptr residual_view = in_res->get_view(0, ni, jb, remaining_lines);
763 vil_image_resource_sptr residual_res = vil_new_image_resource_of_view(*residual_view);
764 vil_image_view_base_sptr view;
765 for (unsigned j = 0; j < remaining_lines; ++j)
766 {
767 view = residual_res->get_copy_view(0, ni, j, 1);
768 if (!j2k_img->put_line(*view))
769 return false;
770 if (verbose)
771 if (j % 100 == 0) // output a dot every 100 lines
772 std::cout << '.';
773 }
774 }
775 if (verbose)
776 std::cout << '\n';
777 return true;
778 }
779
780 bool
s_encode_jpeg2000(const char * in_filename,const char * out_filename,unsigned compression_ratio,unsigned num_lines_block,bool verbose)781 vil_j2k_image::s_encode_jpeg2000(const char * in_filename,
782 const char * out_filename,
783 unsigned compression_ratio,
784 unsigned num_lines_block,
785 bool verbose)
786 {
787 vil_stream * vs = vil_open(in_filename);
788 vs->ref();
789 bool success = vil_j2k_image::s_encode_jpeg2000(vs, out_filename, compression_ratio, num_lines_block, verbose);
790 vs->unref();
791 return success;
792 }
793