//----------------------------------------------------------------------------- // // ImageLib Sources // Copyright (C) 2000-2009 by Denton Woods // Last modified: 02/26/2009 // // Filename: src-IL/src/il_dpx.c // // Description: Reads from a Digital Picture Exchange (.dpx) file. // Specifications for this format were found at // http://www.cineon.com/ff_draft.php and // http://www.fileformat.info/format/dpx/. // //----------------------------------------------------------------------------- #include "il_internal.h" #ifndef IL_NO_DPX #include "il_dpx.h" #include "il_bits.h" ILboolean iLoadDpxInternal(void); //! Reads a DPX file ILboolean ilLoadDpx(ILconst_string FileName) { ILHANDLE DpxFile; ILboolean bDpx = IL_FALSE; DpxFile = iopenr(FileName); if (DpxFile == NULL) { ilSetError(IL_COULD_NOT_OPEN_FILE); return bDpx; } bDpx = ilLoadDpxF(DpxFile); icloser(DpxFile); return bDpx; } //! Reads an already-opened DPX file ILboolean ilLoadDpxF(ILHANDLE File) { ILuint FirstPos; ILboolean bRet; iSetInputFile(File); FirstPos = itell(); bRet = iLoadDpxInternal(); iseek(FirstPos, IL_SEEK_SET); return bRet; } //! Reads from a memory "lump" that contains a DPX ILboolean ilLoadDpxL(const void *Lump, ILuint Size) { iSetInputLump(Lump, Size); return iLoadDpxInternal(); } ILboolean DpxGetFileInfo(DPX_FILE_INFO *FileInfo) { //if (iread(FileInfo, 768, 1) != 1) // return IL_FALSE; FileInfo->MagicNum = GetBigUInt(); FileInfo->Offset = GetBigUInt(); iread(FileInfo->Vers, 8, 1); FileInfo->FileSize = GetBigUInt(); FileInfo->DittoKey = GetBigUInt(); FileInfo->GenHdrSize = GetBigUInt(); FileInfo->IndHdrSize = GetBigUInt(); FileInfo->UserDataSize = GetBigUInt(); iread(FileInfo->FileName, 100, 1); iread(FileInfo->CreateTime, 24, 1); iread(FileInfo->Creator, 100, 1); iread(FileInfo->Project, 200, 1); if (iread(FileInfo->Copyright, 200, 1) != 1) return IL_FALSE; FileInfo->Key = GetBigUInt(); iseek(104, IL_SEEK_CUR); // Skip reserved section. return IL_TRUE; } ILboolean GetImageElement(DPX_IMAGE_ELEMENT *ImageElement) { ImageElement->DataSign = GetBigUInt(); ImageElement->RefLowData = GetBigUInt(); iread(&ImageElement->RefLowQuantity, 1, 4); ImageElement->RefHighData = GetBigUInt(); iread(&ImageElement->RefHighQuantity, 1, 4); ImageElement->Descriptor = igetc(); ImageElement->Transfer = igetc(); ImageElement->Colorimetric = igetc(); ImageElement->BitSize = igetc(); ImageElement->Packing = GetBigUShort(); ImageElement->Encoding = GetBigUShort(); ImageElement->DataOffset = GetBigUInt(); ImageElement->EolPadding = GetBigUInt(); ImageElement->EoImagePadding = GetBigUInt(); if (iread(ImageElement->Description, 32, 1) != 1) return IL_FALSE; return IL_TRUE; } ILboolean DpxGetImageInfo(DPX_IMAGE_INFO *ImageInfo) { ILuint i; //if (iread(ImageInfo, sizeof(DPX_IMAGE_INFO), 1) != 1) // return IL_FALSE; ImageInfo->Orientation = GetBigUShort(); ImageInfo->NumElements = GetBigUShort(); ImageInfo->Width = GetBigUInt(); ImageInfo->Height = GetBigUInt(); for (i = 0; i < 8; i++) { GetImageElement(&ImageInfo->ImageElement[i]); } iseek(52, IL_SEEK_CUR); // Skip padding bytes. return IL_TRUE; } ILboolean DpxGetImageOrient(DPX_IMAGE_ORIENT *ImageOrient) { ImageOrient->XOffset = GetBigUInt(); ImageOrient->YOffset = GetBigUInt(); iread(&ImageOrient->XCenter, 4, 1); iread(&ImageOrient->YCenter, 4, 1); ImageOrient->XOrigSize = GetBigUInt(); ImageOrient->YOrigSize = GetBigUInt(); iread(ImageOrient->FileName, 100, 1); iread(ImageOrient->CreationTime, 24, 1); iread(ImageOrient->InputDev, 32, 1); if (iread(ImageOrient->InputSerial, 32, 1) != 1) return IL_FALSE; ImageOrient->Border[0] = GetBigUShort(); ImageOrient->Border[1] = GetBigUShort(); ImageOrient->Border[2] = GetBigUShort(); ImageOrient->Border[3] = GetBigUShort(); ImageOrient->PixelAspect[0] = GetBigUInt(); ImageOrient->PixelAspect[1] = GetBigUInt(); iseek(28, IL_SEEK_CUR); // Skip reserved bytes. return IL_TRUE; } // Internal function used to load the DPX. ILboolean iLoadDpxInternal(void) { DPX_FILE_INFO FileInfo; DPX_IMAGE_INFO ImageInfo; DPX_IMAGE_ORIENT ImageOrient; // BITFILE *File; ILuint i, NumElements, CurElem = 0; ILushort Val, *ShortData; ILubyte Data[8]; ILenum Format = 0; ILubyte NumChans = 0; if (iCurImage == NULL) { ilSetError(IL_ILLEGAL_OPERATION); return IL_FALSE; } if (!DpxGetFileInfo(&FileInfo)) return IL_FALSE; if (!DpxGetImageInfo(&ImageInfo)) return IL_FALSE; if (!DpxGetImageOrient(&ImageOrient)) return IL_FALSE; iseek(ImageInfo.ImageElement[CurElem].DataOffset, IL_SEEK_SET); //@TODO: Deal with different origins! switch (ImageInfo.ImageElement[CurElem].Descriptor) { case 6: // Luminance data Format = IL_LUMINANCE; NumChans = 1; break; case 50: // RGB data Format = IL_RGB; NumChans = 3; break; case 51: // RGBA data Format = IL_RGBA; NumChans = 4; break; default: ilSetError(IL_FORMAT_NOT_SUPPORTED); return IL_FALSE; } // These are all on nice word boundaries. switch (ImageInfo.ImageElement[CurElem].BitSize) { case 8: case 16: case 32: if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, NumChans, Format, IL_UNSIGNED_BYTE, NULL)) return IL_FALSE; iCurImage->Origin = IL_ORIGIN_UPPER_LEFT; if (iread(iCurImage->Data, iCurImage->SizeOfData, 1) != 1) return IL_FALSE; goto finish; } // The rest of these do not end on word boundaries. if (ImageInfo.ImageElement[CurElem].Packing == 1) { // Here we have it padded out to a word boundary, so the extra bits are filler. switch (ImageInfo.ImageElement[CurElem].BitSize) { case 10: //@TODO: Support other formats! /*if (Format != IL_RGB) { ilSetError(IL_FORMAT_NOT_SUPPORTED); return IL_FALSE; }*/ switch (Format) { case IL_LUMINANCE: if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_SHORT, NULL)) return IL_FALSE; iCurImage->Origin = IL_ORIGIN_UPPER_LEFT; ShortData = (ILushort*)iCurImage->Data; NumElements = iCurImage->SizeOfData / 2; for (i = 0; i < NumElements;) { iread(Data, 1, 2); Val = ((Data[0] << 2) + ((Data[1] & 0xC0) >> 6)) << 6; // Use the first 10 bits of the word-aligned data. ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits. } break; case IL_RGB: if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 3, IL_RGB, IL_UNSIGNED_SHORT, NULL)) return IL_FALSE; iCurImage->Origin = IL_ORIGIN_UPPER_LEFT; ShortData = (ILushort*)iCurImage->Data; NumElements = iCurImage->SizeOfData / 2; for (i = 0; i < NumElements;) { iread(Data, 1, 4); Val = ((Data[0] << 2) + ((Data[1] & 0xC0) >> 6)) << 6; // Use the first 10 bits of the word-aligned data. ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits. Val = (((Data[1] & 0x3F) << 4) + ((Data[2] & 0xF0) >> 4)) << 6; // Use the next 10 bits. ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Same fill Val = (((Data[2] & 0x0F) << 6) + ((Data[3] & 0xFC) >> 2)) << 6; // And finally use the last 10 bits (ignores the last 2 bits). ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Same fill } break; case IL_RGBA: // Is this even a possibility? There is a ton of wasted space here! if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 4, IL_RGBA, IL_UNSIGNED_SHORT, NULL)) return IL_FALSE; iCurImage->Origin = IL_ORIGIN_UPPER_LEFT; ShortData = (ILushort*)iCurImage->Data; NumElements = iCurImage->SizeOfData / 2; for (i = 0; i < NumElements;) { iread(Data, 1, 8); Val = (Data[0] << 2) + ((Data[1] & 0xC0) >> 6); // Use the first 10 bits of the word-aligned data. ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits. Val = ((Data[1] & 0x3F) << 4) + ((Data[2] & 0xF0) >> 4); // Use the next 10 bits. ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Same fill Val = ((Data[2] & 0x0F) << 6) + ((Data[3] & 0xFC) >> 2); // Use the next 10 bits. ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Same fill Val = ((Data[3] & 0x03) << 8) + Data[4]; // And finally use the last 10 relevant bits (skips 3 whole bytes worth of padding!). ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Last fill } break; } break; //case 1: //case 12: default: ilSetError(IL_FORMAT_NOT_SUPPORTED); return IL_FALSE; } } else if (ImageInfo.ImageElement[0].Packing == 0) { // Here we have the data packed so that it is never aligned on a word boundary. /*File = bfile(iGetFile()); if (File == NULL) return IL_FALSE; //@TODO: Error? ShortData = (ILushort*)iCurImage->Data; NumElements = iCurImage->SizeOfData / 2; for (i = 0; i < NumElements; i++) { //bread(&Val, 1, 10, File); Val = breadVal(10, File); ShortData[i] = (Val << 6) | (Val >> 4); } bclose(File);*/ ilSetError(IL_FORMAT_NOT_SUPPORTED); return IL_FALSE; } else { ilSetError(IL_ILLEGAL_FILE_VALUE); return IL_FALSE; //@TODO: Take care of this in an iCheckDpx* function. } finish: return ilFixImage(); } #endif//IL_NO_DPX