5
* Created by Stephan Huber on 07.02.08.
6
* Copyright 2008 __MyCompanyName__. All rights reserved.
11
#include "QTImportExport.h"
14
#include <osgDB/FileNameUtils>
17
/** small exception class bundling a error-message */
18
class QTImportExportException : public std::exception {
21
QTImportExportException(int err, const std::string& msg) : std::exception(), _err(err), _msg(msg) {}
23
virtual const char* what() { return _msg.c_str(); }
24
int getErrorCode() { return _err; }
26
virtual ~QTImportExportException() throw () {}
33
QuicktimeImportExport::QuicktimeImportExport()
41
// ----------------------------------------------------------------------------------------------------------
43
// ----------------------------------------------------------------------------------------------------------
45
void QuicktimeImportExport::flipImage(unsigned char* pixels, int bytesPerPixel, unsigned int width, unsigned height)
48
unsigned imageSize = width * height * bytesPerPixel;
49
char *tBuffer = new char [imageSize];
50
unsigned int rowBytes = width * bytesPerPixel;
52
for (i = 0, j = imageSize - rowBytes; i < imageSize; i += rowBytes, j -= rowBytes)
53
memcpy( &tBuffer[j], &pixels[i], (size_t)rowBytes );
55
memcpy(pixels, tBuffer, (size_t)imageSize);
62
// ----------------------------------------------------------------------------------------------------------
63
// prepareBufferForOSG
64
// ----------------------------------------------------------------------------------------------------------
66
unsigned char* QuicktimeImportExport::pepareBufferForOSG(unsigned char * buffer, int bytesPerPixel, unsigned int width, unsigned int height)
68
unsigned char *pixels = new unsigned char [height * width * 4];
69
unsigned char *dstp = pixels;
70
unsigned char *srcp = buffer;
73
int roffset, goffset, boffset, aoffset;
77
switch (bytesPerPixel) {
80
roffset = goffset = boffset = 0;
98
for (i = 0; i < height; ++i )
100
for (j = 0; j < width; ++j )
102
dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
103
dstp[1] = srcp[roffset];
104
dstp[2] = srcp[goffset];
105
dstp[3] = srcp[boffset];
112
flipImage(pixels, bytesPerPixel, width, height);
119
// ----------------------------------------------------------------------------------------------------------
120
// prepareBufferForQuicktime
121
// ----------------------------------------------------------------------------------------------------------
123
unsigned char* QuicktimeImportExport::prepareBufferForQuicktime(unsigned char* buffer, GLenum pixelFormat, int bytesPerPixel, unsigned int width, unsigned int height)
125
unsigned char *pixels = new unsigned char [height * width * 4];
126
unsigned char *dstp = pixels;
127
unsigned char *srcp = buffer;
130
int roffset, goffset, boffset, aoffset;
134
switch (bytesPerPixel) {
137
roffset = goffset = boffset = 0;
147
switch (pixelFormat) {
165
for (i = 0; i < height; ++i )
167
for (j = 0; j < width; ++j )
169
dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
170
dstp[1] = srcp[roffset];
171
dstp[2] = srcp[goffset];
172
dstp[3] = srcp[boffset];
179
flipImage(pixels, 4, width, height);
185
// ----------------------------------------------------------------------------------------------------------
187
// ----------------------------------------------------------------------------------------------------------
189
osg::Image* QuicktimeImportExport::readFromStream(std::istream & inStream, const std::string& fileTypeHint, long sizeHint)
191
char* content = NULL;
196
content = new char[length];
197
inStream.read (content,length);
201
int readBytes(0), newBytes(0);
205
while (!inStream.eof()) {
206
inStream.read(buffer, 10240);
207
newBytes = inStream.gcount();
209
char* newcontent = new char[readBytes + newBytes];
212
memcpy(newcontent, content, readBytes);
214
memcpy(&newcontent[readBytes], &buffer, newBytes);
215
readBytes += newBytes;
216
if (content) delete[] content;
217
content = newcontent;
223
osg::Image* img = doImport(reinterpret_cast<unsigned char*>(content), length, fileTypeHint);
225
if (content) delete[] content;
230
Handle getPtrDataRef(unsigned char *data, unsigned int size, const std::string &filename)
232
// Load Data Reference
234
Handle fileNameHandle;
235
PointerDataRefRecord ptrDataRefRec;
236
ComponentInstance dataRefHandler;
237
unsigned char pstr[255];
239
ptrDataRefRec.data = data;
240
ptrDataRefRec.dataLength = size;
242
/*err = */PtrToHand(&ptrDataRefRec, &dataRef, sizeof(PointerDataRefRecord));
244
// Open a Data Handler for the Data Reference
245
/*err = */OpenADataHandler(dataRef, PointerDataHandlerSubType, NULL,
246
(OSType)0, NULL, kDataHCanRead, &dataRefHandler);
248
// Convert From CString in filename to a PascalString in pstr
249
if (filename.length() > 255) {
250
CopyCStringToPascal(filename.c_str(), pstr);
251
//hmm...not good, pascal string limit is 255!
252
//do some error handling maybe?!
255
// Add filename extension
256
/*err = */PtrToHand(pstr, &fileNameHandle, filename.length() + 1);
257
/*err = */DataHSetDataRefExtension(dataRefHandler, fileNameHandle,
258
kDataRefExtensionFileName);
259
DisposeHandle(fileNameHandle);
261
// Release old handler which does not have the extensions
262
DisposeHandle(dataRef);
264
// Grab the SAFE_NEW version of the data ref from the data handler
265
/*err = */ DataHGetDataRef(dataRefHandler, &dataRef);
267
CloseComponent(dataRefHandler);
273
osg::Image* QuicktimeImportExport::doImport(unsigned char* data, unsigned int sizeData, const std::string& fileTypeHint)
275
GWorldPtr gworld = 0;
278
GraphicsImportComponent gicomp = 0;
280
GDHandle origDevice = 0;
281
CGrafPtr origPort = 0;
282
ImageDescriptionHandle desc = 0;
284
unsigned int xsize, ysize;
285
unsigned char* imageData;
287
// Data Handle for file data ( & load data from file )
288
Handle dataRef = getPtrDataRef(data, sizeData, fileTypeHint);
293
// GraphicsImporter - Get Importer for our filetype
294
GetGraphicsImporterForDataRef(dataRef, 'ptr ', &gicomp);
296
// GWorld - Get Texture Info
297
err = GraphicsImportGetNaturalBounds(gicomp, &rectImage);
299
throw QTImportExportException(err, "GraphicsImportGetNaturalBounds failed");
302
xsize = (unsigned int)(rectImage.right - rectImage.left);
303
ysize = (unsigned int)(rectImage.bottom - rectImage.top);
305
// ImageDescription - Get Image Description
306
err = GraphicsImportGetImageDescription(gicomp, &desc);
308
throw QTImportExportException(err, "GraphicsImportGetImageDescription failed");
311
// ImageDescription - Get Bit Depth
312
HLock(reinterpret_cast<char **>(desc));
315
// GWorld - Pixel Format stuff
316
pixelFormat = k32ARGBPixelFormat; // Make sure its forced...NOTE: i'm pretty sure this cannot be RGBA!
318
// GWorld - Row stride
319
rowStride = xsize * 4; // (width * depth_bpp / 8)
321
// GWorld - Allocate output buffer
322
imageData = new unsigned char[rowStride * ysize];
324
// GWorld - Actually Create IT!
325
QTNewGWorldFromPtr(&gworld, pixelFormat, &rectImage, 0, 0, 0, imageData, rowStride);
327
throw QTImportExportException(-1, "QTNewGWorldFromPtr failed");
330
// Save old Graphics Device and Graphics Port to reset to later
331
GetGWorld (&origPort, &origDevice);
333
// GraphicsImporter - Set Destination GWorld (our buffer)
334
err = GraphicsImportSetGWorld(gicomp, gworld, 0);
336
throw QTImportExportException(err, "GraphicsImportSetGWorld failed");
339
// GraphicsImporter - Set Quality Level
340
err = GraphicsImportSetQuality(gicomp, codecLosslessQuality);
342
throw QTImportExportException(err, "GraphicsImportSetQuality failed");
345
// Lock pixels so that we can draw to our memory texture
346
if (!GetGWorldPixMap(gworld) || !LockPixels(GetGWorldPixMap(gworld))) {
347
throw QTImportExportException(0, "GetGWorldPixMap failed");
351
//*** Draw GWorld into our Memory Texture!
352
GraphicsImportDraw(gicomp);
355
UnlockPixels(GetGWorldPixMap(gworld));
356
SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now)
357
DisposeGWorld(gworld);
358
CloseComponent(gicomp);
359
DisposeHandle(reinterpret_cast<char **>(desc));
360
DisposeHandle(dataRef);
362
catch (QTImportExportException e)
367
UnlockPixels(GetGWorldPixMap(gworld));
368
SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now)
369
DisposeGWorld(gworld);
372
CloseComponent(gicomp);
374
DisposeHandle(reinterpret_cast<char **>(desc));
379
DisposeHandle(dataRef);
386
unsigned int glpixelFormat;
390
glpixelFormat = GL_RGB;
393
glpixelFormat = GL_RGBA;
397
setError("unknown pixelformat");
402
unsigned char* swizzled = pepareBufferForOSG(imageData, depth >> 3, xsize, ysize);
406
osg::Image* image = new osg::Image();
407
image->setFileName(fileTypeHint.c_str());
408
image->setImage(xsize,ysize,1,
413
osg::Image::USE_NEW_DELETE );
420
void QuicktimeImportExport::writeToStream(std::ostream& outStream, osg::Image* image, const std::string& fileTypeHint)
423
std::string ext = osgDB::getFileExtension(fileTypeHint);
424
//Build map of extension <-> osFileTypes
425
static std::map<std::string, OSType> extmap;
426
if (extmap.size() == 0) {
427
extmap["jpg"] = kQTFileTypeJPEG;
428
extmap["jpeg"] = kQTFileTypeJPEG;
429
extmap["bmp"] = kQTFileTypeBMP;
430
extmap["tif"] = kQTFileTypeTIFF;
431
extmap["tiff"] = kQTFileTypeTIFF;
432
extmap["png"] = kQTFileTypePNG;
433
extmap["gif"] = kQTFileTypeGIF;
434
extmap["psd"] = kQTFileTypePhotoShop;
435
extmap["sgi"] = kQTFileTypeSGIImage;
436
extmap["rgb"] = kQTFileTypeSGIImage;
437
extmap["rgba"] = kQTFileTypeSGIImage;
441
std::map<std::string, OSType>::iterator cur = extmap.find(ext);
443
// can not handle this type of file, perhaps a movie?
444
if (cur == extmap.end())
447
unsigned int numBytes = image->computeNumComponents(image->getPixelFormat());
448
unsigned char* pixels = prepareBufferForQuicktime(
450
image->getPixelFormat(),
457
OSType desiredType = cur->second;
458
GraphicsExportComponent geComp = NULL;
461
dataHandle = NewHandle(0);
464
OSErr err = OpenADefaultComponent(GraphicsExporterComponentType, desiredType, &geComp);
465
Rect bounds = {0,0, image->t(), image->s()};
467
err = QTNewGWorldFromPtr(&gw, k32ARGBPixelFormat, &bounds, 0,0,0, pixels, image->s()*4);
469
throw QTImportExportException(err, "could not create gworld for type " + ext);
472
err = GraphicsExportSetInputGWorld(geComp, gw);
474
throw QTImportExportException(err, "could not set input gworld for type " + ext);
477
err = GraphicsExportSetOutputHandle( geComp, dataHandle);
479
throw QTImportExportException(err, "could not set output file for type " + ext);
482
// Set the compression quality (needed for JPEG, not necessarily for other formats)
483
if (desiredType == kQTFileTypeJPEG) {
484
err = GraphicsExportSetCompressionQuality(geComp, codecLosslessQuality);
486
throw QTImportExportException(err, "could not set compression for type " + ext);
492
err = GraphicsExportSetDepth( geComp, k32ARGBPixelFormat ); // depth
494
// else k24RGBPixelFormat???
497
err = GraphicsExportDoExport(geComp, NULL);
499
throw QTImportExportException(err, "could not do the export for type " + ext);
503
CloseComponent(geComp);
505
if (gw) DisposeGWorld (gw);
506
if (pixels) free(pixels);
508
outStream.write(*dataHandle, GetHandleSize(dataHandle));
509
DisposeHandle(dataHandle);
513
catch (QTImportExportException e)
517
if (geComp != NULL) CloseComponent(geComp);
518
if (gw != NULL) DisposeGWorld (gw);
519
if (pixels) free(pixels);
521
DisposeHandle(dataHandle);