#include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include } #ifndef SEEK_SET # define SEEK_SET 0 #endif using namespace osg; extern "C" { static int putdata(jas_stream_t *out, jas_image_t *image, int numcmpts) { int ret; int cmptno; int x; int y; jas_matrix_t *data[4]; jas_seqent_t *d[4]; jas_seqent_t v; int width, height; width = jas_image_cmptwidth(image, 0); height = jas_image_cmptheight(image, 0); ret = -1; data[0] = 0; data[1] = 0; data[2] = 0; data[3] = 0; for (cmptno = 0; cmptno < numcmpts; ++cmptno) { if (!(data[cmptno] = jas_matrix_create(1, width))) { goto done; } } for (y = height - 1; y >= 0; --y) { for (cmptno = 0; cmptno < numcmpts; ++cmptno) { if (jas_image_readcmpt(image, cmptno, 0, y, width, 1, data[cmptno])) { goto done; } d[cmptno] = jas_matrix_getref(data[cmptno], 0, 0); } for (x = 0; x < width; ++x) { for (cmptno = 0; cmptno < numcmpts; ++cmptno) { v = *d[cmptno]; if (v < 0) { v = 0; } if (v > 255) { v = 255; } unsigned char c; c = v; if (jas_stream_putc(out, c) == EOF) { goto done; } ++d[cmptno]; } } if (jas_stream_error(out)) { goto done; } } jas_stream_flush(out); ret = 0; done: for (cmptno = 0; cmptno < numcmpts; ++cmptno) { if (data[cmptno]) { jas_matrix_destroy(data[cmptno]); } } return ret; } static int getdata(jas_stream_t *in, jas_image_t *image) { int ret; int numcmpts; int cmptno; jas_matrix_t *data[4]; int x; int y; int width, height; width = jas_image_cmptwidth(image, 0); height = jas_image_cmptheight(image, 0); numcmpts = jas_image_numcmpts(image); ret = -1; data[0] = 0; data[1] = 0; data[2] = 0; data[3] = 0; for (cmptno = 0; cmptno < numcmpts; ++cmptno) { if (!(data[cmptno] = jas_matrix_create(1, width))) { goto done; } } for (y = height - 1; y >= 0; --y) // for (y = 0; y < height; ++y) { for (x = 0; x < width; ++x) { for (cmptno = 0; cmptno < numcmpts; ++cmptno) { /* The sample data is unsigned. */ int c; if ((c = jas_stream_getc(in)) == EOF) { return -1; } jas_matrix_set(data[cmptno], 0, x, c); } } for (cmptno = 0; cmptno < numcmpts; ++cmptno) { if (jas_image_writecmpt(image, cmptno, 0, y, width, 1, data[cmptno])) { goto done; } } } jas_stream_flush(in); ret = 0; done: for (cmptno = 0; cmptno < numcmpts; ++cmptno) { if (data[cmptno]) { jas_matrix_destroy(data[cmptno]); } } return ret; } } class ReaderWriterJP2 : public osgDB::ReaderWriter { public: ReaderWriterJP2() { supportsExtension("jp2","Jpeg2000 image format"); supportsExtension("jpc","Jpeg2000 image format"); jas_init(); // little dance here to get around warnings created by jas_image_strtofmt use of char* rather than const char* // as a parameted and modern compilers deprecating "jp2" string being treated as char*. char* jp2 = strdup("jp2"); _fmt_jp2 = jas_image_strtofmt(jp2); free(jp2); } ~ReaderWriterJP2() { jas_cleanup(); } virtual const char* className() const { return "JPEG 2000 Image Reader/Writer"; } virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const { return readImage(file,options); } virtual ReadResult readObject(std::istream& fin, const Options* options) const { return readImage(fin,options); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if(fileName.empty()) { // note from Robert, Dec03, I find returning a valid image when no // file exists a bit odd... osg::Image *img = new osg::Image; img->setFileName(fileName); return img; } FILE * fileHandle = osgDB::fopen(fileName.c_str(), "rb"); if (!fileHandle) { return ReadResult::ERROR_IN_READING_FILE; } jas_stream_t* in = jas_stream_freopen(fileName.c_str(), "rb", fileHandle); // Replacement for jas_stream_fopen() to be able to support UTF8 if (!in) { fclose(fileHandle); return ReadResult::ERROR_IN_READING_FILE; } char* opt = 0; if(options) { opt = new char[options->getOptionString().size() + 1]; strcpy(opt, options->getOptionString().c_str()); } jas_image_t* jimage = jas_image_decode(in, -1, opt); // last is the option string whatto put there? if(opt) delete[] opt; int internalFormat = jimage->numcmpts_; int s = jas_image_width(jimage); int t = jas_image_height(jimage); int r = 1; unsigned char* data = new unsigned char[internalFormat*s*t]; jas_stream_t* mem = jas_stream_memopen((char*)data, internalFormat*s*t); putdata(mem, jimage, internalFormat); jas_image_destroy(jimage); jas_stream_close(in); fclose(fileHandle); unsigned int pixelFormat = internalFormat == 1 ? GL_LUMINANCE : internalFormat == 2 ? GL_LUMINANCE_ALPHA : internalFormat == 3 ? GL_RGB : internalFormat == 4 ? GL_RGBA : (GLenum)-1; unsigned int dataType = GL_UNSIGNED_BYTE; Image* image = new Image(); image->setFileName(fileName.c_str()); image->setImage(s,t,r, internalFormat, pixelFormat, dataType, data, // osg::Image::USE_NEW_DELETE); osg::Image::NO_DELETE); OSG_INFO << "image read ok "< vdata; while(!fin.eof()) { fin.read(&c, 1); vdata.push_back(c); } ssize = vdata.size(); sdata = &vdata[0]; jas_stream_t* in = jas_stream_memopen((char*)sdata, ssize); char* opt = 0; if(options && !options->getOptionString().empty()) { opt = new char[options->getOptionString().size() + 1]; strcpy(opt, options->getOptionString().c_str()); } jas_image_t* jimage = jas_image_decode(in, -1, opt); // last is the option string whatto put there? if(opt) delete[] opt; if (!jimage) return ReadResult::FILE_NOT_HANDLED; int internalFormat = jimage->numcmpts_; int s = jas_image_width(jimage); int t = jas_image_height(jimage); int r = 1; unsigned char* data = new unsigned char[internalFormat*s*t]; jas_stream_t* mem = jas_stream_memopen((char*)data, internalFormat*s*t); putdata(mem, jimage, internalFormat); jas_image_destroy(jimage); jas_stream_close(in); unsigned int pixelFormat = internalFormat == 1 ? GL_LUMINANCE : internalFormat == 2 ? GL_LUMINANCE_ALPHA : internalFormat == 3 ? GL_RGB : internalFormat == 4 ? GL_RGBA : (GLenum)-1; unsigned int dataType = GL_UNSIGNED_BYTE; Image* image = new Image(); // image->setFileName(fileName.c_str()); image->setImage(s,t,r, internalFormat, pixelFormat, dataType, data, // osg::Image::USE_NEW_DELETE); osg::Image::NO_DELETE); OSG_INFO << "image read ok "<(&object); if (!image) return WriteResult::FILE_NOT_HANDLED; return writeImage(*image,file,options); } virtual WriteResult writeObject(const osg::Object& object,std::ostream& fout,const Options* options) const { const osg::Image* image = dynamic_cast(&object); if (!image) return WriteResult::FILE_NOT_HANDLED; return writeImage(*image,fout,options); } virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; if (!img.isDataContiguous()) { OSG_WARN<<"Warning: Writing of image data, that is non contiguous, is not supported by JPEG2000 plugin."<tlx = 0; cmptparm->tly = 0; cmptparm->hstep = 1; cmptparm->vstep = 1; cmptparm->width = img.s(); cmptparm->height = img.t(); cmptparm->prec = 8; cmptparm->sgnd = 0; } if (!(jimage = jas_image_create(internalFormat, cmptparms, JAS_CLRSPC_UNKNOWN))) { return WriteResult::ERROR_IN_WRITING_FILE; } if(internalFormat == 1) { jas_image_setclrspc(jimage, JAS_CLRSPC_GENGRAY); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); } else if(internalFormat == 2) { jas_image_setclrspc(jimage, JAS_CLRSPC_GENGRAY); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } else if(internalFormat == 3) { jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); } else if(internalFormat == 4) { jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); jas_image_setcmpttype(jimage, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } getdata(mem, jimage); FILE * fileHandle = osgDB::fopen(fileName.c_str(), "wb"); if (!fileHandle) { return WriteResult::ERROR_IN_WRITING_FILE; } jas_stream_t* out = jas_stream_freopen(fileName.c_str(), "wb", fileHandle); // Replacement for jas_stream_fopen() to be able to support UTF8 if (!out) { fclose(fileHandle); return WriteResult::ERROR_IN_WRITING_FILE; } char* opt = 0; if(options) { opt = new char[options->getOptionString().size() + 1]; strcpy(opt, options->getOptionString().c_str()); } jas_image_encode(jimage, out, _fmt_jp2, opt); if(opt) delete[] opt; jas_stream_flush(out); jas_stream_close(out); jas_image_destroy(jimage); fclose(fileHandle); return WriteResult::FILE_SAVED; } WriteResult writeImage(const osg::Image& img, std::ostream& fout, const Options* options) const { if (!img.isDataContiguous()) { OSG_WARN<<"Warning: Writing of image data, that is non contiguous, is not supported by JPEG2000 plugin."<tlx = 0; cmptparm->tly = 0; cmptparm->hstep = 1; cmptparm->vstep = 1; cmptparm->width = img.s(); cmptparm->height = img.t(); cmptparm->prec = 8; cmptparm->sgnd = 0; } if (!(jimage = jas_image_create(internalFormat, cmptparms, JAS_CLRSPC_UNKNOWN))) { return WriteResult::ERROR_IN_WRITING_FILE; } if(internalFormat == 1) { jas_image_setclrspc(jimage, JAS_CLRSPC_SGRAY); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); } else if(internalFormat == 2) { jas_image_setclrspc(jimage, JAS_CLRSPC_SGRAY); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } else if(internalFormat == 3) { jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); } else if(internalFormat == 4) { jas_image_setclrspc(jimage, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jimage, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jimage, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jimage, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); jas_image_setcmpttype(jimage, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } getdata(mem, jimage); jas_stream_t* out = jas_stream_memopen(0, 0); if (!out) return WriteResult::ERROR_IN_WRITING_FILE; char* opt = 0; if(options) { opt = new char[options->getOptionString().size() + 1]; strcpy(opt, options->getOptionString().c_str()); } jas_image_encode(jimage, out, _fmt_jp2, opt); if(opt) delete[] opt; jas_stream_flush(out); // 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 jas_stream_memobj_t* obj = (jas_stream_memobj_t*) out->obj_; fout.write((char*)obj->buf_, obj->len_); fout << std::flush; jas_stream_close(out); jas_image_destroy(jimage); return WriteResult::FILE_SAVED; } int _fmt_jp2; }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(jp2, ReaderWriterJP2)