From Johannes Scholz, "Attached you find a patch for osgDB::OutputStream and osgDB::InputStream to include osg::Image::data() using Base64 encoding inside the ASCII OSGT, if WriteImageHint=IncludeData is set, only."
git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14748 16af8721-9629-0410-8352-f15c8da7e697
This commit is contained in:
@@ -53,6 +53,7 @@ SET(TARGET_H
|
||||
${HEADER_PATH}/AuthenticationMap
|
||||
${HEADER_PATH}/Callbacks
|
||||
${HEADER_PATH}/ClassInterface
|
||||
${HEADER_PATH}/ConvertBase64
|
||||
${HEADER_PATH}/ConvertUTF
|
||||
${HEADER_PATH}/DatabasePager
|
||||
${HEADER_PATH}/DatabaseRevisions
|
||||
@@ -91,6 +92,7 @@ SET(TARGET_SRC
|
||||
AuthenticationMap.cpp
|
||||
Callbacks.cpp
|
||||
ClassInterface.cpp
|
||||
ConvertBase64.cpp
|
||||
ConvertUTF.cpp
|
||||
DatabasePager.cpp
|
||||
DatabaseRevisions.cpp
|
||||
|
||||
326
src/osgDB/ConvertBase64.cpp
Normal file
326
src/osgDB/ConvertBase64.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
/* This file is derived from the libb64 project which itself was released to public domain.
|
||||
* For details, see http://sourceforge.net/projects/libb64. Original code by Chris Venter
|
||||
* c++ wrapper for a base64 encoding and decoding algorithm
|
||||
*/
|
||||
|
||||
#include <osgDB/ConvertBase64>
|
||||
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
|
||||
namespace osgDB
|
||||
{
|
||||
|
||||
const int CHARS_PER_LINE = 72;
|
||||
|
||||
int base64_decode_value(char value_in)
|
||||
{
|
||||
static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
|
||||
static const char decoding_size = sizeof(decoding);
|
||||
value_in -= 43;
|
||||
if (value_in < 0 || value_in > decoding_size) return -1;
|
||||
return decoding[(int)value_in];
|
||||
}
|
||||
|
||||
void base64_init_decodestate(base64_decodestate* state_in)
|
||||
{
|
||||
state_in->step = step_a;
|
||||
state_in->plainchar = 0;
|
||||
}
|
||||
|
||||
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
|
||||
{
|
||||
const char* codechar = code_in;
|
||||
char* plainchar = plaintext_out;
|
||||
char fragment;
|
||||
|
||||
*plainchar = state_in->plainchar;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
case step_a:
|
||||
do {
|
||||
if (codechar == code_in+length_in)
|
||||
{
|
||||
state_in->step = step_a;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
fragment = (char)base64_decode_value(*codechar++);
|
||||
} while (fragment < 0);
|
||||
*plainchar = (fragment & 0x03f) << 2;
|
||||
case step_b:
|
||||
do {
|
||||
if (codechar == code_in+length_in)
|
||||
{
|
||||
state_in->step = step_b;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
fragment = (char)base64_decode_value(*codechar++);
|
||||
} while (fragment < 0);
|
||||
*plainchar++ |= (fragment & 0x030) >> 4;
|
||||
*plainchar = (fragment & 0x00f) << 4;
|
||||
case step_c:
|
||||
do {
|
||||
if (codechar == code_in+length_in)
|
||||
{
|
||||
state_in->step = step_c;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
fragment = (char)base64_decode_value(*codechar++);
|
||||
} while (fragment < 0);
|
||||
*plainchar++ |= (fragment & 0x03c) >> 2;
|
||||
*plainchar = (fragment & 0x003) << 6;
|
||||
case step_d:
|
||||
do {
|
||||
if (codechar == code_in+length_in)
|
||||
{
|
||||
state_in->step = step_d;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
fragment = (char)base64_decode_value(*codechar++);
|
||||
} while (fragment < 0);
|
||||
*plainchar++ |= (fragment & 0x03f);
|
||||
}
|
||||
}
|
||||
/* control should not reach here */
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in)
|
||||
{
|
||||
state_in->step = step_A;
|
||||
state_in->result = 0;
|
||||
state_in->stepcount = 0;
|
||||
}
|
||||
|
||||
char base64_encode_value(char value_in)
|
||||
{
|
||||
static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
if (value_in > 63) return '=';
|
||||
return encoding[(int)value_in];
|
||||
}
|
||||
|
||||
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
|
||||
{
|
||||
const char* plainchar = plaintext_in;
|
||||
const char* const plaintextend = plaintext_in + length_in;
|
||||
char* codechar = code_out;
|
||||
char result;
|
||||
char fragment;
|
||||
|
||||
result = state_in->result;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
case step_A:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_A;
|
||||
return codechar - code_out;
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result = (fragment & 0x0fc) >> 2;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x003) << 4;
|
||||
case step_B:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_B;
|
||||
return codechar - code_out;
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0f0) >> 4;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x00f) << 2;
|
||||
case step_C:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_C;
|
||||
return codechar - code_out;
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0c0) >> 6;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x03f) >> 0;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
|
||||
++(state_in->stepcount);
|
||||
if (state_in->stepcount == CHARS_PER_LINE/4)
|
||||
{
|
||||
*codechar++ = '\n';
|
||||
state_in->stepcount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* control should not reach here */
|
||||
return codechar - code_out;
|
||||
}
|
||||
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
||||
{
|
||||
char* codechar = code_out;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
case step_B:
|
||||
*codechar++ = base64_encode_value(state_in->result);
|
||||
*codechar++ = '=';
|
||||
*codechar++ = '=';
|
||||
break;
|
||||
case step_C:
|
||||
*codechar++ = base64_encode_value(state_in->result);
|
||||
*codechar++ = '=';
|
||||
break;
|
||||
case step_A:
|
||||
break;
|
||||
}
|
||||
*codechar++ = '\n';
|
||||
|
||||
return codechar - code_out;
|
||||
}
|
||||
|
||||
int Base64encoder::encode(char value_in)
|
||||
{
|
||||
return base64_encode_value(value_in);
|
||||
}
|
||||
|
||||
int Base64encoder::encode(const char* code_in, const int length_in, char* plaintext_out)
|
||||
{
|
||||
return base64_encode_block(code_in, length_in, plaintext_out, &_state);
|
||||
}
|
||||
|
||||
int Base64encoder::encode_end(char* plaintext_out)
|
||||
{
|
||||
return base64_encode_blockend(plaintext_out, &_state);
|
||||
}
|
||||
|
||||
void Base64encoder::encode(std::istream& istream_in, std::ostream& ostream_in)
|
||||
{
|
||||
base64_init_encodestate(&_state);
|
||||
|
||||
const int N = _buffersize;
|
||||
char* plaintext = new char[N];
|
||||
char* code = new char[2*N];
|
||||
int plainlength;
|
||||
int codelength;
|
||||
|
||||
do
|
||||
{
|
||||
istream_in.read(plaintext, N);
|
||||
plainlength = istream_in.gcount();
|
||||
|
||||
codelength = encode(plaintext, plainlength, code);
|
||||
ostream_in.write(code, codelength);
|
||||
}
|
||||
while (istream_in.good() && plainlength > 0);
|
||||
|
||||
codelength = encode_end(code);
|
||||
ostream_in.write(code, codelength);
|
||||
|
||||
base64_init_encodestate(&_state);
|
||||
|
||||
delete [] code;
|
||||
delete [] plaintext;
|
||||
}
|
||||
|
||||
void Base64encoder::encode(const char* chars_in, int length_in, std::string& code_out)
|
||||
{
|
||||
std::stringstream stream_out;
|
||||
{
|
||||
std::stringstream stream_in;
|
||||
{
|
||||
stream_in<<std::string(chars_in, length_in);
|
||||
}
|
||||
stream_in.seekg(0, stream_in.beg);
|
||||
encode(stream_in, stream_out);
|
||||
}
|
||||
stream_out.seekg (0, stream_out.beg);
|
||||
code_out = stream_out.str();
|
||||
}
|
||||
|
||||
int Base64decoder::decode(char value_in)
|
||||
{
|
||||
return base64_decode_value(value_in);
|
||||
}
|
||||
|
||||
int Base64decoder::decode(const char* code_in, const int length_in, char* plaintext_out)
|
||||
{
|
||||
return base64_decode_block(code_in, length_in, plaintext_out, &_state);
|
||||
}
|
||||
|
||||
void Base64decoder::decode(std::istream& istream_in, std::ostream& ostream_in)
|
||||
{
|
||||
base64_init_decodestate(&_state);
|
||||
|
||||
const int N = _buffersize;
|
||||
char* code = new char[N];
|
||||
char* plaintext = new char[N];
|
||||
int codelength;
|
||||
int plainlength;
|
||||
|
||||
do
|
||||
{
|
||||
istream_in.read((char*)code, N);
|
||||
codelength = istream_in.gcount();
|
||||
plainlength = decode(code, codelength, plaintext);
|
||||
ostream_in.write((const char*)plaintext, plainlength);
|
||||
}
|
||||
while (istream_in.good() && codelength > 0);
|
||||
|
||||
base64_init_decodestate(&_state);
|
||||
|
||||
delete [] code;
|
||||
delete [] plaintext;
|
||||
}
|
||||
|
||||
char* Base64decoder::decode(const std::vector<std::string>& str_in, std::vector<unsigned int>& pos_out)
|
||||
{
|
||||
std::stringstream stream_out;
|
||||
{
|
||||
std::stringstream stream_in;
|
||||
|
||||
pos_out.resize(str_in.size());
|
||||
|
||||
for (unsigned int i = 0; i < str_in.size(); ++i)
|
||||
{
|
||||
stream_in.clear();
|
||||
stream_in<<str_in.at(i);
|
||||
stream_in.seekg(0, stream_in.beg);
|
||||
|
||||
decode(stream_in, stream_out);
|
||||
pos_out.at(i) = stream_out.tellp();
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory for use with osg::Image
|
||||
char* allocated_out = new char[stream_out.tellp()];
|
||||
memcpy(allocated_out, stream_out.str().c_str(), stream_out.tellp());
|
||||
|
||||
return allocated_out;
|
||||
}
|
||||
|
||||
} // namespace osgDB
|
||||
@@ -15,9 +15,11 @@
|
||||
#include <osg/Notify>
|
||||
#include <osg/ImageSequence>
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgDB/WriteFile>
|
||||
#include <osgDB/XmlParser>
|
||||
#include <osgDB/FileNameUtils>
|
||||
#include <osgDB/ObjectWrapper>
|
||||
#include <osgDB/ConvertBase64>
|
||||
|
||||
using namespace osgDB;
|
||||
|
||||
@@ -726,6 +728,61 @@ osg::Image* InputStream::readImage(bool readFromExternal)
|
||||
if ( image && levelSize>0 )
|
||||
image->setMipmapLevels( levels );
|
||||
readFromExternal = false;
|
||||
} else { // ASCII
|
||||
// _origin, _s & _t & _r, _internalTextureFormat
|
||||
int origin, s, t, r, internalFormat;
|
||||
*this >> PROPERTY("Origin") >> origin;
|
||||
*this >> PROPERTY("Size") >> s >> t >> r;
|
||||
*this >> PROPERTY("InternalTextureFormat") >> internalFormat;
|
||||
|
||||
// _pixelFormat, _dataType, _packing, _allocationMode
|
||||
int pixelFormat, dataType, packing, mode;
|
||||
*this >> PROPERTY("PixelFormat") >> pixelFormat;
|
||||
*this >> PROPERTY("DataType") >> dataType;
|
||||
*this >> PROPERTY("Packing") >> packing;
|
||||
*this >> PROPERTY("AllocationMode") >> mode;
|
||||
|
||||
*this >> PROPERTY("Data");
|
||||
unsigned int levelSize = readSize()-1;
|
||||
*this >> BEGIN_BRACKET;
|
||||
|
||||
// _data
|
||||
std::vector<std::string> encodedData;
|
||||
encodedData.resize(levelSize+1);
|
||||
readWrappedString(encodedData.at(0));
|
||||
|
||||
// Read all mipmap levels and to also add them to char* data
|
||||
// _mipmapData
|
||||
osg::Image::MipmapDataType levels(levelSize);
|
||||
for ( unsigned int i=1; i<=levelSize; ++i )
|
||||
{
|
||||
//*this >> levels[i];
|
||||
readWrappedString(encodedData.at(i));
|
||||
}
|
||||
|
||||
Base64decoder d;
|
||||
char* data = d.decode(encodedData, levels);
|
||||
// remove last item as we do not need the actual size
|
||||
// of the image including all mipmaps
|
||||
levels.pop_back();
|
||||
|
||||
*this >> END_BRACKET;
|
||||
|
||||
if ( !data )
|
||||
throwException( "InputStream::readImage() Decoding of stream failed. Out of memory." );
|
||||
if ( getException() ) return NULL;
|
||||
|
||||
image = new osg::Image;
|
||||
image->setOrigin( (osg::Image::Origin)origin );
|
||||
image->setImage( s, t, r, internalFormat, pixelFormat, dataType,
|
||||
(unsigned char*)data, (osg::Image::AllocationMode)mode, packing );
|
||||
|
||||
// Level positions (size of mipmap data)
|
||||
// from actual size of mipmap data read before
|
||||
if ( image && levelSize>0 )
|
||||
image->setMipmapLevels( levels );
|
||||
|
||||
readFromExternal = false;
|
||||
}
|
||||
break;
|
||||
case IMAGE_INLINE_FILE:
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
*/
|
||||
// Written by Wang Rui, (C) 2010
|
||||
|
||||
#include <osg/Version>
|
||||
#include <osg/Notify>
|
||||
#include <osgDB/ConvertBase64>
|
||||
#include <osgDB/FileUtils>
|
||||
#include <osgDB/WriteFile>
|
||||
#include <osgDB/ObjectWrapper>
|
||||
@@ -526,6 +528,31 @@ void OutputStream::writeImage( const osg::Image* img )
|
||||
if (t<1) t=1;
|
||||
if (r<1) r=1;
|
||||
}
|
||||
} else { // ASCII
|
||||
*this << PROPERTY("Origin") << img->getOrigin() << std::endl; // _origin
|
||||
*this << PROPERTY("Size") << img->s() << img->t() << img->r() << std::endl; // _s & _t & _r
|
||||
*this << PROPERTY("InternalTextureFormat") << img->getInternalTextureFormat() << std::endl; // _internalTextureFormat
|
||||
*this << PROPERTY("PixelFormat") << img->getPixelFormat() << std::endl; // _pixelFormat
|
||||
*this << PROPERTY("DataType") << img->getDataType() << std::endl; // _dataType
|
||||
*this << PROPERTY("Packing") << img->getPacking() << std::endl; // _packing
|
||||
*this << PROPERTY("AllocationMode") << img->getAllocationMode() << std::endl; // _allocationMode
|
||||
|
||||
// _data
|
||||
*this << PROPERTY("Data") << img->getNumMipmapLevels();
|
||||
*this << BEGIN_BRACKET << std::endl;
|
||||
|
||||
Base64encoder e;
|
||||
for(osg::Image::DataIterator img_itr(img); img_itr.valid(); ++img_itr)
|
||||
{
|
||||
std::string encodedData;
|
||||
e.encode((char*)img_itr.data(), img_itr.size(), encodedData);
|
||||
// Each set of data is written into a separate string so we can
|
||||
// distiguish between main data and all mipmap levels, so writing
|
||||
// mipmap size is not required for ASCII mode.
|
||||
writeWrappedString(encodedData);
|
||||
}
|
||||
|
||||
*this << END_BRACKET << std::endl;
|
||||
}
|
||||
break;
|
||||
case IMAGE_INLINE_FILE:
|
||||
|
||||
Reference in New Issue
Block a user