root/OpenSceneGraph/trunk/src/osgPlugins/jp2/ReaderWriterJP2.cpp @ 12912

Revision 12912, 17.3 kB (checked in by robert, 3 years ago)

Added support for using GL_UNPACK_ROW_LENGTH in conjunction with texture's + osg::Image via new RowLength?
parameter in osg::Image. To support this Image::setData(..) now has a new optional rowLength parameter which
defaults to 0, which provides the original behaviour, Image::setRowLength(int) and int Image::getRowLength() are also provided.

With the introduction of RowLength? support in osg::Image it is now possible to create a sub image where
the t size of the image are smaller than the row length, useful for when you have a large image on the CPU
and which to use a small portion of it on the GPU. However, when these sub images are created the data
within the image is no longer contiguous so data access can no longer assume that all the data is in
one block. The new method Image::isDataContiguous() enables the user to check whether the data is contiguous,
and if not one can either access the data row by row using Image::data(column,row,image) accessor, or use the
new Image::DataIterator? for stepping through each block on memory assocatied with the image.

To support the possibility of non contiguous osg::Image usage of image objects has had to be updated to
check DataContiguous? and handle the case or use access via the DataIerator? or by row by row. To achieve
this a relatively large number of files has had to be modified, in particular the texture classes and
image plugins that doing writing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/Image>
2#include <osg/Notify>
3
4#include <osg/Geode>
5
6#include <osg/GL>
7
8#include <osgDB/FileNameUtils>
9#include <osgDB/FileUtils>
10#include <osgDB/Registry>
11
12#include <string>
13#include <sstream>
14#include <vector>
15#include <stdio.h>
16#include <stdlib.h>
17
18extern "C"
19{
20    #include <jasper/jasper.h>
21}
22
23#ifndef SEEK_SET
24define SEEK_SET 0
25#endif
26
27using namespace osg;
28
29
30extern "C" {
31
32    static int putdata(jas_stream_t *out, jas_image_t *image, int numcmpts)
33    {
34        int ret;
35        int cmptno;
36        int x;
37        int y;
38        jas_matrix_t *data[4];
39        jas_seqent_t *d[4];
40        jas_seqent_t v;
41        int width, height;
42
43        width = jas_image_cmptwidth(image, 0);
44        height = jas_image_cmptheight(image, 0);
45
46        ret = -1;
47
48        data[0] = 0;
49        data[1] = 0;
50        data[2] = 0;
51        data[3] = 0;
52        for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
53            if (!(data[cmptno] = jas_matrix_create(1, width))) {
54                goto done;
55            }
56        }
57
58        for (y = height - 1; y >= 0; --y) {
59            for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
60                if (jas_image_readcmpt(image, cmptno, 0, y, width, 1,
61                  data[cmptno])) {
62                    goto done;
63                }
64                d[cmptno] = jas_matrix_getref(data[cmptno], 0, 0);
65            }
66            for (x = 0; x < width; ++x) {
67                for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
68                    v = *d[cmptno];
69                    if (v < 0) {
70                        v = 0;
71                    }
72                    if (v > 255) {
73                        v = 255;
74                    }
75                    unsigned char c;
76                    c = v;
77                    if (jas_stream_putc(out, c) == EOF) {
78                        goto done;
79                    }
80                    ++d[cmptno];
81                }
82            }
83            if (jas_stream_error(out)) {
84                goto done;
85            }
86        }
87
88        jas_stream_flush(out);
89        ret = 0;
90
91    done:
92
93        for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
94            if (data[cmptno]) {
95                jas_matrix_destroy(data[cmptno]);
96            }
97        }
98
99        return ret;
100    }
101
102    static int getdata(jas_stream_t *in, jas_image_t *image)
103    {
104        int ret;
105        int numcmpts;
106        int cmptno;
107        jas_matrix_t *data[4];
108        int x;
109        int y;
110        int width, height;
111
112        width = jas_image_cmptwidth(image, 0);
113        height = jas_image_cmptheight(image, 0);
114        numcmpts = jas_image_numcmpts(image);
115
116        ret = -1;
117
118        data[0] = 0;
119        data[1] = 0;
120        data[2] = 0;
121        data[3] = 0;
122        for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
123            if (!(data[cmptno] = jas_matrix_create(1, width))) {
124                goto done;
125            }
126        }
127
128        for (y = height - 1; y >= 0; --y)
129//        for (y = 0; y < height; ++y)
130        {
131            for (x = 0; x < width; ++x)
132            {
133                for (cmptno = 0; cmptno < numcmpts; ++cmptno)
134                {
135                    /* The sample data is unsigned. */
136                    int c;
137                    if ((c = jas_stream_getc(in)) == EOF) {
138                        return -1;
139                    }
140                    jas_matrix_set(data[cmptno], 0, x, c);
141                }
142            }
143            for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
144                if (jas_image_writecmpt(image, cmptno, 0, y, width, 1,
145                  data[cmptno])) {
146                    goto done;
147                }
148            }
149        }
150
151        jas_stream_flush(in);
152
153        ret = 0;
154
155    done:
156
157        for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
158            if (data[cmptno]) {
159                jas_matrix_destroy(data[cmptno]);
160            }
161        }
162
163        return ret;
164    }
165
166}
167
168class ReaderWriterJP2 : public osgDB::ReaderWriter
169{
170    public:
171
172
173        ReaderWriterJP2()
174        {
175            supportsExtension("jp2","Jpeg2000 image format");
176            supportsExtension("jpc","Jpeg2000 image format");
177
178            jas_init();
179
180            // little dance here to get around warnings created by jas_image_strtofmt use of char* rather than const char*
181            // as a parameted and modern compilers deprecating "jp2" string being treated as char*.
182            char* jp2 = strdup("jp2");
183            _fmt_jp2 = jas_image_strtofmt(jp2);
184            free(jp2);
185        }
186
187        ~ReaderWriterJP2()
188        {
189            jas_cleanup();
190        }
191
192        virtual const char* className() const { return "RGB Image Reader/Writer"; }
193
194        virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const
195        {
196            return readImage(file,options);
197        }
198
199        virtual ReadResult readObject(std::istream& fin, const Options* options) const
200        {
201            return readImage(fin,options);
202        }
203
204
205        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
206        {
207            std::string ext = osgDB::getFileExtension(file);
208            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
209
210            std::string fileName = osgDB::findDataFile( file, options );
211            if(fileName.empty())
212            {
213                // note from Robert, Dec03, I find returning a valid image when no
214                // file exists a bit odd...
215                osg::Image *img = new osg::Image;
216                img->setFileName(fileName);
217                return img;
218            }
219
220            jas_stream_t* in = jas_stream_fopen(fileName.c_str(), "rb");
221
222            char* opt = 0;
223            if(options)
224            {
225                opt = new char[options->getOptionString().size() + 1];
226                strcpy(opt, options->getOptionString().c_str());
227            }
228            jas_image_t* jimage = jas_image_decode(in, -1, opt); // last is the option string whatto put there?
229            if(opt) delete[] opt;
230
231            int internalFormat = jimage->numcmpts_;
232
233            int s = jas_image_width(jimage);
234            int t = jas_image_height(jimage);
235            int r = 1;
236
237            unsigned char* data = new unsigned char[internalFormat*s*t];
238
239            jas_stream_t* mem = jas_stream_memopen((char*)data, internalFormat*s*t);
240
241            putdata(mem, jimage, internalFormat);
242
243            jas_image_destroy(jimage);
244            jas_stream_close(in);
245
246            unsigned int pixelFormat =
247                internalFormat == 1 ? GL_LUMINANCE :
248                internalFormat == 2 ? GL_LUMINANCE_ALPHA :
249                internalFormat == 3 ? GL_RGB :
250                internalFormat == 4 ? GL_RGBA : (GLenum)-1;
251
252            unsigned int dataType = GL_UNSIGNED_BYTE;
253
254            Image* image = new Image();
255            image->setFileName(fileName.c_str());
256            image->setImage(s,t,r,
257                internalFormat,
258                pixelFormat,
259                dataType,
260                data,
261//                osg::Image::USE_NEW_DELETE);
262                osg::Image::NO_DELETE);
263
264            OSG_INFO << "image read ok "<<s<<"  "<<t<< std::endl;
265            return image;
266
267        }
268
269        virtual ReadResult readImage(std::istream& fin,const Options* options) const
270        {
271            char c;
272            char * sdata;
273            long ssize;
274            std::vector<char> vdata;
275
276            while(!fin.eof())
277            {
278                fin.read(&c, 1);
279                vdata.push_back(c);
280            }
281            ssize = vdata.size();
282
283            sdata = &vdata[0];
284
285            jas_stream_t* in = jas_stream_memopen((char*)sdata, ssize);
286
287            char* opt = 0;
288            if(options && !options->getOptionString().empty())
289            {
290                opt = new char[options->getOptionString().size() + 1];
291                strcpy(opt, options->getOptionString().c_str());
292            }
293            jas_image_t* jimage = jas_image_decode(in, -1, opt); // last is the option string whatto put there?
294            if(opt) delete[] opt;
295           
296            if (!jimage) return ReadResult::FILE_NOT_HANDLED;
297
298            int internalFormat = jimage->numcmpts_;
299
300            int s = jas_image_width(jimage);
301            int t = jas_image_height(jimage);
302            int r = 1;
303
304            unsigned char* data = new unsigned char[internalFormat*s*t];
305
306            jas_stream_t* mem = jas_stream_memopen((char*)data, internalFormat*s*t);
307
308            putdata(mem, jimage, internalFormat);
309
310            jas_image_destroy(jimage);
311            jas_stream_close(in);
312
313            unsigned int pixelFormat =
314                internalFormat == 1 ? GL_LUMINANCE :
315                internalFormat == 2 ? GL_LUMINANCE_ALPHA :
316                internalFormat == 3 ? GL_RGB :
317                internalFormat == 4 ? GL_RGBA : (GLenum)-1;
318
319            unsigned int dataType = GL_UNSIGNED_BYTE;
320
321            Image* image = new Image();
322//            image->setFileName(fileName.c_str());
323            image->setImage(s,t,r,
324                internalFormat,
325                pixelFormat,
326                dataType,
327                data,
328//                osg::Image::USE_NEW_DELETE);
329                osg::Image::NO_DELETE);
330
331            OSG_INFO << "image read ok "<<s<<"  "<<t<< std::endl;
332            return image;
333        }
334
335        virtual WriteResult writeObject(const osg::Object& object,const std::string& file, const osgDB::ReaderWriter::Options* options) const
336        {
337            const osg::Image* image = dynamic_cast<const osg::Image*>(&object);
338            if (!image) return WriteResult::FILE_NOT_HANDLED;
339
340            return writeImage(*image,file,options);
341        }
342
343        virtual WriteResult writeObject(const osg::Object& object,std::ostream& fout,const Options* options) const
344        {
345            const osg::Image* image = dynamic_cast<const osg::Image*>(&object);
346            if (!image) return WriteResult::FILE_NOT_HANDLED;
347
348            return writeImage(*image,fout,options);
349        }
350
351        virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
352        {
353            std::string ext = osgDB::getFileExtension(fileName);
354            if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
355
356            if (!img.isDataContiguous())
357            {
358                OSG_WARN<<"Warning: Writing of image data, that is non contiguous, is not supported by JPEG2000 plugin."<<std::endl;
359                return WriteResult::ERROR_IN_WRITING_FILE;
360            }
361
362            jas_image_cmptparm_t cmptparms[4];
363            jas_image_cmptparm_t *cmptparm;
364
365            int internalFormat = osg::Image::computeNumComponents(img.getPixelFormat());
366
367            jas_stream_t* mem = jas_stream_memopen((char*)img.data(), internalFormat*img.s()*img.t());
368
369            /* Create an image of the correct size. */
370            jas_image_t* jimage;
371            int i;
372            for (i = 0, cmptparm = cmptparms; i < internalFormat; ++i, ++cmptparm) {
373                cmptparm->tlx = 0;
374                cmptparm->tly = 0;
375                cmptparm->hstep = 1;
376                cmptparm->vstep = 1;
377                cmptparm->width = img.s();
378                cmptparm->height = img.t();
379                cmptparm->prec = 8;
380                cmptparm->sgnd = 0;
381            }
382            if (!(jimage = jas_image_create(internalFormat, cmptparms, JAS_CLRSPC_UNKNOWN))) {
383                return WriteResult::ERROR_IN_WRITING_FILE;
384            }
385
386            if(internalFormat == 1)
387            {
388                jas_image_setclrspc(jimage, JAS_CLRSPC_GENGRAY);
389                jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
390            }
391            else if(internalFormat == 2)
392            {
393                jas_image_setclrspc(jimage, JAS_CLRSPC_GENGRAY);
394                jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
395                jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
396            }
397            else if(internalFormat == 3)
398            {
399                jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB);
400                jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
401                jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
402                jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
403            }
404            else if(internalFormat == 4)
405            {
406                jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB);
407                jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
408                jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
409                jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
410                jas_image_setcmpttype(jimage, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
411            }
412
413            getdata(mem, jimage);
414
415            jas_stream_t* out = jas_stream_fopen(fileName.c_str(), "wb");
416            if (!out)
417                return WriteResult::ERROR_IN_WRITING_FILE;
418
419            char* opt = 0;
420            if(options)
421            {
422                opt = new char[options->getOptionString().size() + 1];
423                strcpy(opt, options->getOptionString().c_str());
424            }
425            jas_image_encode(jimage, out, _fmt_jp2,  opt);
426            if(opt) delete[] opt;
427
428            jas_stream_flush(out);
429
430            jas_stream_close(out);
431            jas_image_destroy(jimage);
432
433            return WriteResult::FILE_SAVED;
434        }
435
436        WriteResult writeImage(const osg::Image& img, std::ostream& fout, const Options* options) const
437        {
438            if (!img.isDataContiguous())
439            {
440                OSG_WARN<<"Warning: Writing of image data, that is non contiguous, is not supported by JPEG2000 plugin."<<std::endl;
441                return WriteResult::ERROR_IN_WRITING_FILE;
442            }
443
444            jas_image_cmptparm_t cmptparms[4];
445            jas_image_cmptparm_t *cmptparm;
446
447            int internalFormat = osg::Image::computeNumComponents(img.getPixelFormat());
448
449            jas_stream_t* mem = jas_stream_memopen((char*)img.data(), internalFormat*img.s()*img.t());
450
451            /* Create an image of the correct size. */
452            jas_image_t* jimage;
453            int i;
454            for (i = 0, cmptparm = cmptparms; i < internalFormat; ++i, ++cmptparm) {
455                cmptparm->tlx = 0;
456                cmptparm->tly = 0;
457                cmptparm->hstep = 1;
458                cmptparm->vstep = 1;
459                cmptparm->width = img.s();
460                cmptparm->height = img.t();
461                cmptparm->prec = 8;
462                cmptparm->sgnd = 0;
463            }
464            if (!(jimage = jas_image_create(internalFormat, cmptparms, JAS_CLRSPC_UNKNOWN))) {
465                return WriteResult::ERROR_IN_WRITING_FILE;
466            }
467
468            if(internalFormat == 1)
469            {
470                jas_image_setclrspc(jimage, JAS_CLRSPC_SGRAY);
471                jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
472            }
473            else if(internalFormat == 2)
474            {
475                jas_image_setclrspc(jimage, JAS_CLRSPC_SGRAY);
476                jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
477                jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
478            }
479            else if(internalFormat == 3)
480            {
481                jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB);
482                jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
483                jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
484                jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
485            }
486            else if(internalFormat == 4)
487            {
488                jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB);
489                jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
490                jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
491                jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
492                jas_image_setcmpttype(jimage, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
493            }
494
495            getdata(mem, jimage);
496
497            jas_stream_t* out = jas_stream_memopen(0, 0);
498//            jas_stream_t* out = jas_stream_fopen(fileName.c_str(), "wb");
499            if (!out)
500                return WriteResult::ERROR_IN_WRITING_FILE;
501
502            char* opt = 0;
503            if(options)
504            {
505                opt = new char[options->getOptionString().size() + 1];
506                strcpy(opt, options->getOptionString().c_str());
507            }
508
509            jas_image_encode(jimage, out, _fmt_jp2,  opt);
510            if(opt) delete[] opt;
511
512            jas_stream_flush(out);
513
514            // now the encoded jp2 image resides in the out->buf_ member with size out->len_ we now need to stream it to a std::ostream
515            jas_stream_memobj_t* obj = (jas_stream_memobj_t*) out->obj_;
516
517            fout.write((char*)obj->buf_, obj->len_);
518
519            fout << std::flush;
520
521            jas_stream_close(out);
522
523            jas_image_destroy(jimage);
524
525            return WriteResult::FILE_SAVED;
526        }
527
528
529        int _fmt_jp2;
530};
531
532// now register with Registry to instantiate the above
533// reader/writer.
534REGISTER_OSGPLUGIN(jp2, ReaderWriterJP2)
Note: See TracBrowser for help on using the browser.