vil_jpeg.cxx
Go to the documentation of this file.
1 // This is core/vil/file_formats/vil_jpeg.cxx
2 //:
3 // \file
4 // \author fsm
5 // \date 17 Feb 2000
6 // \verbatim
7 // Modifications
8 // 11 Oct 2002 Ian Scott - converted to vil
9 // 30 Mar 2007 Peter Vanroose - replaced deprecated vil_new_image_view_j_i_plane()
10 //\endverbatim
11 
12 #include <iostream>
13 #include <cstring>
14 #include "vil_jpeg.h"
15 #include "vil_jpeg_source_mgr.h"
16 #include "vil_jpeg_decompressor.h"
18 #include "vil_jpeg_compressor.h"
19 
20 #include <cassert>
21 #ifdef _MSC_VER
22 # include <vcl_msvc_warnings.h>
23 #endif
24 #include <vxl_config.h> // vxl_byte
25 
26 #include <vil/vil_stream.h>
27 #include <vil/vil_image_view.h>
28 #include <vil/vil_exception.h>
29 
30 //: the file probe, as a C function.
32 {
33  char magic[2];
34  vs->seek(0L);
35  vil_streampos n = vs->read(magic, sizeof(magic));
36 
37  if (n != sizeof(magic)) {
38  std::cerr << __FILE__ << " : vil_stream::read() failed\n";
39  return false;
40  }
41 
42  // 0xFF followed by 0xD8
43  return (magic[0] == char(0xFF)) && (magic[1] == char(0xD8));
44 }
45 
46 // static data
47 static char const jpeg_string[] = "jpeg";
48 
49 //--------------------------------------------------------------------------------
50 // class vil_jpeg_file_format
51 
52 char const* vil_jpeg_file_format::tag() const
53 {
54  return jpeg_string;
55 }
56 
57 //:
59 {
60  return vil_jpeg_file_probe(vs) ? new vil_jpeg_image(vs) : nullptr;
61 }
62 
65  unsigned nx,
66  unsigned ny,
67  unsigned nplanes,
68  enum vil_pixel_format format)
69 {
70  if (format != VIL_PIXEL_FORMAT_BYTE)
71  {
72  std::cout<<"ERROR! vil_jpeg_file_format::make_output_image()\n"
73  <<"Pixel format should be byte, but is "<<format<<" instead.\n";
74  return nullptr;
75  }
76  return new vil_jpeg_image(vs, nx, ny, nplanes, format);
77 }
78 
79 //--------------------------------------------------------------------------------
80 
81 // class vil_jpeg_image
82 
84  : jc(nullptr)
85  , jd(new vil_jpeg_decompressor(s))
86  , stream(s)
87 {
88  stream->ref();
89 }
90 
91 bool vil_jpeg_image::get_property(char const * /*tag*/, void * /*prop*/) const
92 {
93  // This is not an in-memory image type, nor is it read-only:
94  return false;
95 }
96 
97 void vil_jpeg_image::set_quality(int quality)
98 {
99  if( jc )
100  jc->set_quality(quality);
101 }
102 
104  unsigned nx,
105  unsigned ny,
106  unsigned nplanes,
107  enum vil_pixel_format format)
108  : jc(new vil_jpeg_compressor(s))
109  , jd(nullptr)
110  , stream(s)
111 {
112  if (format != VIL_PIXEL_FORMAT_BYTE)
113  std::cerr << "Sorry -- pixel format " << format << " not yet supported\n";
114  assert(format == VIL_PIXEL_FORMAT_BYTE); // FIXME.
115 
116  stream->ref();
117 
118  // use same number of components as prototype, obviously.
119  jc->jobj.input_components = nplanes;
120 
121  // store size
122  jc->jobj.image_width = nx;
123  jc->jobj.image_height = ny;
124 #ifdef DEBUG
125  std::cerr << "w h = " << nx << ' ' << ny << '\n';
126 #endif
127 }
128 
130 {
131  // FIXME: I suspect there's a core leak here because jpeg_destroy() does not
132  // free the vil_jpeg_stream_source_mgr allocated in vil_jpeg_stream_xxx_set()
133  if (jd)
134  delete jd;
135  jd = nullptr;
136  if (jc)
137  delete jc;
138  jc = nullptr;
139  stream->unref();
140  stream = nullptr;
141 }
142 
143 //--------------------------------------------------------------------------------
144 
145 //: decompressing from the vil_stream to a section buffer.
147  unsigned nx,
148  unsigned y0,
149  unsigned ny) const
150 {
151  if (!jd) {
152  std::cerr << "attempted get_copy_view() failed -- no jpeg decompressor\n";
153  return nullptr;
154  }
155 #ifdef DEBUG
156  std::cerr << "get_copy_view " << ' ' << x0 << ' ' << nx << ' ' << y0 << ' ' << ny << '\n';
157 #endif
158 
159  // number of bytes per pixel
160  unsigned bpp = jd->jobj.output_components;
161 
162  vil_memory_chunk_sptr chunk = new vil_memory_chunk(bpp * nx * ny, pixel_format());
163 
164  for (unsigned int i=0; i<ny; ++i) {
165  JSAMPLE const *scanline = jd->read_scanline(y0+i);
166  if (!scanline)
167  return nullptr; // failed
168 
169  std::memcpy(reinterpret_cast<char*>(chunk->data()) + i*nx*bpp, &scanline[x0*bpp], nx*bpp);
170  }
171 
172  return new vil_image_view<vxl_byte>(chunk, reinterpret_cast<vxl_byte *>(chunk->data()), nx, ny, bpp, bpp, bpp*nx, 1);
173 }
174 
175 //--------------------------------------------------------------------------------
176 
177 //: compressing a section onto the vil_stream.
179  unsigned x0, unsigned y0)
180 {
181 
182  if (!view_fits(view, x0, y0))
183  {
184  vil_exception_warning(vil_exception_out_of_bounds("vil_jpeg_image::put_view"));
185  return false;
186  }
187 
188  if (!jc) {
189  std::cerr << "attempted put_view() failed -- no jpeg compressor\n";
190  return false;
191  }
192 
193  if (view.pixel_format() != VIL_PIXEL_FORMAT_BYTE)
194  {
195  std::cerr << "vil_jpeg_image::put_view() failed -- can only deal with byte images\n";
196  return false;
197  }
198 
199  const auto& view2 =
200  static_cast<const vil_image_view<vxl_byte>&>(view);
201 
202  // "compression makes no sense unless the section covers the whole image."
203  // Relaxed slightly.. awf.
204  // It will work if you send entire scan lines sequentially
205  if (x0 != 0 || view2.ni() != jc->jobj.image_width) {
206  std::cerr << __FILE__ << " : Can only compress complete scanlines\n";
207  return false;
208  }
209  if (y0 != jc->jobj.next_scanline) {
210  std::cerr << __FILE__ << " : Scanlines must be sent sequentially\n";
211  return false;
212  }
213 
214  // write each scanline
215  if ((view2.planestep() == 1 || view2.nplanes() == 1) && view2.istep() == jc->jobj.input_components)
216  {
217  assert(view2.istep() > 0);
218  assert(view2.istep() == jc->jobj.input_components); // bytes per pixel in the section
219  for (unsigned int j=0; j<view2.nj(); ++j) {
220  auto const *scanline = (JSAMPLE const*)
221  &view2(0,j);
222  if (!jc->write_scanline(y0+j, scanline))
223  return false;
224  }
225  }
226  else
227  {
228  vil_memory_chunk_sptr chunk = new vil_memory_chunk(view2.ni()*view2.nplanes(), vil_pixel_format_component_format(vil_pixel_format_of(vxl_byte())));
229  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);
230  JSAMPLE *scanline = line.top_left_ptr();
231 
232  for (unsigned int j=0; j<view2.nj(); ++j)
233  {
234  // arrange data into componentwise form.
235  for (unsigned i = 0; i < view2.ni(); ++i)
236  for (unsigned p = 0; p < view2.nplanes(); ++p)
237  line(i,0,p) = view2(i,j,p);
238  if (!jc->write_scanline(y0+j, scanline))
239  return false;
240  }
241  }
242 
243  return true;
244 }
245 
246 //--------------------------------------------------------------------------------
247 
248 
249 unsigned vil_jpeg_image::ni() const
250 {
251  if (jd) return jd->jobj.output_width;
252  if (jc) return jc->jobj.image_width;
253  return 0;
254 }
255 
256 unsigned vil_jpeg_image::nj() const
257 {
258  if (jd) return jd->jobj.output_height;
259  if (jc) return jc->jobj.image_height;
260  return 0;
261 }
262 
263 unsigned vil_jpeg_image::nplanes() const
264 {
265  if (jd) return jd->jobj.output_components;
266  if (jc) return jc->jobj.input_components;
267  return 0;
268 }
269 
270 
272 {
273  return VIL_PIXEL_FORMAT_BYTE;
274 }
275 
276 
277 char const *vil_jpeg_image::file_format() const
278 {
279  return jpeg_string;
280 }
281 
282 //--------------------------------------------------------------------------------
char const * file_format() const override
returns "jpeg".
Definition: vil_jpeg.cxx:277
Stream interface for VIL image loaders.
An abstract base class of smart pointers to actual image data in memory.
generic_image implementation for JPEG files.
Definition: vil_jpeg.h:41
vil_pixel_format
Describes the type of the concrete data.
bool put_view(const vil_image_view_base &im, unsigned i0, unsigned j0) override
Put the data in this view back into the image source.
Definition: vil_jpeg.cxx:178
vil_pixel_format vil_pixel_format_component_format(enum vil_pixel_format f)
Return the number of components in pixel format f.
virtual bool view_fits(const vil_image_view_base &im, unsigned i0, unsigned j0)
Check that a view will fit into the data at the given offset.
bool write_scanline(unsigned line, JSAMPLE const *)
enum vil_pixel_format pixel_format() const override
Pixel Format.
Definition: vil_jpeg.cxx:271
unsigned ni() const override
Dimensions: Planes x ni x nj.
Definition: vil_jpeg.cxx:249
Concrete view of image data of type T held in memory.
Definition: vil_fwd.h:13
virtual void seek(vil_streampos position)=0
Goto file pointer.
virtual vil_streampos read(void *buf, vil_streampos n)=0
Read n bytes into buf. Returns number of bytes read.
vil_jpeg_compressor * jc
Definition: vil_jpeg.h:73
Exceptions thrown by vil, and a mechanism for turning them off.
bool get_property(char const *tag, void *prop=nullptr) const override
Extra property information.
Definition: vil_jpeg.cxx:91
JSAMPLE const * read_scanline(unsigned line)
Do not delete the return value.
void set_quality(int quality)
set the quality for compression.
Definition: vil_jpeg.cxx:97
Stream interface for VIL image loaders.
Definition: vil_stream.h:21
virtual enum vil_pixel_format pixel_format() const =0
Return a description of the concrete data pixel type.
vil_jpeg_image(vil_stream *is)
Definition: vil_jpeg.cxx:83
Indicates that some reference was made to pixels beyond the bounds of an image.
Definition: vil_exception.h:81
void set_quality(int quality)
vil_stream * stream
Definition: vil_jpeg.h:75
bool vil_jpeg_file_probe(vil_stream *vs)
the file probe, as a C function.
Definition: vil_jpeg.cxx:31
vil_jpeg_decompressor * jd
Definition: vil_jpeg.h:74
void ref()
up/down the reference count.
Definition: vil_stream.h:45
vil_image_view_base_sptr get_copy_view() const
Create a read/write view of a copy of all the data.
A base class reference-counting view of some image data.
Ref. counted block of data on the heap.
void unref()
Definition: vil_stream.cxx:31
unsigned nplanes() const override
Dimensions: planes x width x height x components.
Definition: vil_jpeg.cxx:263
T * top_left_ptr()
Pointer to the first (top left in plane 0) pixel.
~vil_jpeg_image() override
Definition: vil_jpeg.cxx:129
vil_image_resource_sptr make_output_image(vil_stream *vs, unsigned nx, unsigned ny, unsigned nplanes, enum vil_pixel_format) override
Make a "generic_image" on which put_section may be applied.
Definition: vil_jpeg.cxx:64
vxl_int_32 vil_streampos
Definition: vil_stream.h:16
void vil_exception_warning(T exception)
Throw an exception indicating a potential problem.
Definition: vil_exception.h:37
unsigned nj() const override
Dimensions: Planes x ni x nj.
Definition: vil_jpeg.cxx:256
char const * tag() const override
Return a character string which uniquely identifies this format.
Definition: vil_jpeg.cxx:52
vil_image_resource_sptr make_input_image(vil_stream *vs) override
Attempt to make a generic_image which will read from vil_stream vs.
Definition: vil_jpeg.cxx:58
struct jpeg_decompress_struct jobj
vil_pixel_format vil_pixel_format_of(T)
The pixel format enumeration corresponding to the C++ type.
struct jpeg_compress_struct jobj