// I let Quicktime handle image import since it supports most popular // image formats such as: // *.psd, *.bmp, *.tif, *.png, *.jpg, *.gif, *.pct, *.pcx //------------------------------------------------------------------------ bool pixel_map::load_from_qt(const char *filename) { FSSpec fss; OSErr err; // get file specification to application directory err = HGetVol(nil, &fss.vRefNum, &fss.parID); if (err == noErr) { CopyCStringToPascal(filename, fss.name); GraphicsImportComponent gi; err = GetGraphicsImporterForFile (&fss, &gi); if (err == noErr) { ImageDescriptionHandle desc; GraphicsImportGetImageDescription(gi, &desc); // For simplicity, all images are currently converted to 32 bit. // create an empty pixelmap short depth = 32; create ((**desc).width, (**desc).height, (org_e)depth, 0xff); DisposeHandle ((Handle)desc); // let Quicktime draw to pixelmap GraphicsImportSetGWorld(gi, m_pmap, nil); GraphicsImportDraw(gi); // Well, this is a hack. The graphics importer sets the alpha channel of the pixelmap to 0x00 // for imported images without alpha channel but this would cause agg to draw an invisible image. // set alpha channel to 0xff unsigned char * buf = m_buf; for (unsigned int size = 0; size < m_img_size; size += 4) { *buf = 0xff; buf += 4; } } } return err == noErr; }
osg::Image* QuicktimeImportExport::doImport(unsigned char* data, unsigned int sizeData, const std::string& fileTypeHint) { GWorldPtr gworld = 0; OSType pixelFormat; int rowStride; GraphicsImportComponent gicomp = 0; Rect rectImage; GDHandle origDevice = 0; CGrafPtr origPort = 0; ImageDescriptionHandle desc = 0; int depth = 32; unsigned int xsize, ysize; unsigned char* imageData = 0; // Data Handle for file data ( & load data from file ) Handle dataRef = getPtrDataRef(data, sizeData, fileTypeHint); try { OSErr err = noErr; // GraphicsImporter - Get Importer for our filetype GetGraphicsImporterForDataRef(dataRef, 'ptr ', &gicomp); // GWorld - Get Texture Info err = GraphicsImportGetNaturalBounds(gicomp, &rectImage); if (err != noErr) { throw QTImportExportException(err, "GraphicsImportGetNaturalBounds failed"); } xsize = (unsigned int)(rectImage.right - rectImage.left); ysize = (unsigned int)(rectImage.bottom - rectImage.top); // ImageDescription - Get Image Description err = GraphicsImportGetImageDescription(gicomp, &desc); if (err != noErr) { throw QTImportExportException(err, "GraphicsImportGetImageDescription failed"); } // ImageDescription - Get Bit Depth HLock(reinterpret_cast<char **>(desc)); // GWorld - Pixel Format stuff pixelFormat = k32ARGBPixelFormat; // Make sure its forced...NOTE: i'm pretty sure this cannot be RGBA! // GWorld - Row stride rowStride = xsize * 4; // (width * depth_bpp / 8) // GWorld - Allocate output buffer imageData = new unsigned char[rowStride * ysize]; // GWorld - Actually Create IT! QTNewGWorldFromPtr(&gworld, pixelFormat, &rectImage, 0, 0, 0, imageData, rowStride); if (!gworld) { throw QTImportExportException(-1, "QTNewGWorldFromPtr failed"); } // Save old Graphics Device and Graphics Port to reset to later GetGWorld (&origPort, &origDevice); // GraphicsImporter - Set Destination GWorld (our buffer) err = GraphicsImportSetGWorld(gicomp, gworld, 0); if (err != noErr) { throw QTImportExportException(err, "GraphicsImportSetGWorld failed"); } // GraphicsImporter - Set Quality Level err = GraphicsImportSetQuality(gicomp, codecLosslessQuality); if (err != noErr) { throw QTImportExportException(err, "GraphicsImportSetQuality failed"); } // Lock pixels so that we can draw to our memory texture if (!GetGWorldPixMap(gworld) || !LockPixels(GetGWorldPixMap(gworld))) { throw QTImportExportException(0, "GetGWorldPixMap failed"); } //*** Draw GWorld into our Memory Texture! GraphicsImportDraw(gicomp); // Clean up UnlockPixels(GetGWorldPixMap(gworld)); SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now) DisposeGWorld(gworld); CloseComponent(gicomp); DisposeHandle(reinterpret_cast<char **>(desc)); DisposeHandle(dataRef); } catch (QTImportExportException& e) { setError(e.what()); if (gworld) { UnlockPixels(GetGWorldPixMap(gworld)); SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now) DisposeGWorld(gworld); } if (gicomp) CloseComponent(gicomp); if (desc) DisposeHandle(reinterpret_cast<char **>(desc)); if (imageData) delete[] imageData; if (dataRef) DisposeHandle(dataRef); return NULL; } unsigned int bytesPerPixel = depth / 8; unsigned int glpixelFormat; switch(bytesPerPixel) { case 3 : glpixelFormat = GL_RGB; break; case 4 : glpixelFormat = GL_RGBA; break; default : delete[] imageData; setError("unknown pixelformat"); return NULL; break; } unsigned char* swizzled = pepareBufferForOSG(imageData, bytesPerPixel, xsize, ysize); delete[] imageData; osg::Image* image = new osg::Image(); image->setFileName(fileTypeHint.c_str()); image->setImage(xsize,ysize,1, bytesPerPixel, glpixelFormat, GL_UNSIGNED_BYTE, swizzled, osg::Image::USE_NEW_DELETE ); return image; }
GLuint platformLoadTextureFile(string theFilename, bool generateMipmaps, int *width, int *height) { #ifdef QuickTimeInstalled GLuint textureName; // the "name" by which OpenGL knows the texture unsigned char *pImageBuffer; // the buffer that contains the image data GWorldPtr pGWorld; // a gworld to load the image into int imageDepth; FSSpec fsspecImage; // FSSpec of the image to load #ifdef __APPLE__ CFURLRef imageURL; FSRef imagefsRef; #endif OSStatus err = noErr; // err return value long rowStride; // length, in bytes, of a pixel row in the image GraphicsImportComponent giComp; // component for importing image MatrixRecord matrix; Rect rectImage; // rectangle of source image PixMapHandle hPixMap; // handle to image pix map ImageDescriptionHandle hImageDesc; // handle to image description used to get image depth long imageWidth; long imageHeight; float imageAspect; long textureWidth; long textureHeight; // get the full path to the texture file string fileLocation; fileLocation = pathToResourceDirectory() + theFilename; #ifdef __APPLE__ // create a URL to the file from the C string imageURL = CFURLCreateWithBytes (kCFAllocatorDefault, (UInt8 *)fileLocation.c_str(), fileLocation.length(), kCFStringEncodingASCII, NULL); if (imageURL == NULL) { cout << "error getting URL for image file (image file may not exist): " << theFilename << endl; return 0; } // get a FSRef from the URL if (!CFURLGetFSRef(imageURL, &imagefsRef)) { cout << "error getting FSRef for image file:: " << theFilename << endl; CFRelease(imageURL); return 0; } // get the FSSpec from the FSRef if (FSGetCatalogInfo (&imagefsRef, kFSCatInfoNone, NULL, NULL, &fsspecImage, NULL)) { cout << "error getting FSSpec for image file: " << theFilename << endl; CFRelease(imageURL); return 0; } // release the URL (not needed any more) CFRelease(imageURL); #endif #ifdef _WIN32 // get an FSSpec from the pathname if (NativePathNameToFSSpec ((char *)fileLocation.c_str(), &fsspecImage, kErrorIfFileNotFound)) { cout << "error getting FSSpec for image file: " << fileLocation << endl; return 0; } #endif // save the onscreen graphics port GDHandle origDevice; CGrafPtr origPort; GetGWorld (&origPort, &origDevice); // get an importer for the file err = GetGraphicsImporterForFileWithFlags (&fsspecImage, &giComp, kDontUseValidateToFindGraphicsImporter); if (err != noErr) return 0; // get the image bounds err = GraphicsImportGetNaturalBounds (giComp, &rectImage); if (err != noErr) return 0; // create a handle for the image description and lock it hImageDesc = (ImageDescriptionHandle) NewHandle (sizeof (ImageDescriptionHandle)); HLock ((Handle) hImageDesc); // retrieve the image description err = GraphicsImportGetImageDescription (giComp, &hImageDesc); if (err != noErr) return 0; // find width and height imageWidth = (int) (rectImage.right - rectImage.left); imageHeight = (int) (rectImage.bottom - rectImage.top); // now calculate the aspect ratio (width/height), used to restore image correctly imageAspect = ((float) imageWidth) / ((float) imageHeight); // get the image's pixel depth imageDepth = (**hImageDesc).depth; // find nearest acceptable texture size (width and height) for the image textureWidth = GetTextureDimFromImageDim (imageWidth); textureHeight = GetTextureDimFromImageDim (imageHeight); // pass the optimised (and scaled) size back out to the caller *width = textureWidth; *height = textureHeight; // set texture rectangle for creation of GWorld #ifdef __APPLE__ SetRect (&rectImage, 0, 0, (int) textureWidth, (int) textureHeight); #endif #ifdef _WIN32 MacSetRect (&rectImage, 0, 0, (int) textureWidth, (int) textureHeight); #endif // set stride in bytes width of image * 4 bytes per pixel rowStride = textureWidth * 4; // build new buffer exact size of image (stride * height) pImageBuffer = (unsigned char *) NewPtr (rowStride * textureHeight); // check we got the buffer we wanted if (pImageBuffer == NULL) { // failed - release the component and return an error CloseComponent(giComp); return 0; } // create a new gworld using our unpadded buffer, setting the pixel type correctly for the expected image depth #ifdef __BIG_ENDIAN__ QTNewGWorldFromPtr (&(pGWorld), k32ARGBPixelFormat, &rectImage, NULL, NULL, 0, pImageBuffer, rowStride); #else QTNewGWorldFromPtr (&(pGWorld), k32RGBAPixelFormat, &rectImage, NULL, NULL, 0, pImageBuffer, rowStride); #endif // could we allocate the GWorld? if (pGWorld == NULL) { // failed - release the buffer, component and return an error DisposePtr ((Ptr) pImageBuffer); CloseComponent(giComp); return 0; } // build a transformation matrix to scale the image to the texture size // this also flips the image horizontally, so that texture coordinates map correctly float horizontalScale = (float) textureWidth / (float) imageWidth; float verticalScale = (float) textureHeight / (float) imageHeight; SetIdentityMatrix (&matrix); ScaleMatrix (&matrix, X2Fix(horizontalScale), X2Fix(-verticalScale), 0, 0); TranslateMatrix (&matrix, 0, X2Fix((float)textureHeight)); // set the matrix as the importer matrix err = GraphicsImportSetMatrix(giComp, &matrix); // set the destination of the importer component if (err == noErr) err = GraphicsImportSetGWorld (giComp, pGWorld, NULL); // ensure lossless decompression (if the CODEC supports this) if (err == noErr) err = GraphicsImportSetQuality(giComp, codecLosslessQuality); if (err != noErr) { // failed - release the GWorld, buffer, component and return an error DisposeGWorld (pGWorld); DisposePtr ((Ptr) pImageBuffer); CloseComponent(giComp); return 0; } // get the address of the GWorld's pixmap hPixMap = GetGWorldPixMap (pGWorld); // if everything looks good draw the image to the locked pixmap if ((hPixMap) && (LockPixels (hPixMap))) GraphicsImportDraw (giComp); else { // the pixmap doesn't exist, or we couldn't lock it // release the GWorld, buffer, component and return an error DisposeGWorld (pGWorld); DisposePtr ((Ptr) pImageBuffer); CloseComponent(giComp); return 0; } // for images without an alpha channel, initialise the alpha bytes since QuickTime won't if (imageDepth < 32) { #ifdef __BIG_ENDIAN__ for( unsigned char *p = pImageBuffer; p < pImageBuffer + (rowStride * textureHeight); p+=4) *p = 0xFF; #else for( unsigned char *p = pImageBuffer+3; p < pImageBuffer + (rowStride * textureHeight) +3; p+=4) *p = 0xFF; #endif } // unlock the pixmap UnlockPixels (hPixMap); // dump the component CloseComponent(giComp); // set image width in groups (pixels), accounts for border this ensures proper image alignment row to row glPixelStorei (GL_UNPACK_ROW_LENGTH, textureWidth); // generate a "name" for the texture glGenTextures (1, &textureName); // create the texture in OpenGL glBindTexture(GL_TEXTURE_2D, textureName); // tell OpenGL about the texture and have GLU build mipmaps #ifdef __BIG_ENDIAN__ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pImageBuffer); #else glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pImageBuffer); #endif if (generateMipmaps) #ifdef __BIG_ENDIAN__ if (gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureWidth, textureHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pImageBuffer) != 0) #else if (gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE, pImageBuffer) != 0) #endif // good time to check for errors? openGLCheckError(); // finished with the GWorld but not the image buffer (it's used by OpenGL as the "live" image buffer) DisposeGWorld (pGWorld); // restore the current graphics port we saved earlier SetGWorld(origPort, origDevice); // all done - return the texture name return textureName; #endif // QuickTimeInstalled }
//============================================================================= // QutTexture_CreateGWorldFromFile : Create a GWorld from a file. //----------------------------------------------------------------------------- GWorldPtr QutTexture_CreateGWorldFromFile(const FSSpec *theFSSpec, TQ3PixelType pixelType) { CTabHandle colourTableHnd; ImageDescriptionHandle imageDescHnd; ComponentInstance theImporter; GWorldPtr theGWorld; TQ3Uns32 theDepth; Rect theRect; OSErr theErr; // Initialise ourselves theImporter = NULL; theGWorld = NULL; imageDescHnd = NULL; colourTableHnd = NULL; theDepth = (pixelType == kQ3PixelTypeARGB16 || pixelType == kQ3PixelTypeRGB16) ? 16 : 32; // Create the importer theErr = GetGraphicsImporterForFile(theFSSpec, &theImporter); // Query the importer for the information we need if (theErr == noErr) { GraphicsImportGetBoundsRect(theImporter, &theRect); theErr = GraphicsImportGetImageDescription(theImporter, &imageDescHnd); if (theErr == noErr) theErr = GetImageDescriptionCTable(imageDescHnd, &colourTableHnd); } // Create the GWorld if (theErr == noErr) theErr = NewGWorld(&theGWorld, theDepth, &theRect, colourTableHnd, NULL, useTempMem | kQ3NativeEndianPixMap ); // Draw the image into the GWorld if (theErr == noErr) { GraphicsImportSetGWorld(theImporter, theGWorld, NULL); GraphicsImportDraw(theImporter); } // Clean up if (theImporter != NULL) CloseComponent(theImporter); if (imageDescHnd != NULL) DisposeHandle((Handle) imageDescHnd); if (colourTableHnd != NULL) DisposeCTable(colourTableHnd); return(theGWorld); }
GWorldPtr OpenImage (void) { unsigned long rowStride; GraphicsImportComponent giComp; NavReplyRecord replyNav; NavTypeListHandle hTypeList = (NavTypeListHandle) NewHandleClear (sizeof (NavTypeList) + sizeof (OSType) * 13); FSSpec fsspecImage; AEKeyword theKeyword; DescType actualType; Size actualSize; OSStatus err = noErr; Rect rectImage; GDHandle origDevice; CGrafPtr origPort; PixMapHandle hPixMap; ImageDescriptionHandle hImageDesc; MatrixRecord matrix; GWorldPtr pGWorld; unsigned char * pImageBuffer; long imageWidth; long imageHeight; float imageAspect; long imageDepth; long textureWidth; long textureHeight; GetGWorld (&origPort, &origDevice); // save onscreen graphics port HLock ((Handle) hTypeList); (**hTypeList).osTypeCount = 14; (**hTypeList).osType[0] = 'qtif'; (**hTypeList).osType[1] = 'SGI '; (**hTypeList).osType[2] = '8BPS'; (**hTypeList).osType[3] = 'GIF '; (**hTypeList).osType[4] = 'GIFf'; (**hTypeList).osType[5] = 'JPEG'; (**hTypeList).osType[6] = 'JPG '; (**hTypeList).osType[7] = 'PICT'; (**hTypeList).osType[8] = 'PNTG'; (**hTypeList).osType[9] = 'grip'; (**hTypeList).osType[10] = 'BMPp'; (**hTypeList).osType[11] = 'TIFF'; (**hTypeList).osType[12] = 'TEXT'; (**hTypeList).osType[13] = '????'; err = NavChooseFile (NULL, &replyNav, NULL, NULL, NULL, NULL, hTypeList, NULL); if ((err == noErr) && (replyNav.validRecord)) err = AEGetNthPtr (&(replyNav.selection), 1, typeFSS, &theKeyword, &actualType, &fsspecImage, sizeof (fsspecImage), &actualSize); NavDisposeReply (&replyNav); if (err != noErr) return NULL; GetGraphicsImporterForFile (&fsspecImage, &giComp); if (err != noErr) return NULL; // create GWorld err = GraphicsImportGetNaturalBounds (giComp, &rectImage); if (err != noErr) return NULL; hImageDesc = (ImageDescriptionHandle) NewHandle (sizeof (ImageDescriptionHandle)); HLock ((Handle) hImageDesc); err = GraphicsImportGetImageDescription (giComp, &hImageDesc); if (err != noErr) return NULL; imageWidth = rectImage.right - rectImage.left; imageHeight = rectImage.bottom - rectImage.top; imageAspect = ((float) imageWidth) / ((float) imageHeight); imageDepth = (**hImageDesc).depth; // bits if (imageDepth <= 16) imageDepth = 16; else imageDepth = 32; #if 1 textureWidth = imageWidth;//40;//imageWidth;//256; textureHeight = imageHeight;//40 * imageHeight / imageWidth;//imageHeight;//256; #else textureWidth = imageWidth;//256; textureHeight = imageHeight;//256; #endif SetRect (&rectImage, 0, 0, textureWidth, textureHeight); // l, t, r. b reset to texture rectangle rowStride = textureWidth * imageDepth / 8; pImageBuffer = (unsigned char *) NewPtrClear (rowStride * (textureHeight)); if (imageDepth == 32) QTNewGWorldFromPtr (&(pGWorld), k32ARGBPixelFormat, &rectImage, NULL, NULL, 0, pImageBuffer, rowStride); else QTNewGWorldFromPtr (&(pGWorld), k16BE555PixelFormat, &rectImage, NULL, NULL, 0, pImageBuffer, rowStride); if (NULL == pGWorld) return NULL; // decompress to gworld SetIdentityMatrix (&matrix); ScaleMatrix (&matrix, X2Fix ((float) textureWidth / (float) imageWidth), X2Fix ((float) textureHeight / (float) imageHeight), X2Fix (0.0), X2Fix (0.0)); err = GraphicsImportSetMatrix(giComp, &matrix); if (err != noErr) return NULL; err = GraphicsImportSetGWorld (giComp, pGWorld, NULL); if (err != noErr) return NULL; err = GraphicsImportSetQuality(giComp, codecLosslessQuality); if (err != noErr) return NULL; hPixMap = GetGWorldPixMap (pGWorld); if ((hPixMap) && (LockPixels (hPixMap))) // lock offscreen pixel map GraphicsImportDraw (giComp); else return NULL; // modify alpha if ( imageDepth == 32 ) { unsigned long i; unsigned long * pixel = (unsigned long *)GetPixBaseAddr( hPixMap ); for (i = 0; i < textureWidth * textureHeight; i++) { if ((*pixel & 0x00FFFFFF) == 0x00FF00) // mask only color bits and look for green *pixel = 0x00000000;//0x00303040; // replace green with dark gray transparent (to help filtering) else *pixel |= 0xFF000000; // ensure alpha is set for opaque pixels pixel++; } } else { unsigned short i; unsigned short * pixel = (unsigned short *)GetPixBaseAddr( hPixMap ); for (i = 0; i < textureWidth * textureHeight; i++) { if ((*pixel & 0x7FFF) == 0x03E0) // mask only color bits and look for green *pixel = 0x0000;//0x0363; // replace green with dark gray transparent (to help filtering) else *pixel |= 0x8000; // ensure alpha is set for opaque pixels pixel++; } } return pGWorld; }
bool LoadTexture(IplTexture *tex, const char *filename, const char *subdir) { ComponentInstance fileImporter; OSErr error; ImageDescriptionHandle imageInfo; ComponentResult err; CFStringRef name = CFStringCreateWithCStringNoCopy(NULL, filename, kCFStringEncodingASCII, NULL); CFStringRef _subdir = CFStringCreateWithCStringNoCopy(NULL, subdir, kCFStringEncodingASCII, NULL); CFURLRef texture_url = CFBundleCopyResourceURL( CFBundleGetMainBundle(), name, NULL, _subdir); // Create the data reference so we can get the file's graphics importer. Handle dataRef; OSType dataRefType; dataRef = NewHandle(sizeof(AliasHandle)); // The second parameter to QTNewDataReferenceFromCFURL is flags. // It should be set to 0. error = QTNewDataReferenceFromCFURL(texture_url, 0, &dataRef, &dataRefType); if(error != noErr) { //DisposeHandle(dataRef); //CFRelease(texture_url); return false; } // Get the importer for the file so we can read the information. error = GetGraphicsImporterForDataRef(dataRef, dataRefType, &fileImporter); // Retrieve information about the image imageInfo = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription)); err = GraphicsImportGetImageDescription(fileImporter, &imageInfo); unsigned width = ((**imageInfo).width); unsigned height = ((**imageInfo).height); IplImage *im = tex->getIm(); if (im && (im->width != width || im->height!=height)) cvReleaseImage(&im); if (im==0) { im = cvCreateImage(cvSize(width,height), IPL_DEPTH_8U, 4); //memset(im->imageData, 0x8f, 30*im->widthStep ); //memset(im->imageData+ 50*im->widthStep, 0xff, 30*im->widthStep); tex->setImage(im); //return true; } tex->update(); void *imageData = im->imageData; // Get the boundary rectangle of the image Rect imageRect; err = GraphicsImportGetNaturalBounds(fileImporter, &imageRect); // Create an offscreen buffer to hold the image. // Apparently QuickTime requires a GWorld to // decompress a texture file. long bytesPerRow = im->widthStep; //static GWorldPtr offscreenBuffer=0; if (offscreenBuffer==0) { error = QTNewGWorldFromPtr(&offscreenBuffer, k32RGBAPixelFormat, &imageRect, NULL, NULL, kNativeEndianPixMap, imageData, bytesPerRow); assert(error == noErr); } // Draw the image into the offscreen buffer err = GraphicsImportSetGWorld(fileImporter, offscreenBuffer, NULL); assert(err == noErr); err = GraphicsImportDraw(fileImporter); assert(err == noErr); // Cleanup error = CloseComponent(fileImporter); DisposeHandle((Handle)imageInfo); DisposeHandle(dataRef); DisposeGWorld(offscreenBuffer); return true; }