bool DPXInput::open (const std::string &name, ImageSpec &newspec) { // open the image m_stream = new InStream(); if (! m_stream->Open(name.c_str())) { error ("Could not open file \"%s\"", name.c_str()); return false; } m_dpx.SetInStream(m_stream); if (! m_dpx.ReadHeader()) { error ("Could not read header"); return false; } bool ok = seek_subimage (0, 0, newspec); newspec = spec (); return ok; }
OIIO_PLUGIN_EXPORTS_END bool DPXInput::valid_file (const std::string &filename) const { InStream *stream = new InStream(); if (! stream) return false; bool ok = false; if (stream->Open(filename.c_str())) { dpx::Reader dpx; dpx.SetInStream(stream); ok = dpx.ReadHeader(); stream->Close(); } delete stream; return ok; }
int main(int argc, char **argv) { int offset = 1; bool write8bit = false; //bool write8bit = true; if (argc == 4 && strcmp(argv[1], "-8") == 0) { write8bit = true; offset++; } else if (argc != 3) { Usage(); return 1; } // open the image InStream img; if (!img.Open(argv[offset])) { cout << "Unable to open file " << argv[1] << endl; return 1; } dpx::Reader dpx; dpx.SetInStream(&img); if (!dpx.ReadHeader()) { cout << "Unable to read header" << endl; return 2; } TIFF *out; out = TIFFOpen(argv[offset+1], "w"); if (out == NULL) { cout << "Unable to open output file" << endl; return 3; } // data size, override if user specifies dpx::DataSize size = dpx.header.ComponentDataSize(0); int nob = dpx.header.ComponentByteCount(0); if (write8bit) { size = dpx::kByte; nob = 1; } cout << "Image Width " << dpx.header.Width() << " Height " << dpx.header.Height() << " component byte count " << dpx.header.ComponentByteCount(0) << endl; // conversion int format = PHOTOMETRIC_RGB; int elementCount = 3; if (dpx.header.ImageElementComponentCount(0) == 1) { format = PHOTOMETRIC_MINISBLACK; elementCount = 1; } TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) dpx.header.Width()); TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) dpx.header.Height()); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (uint32) nob * 8); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, elementCount); TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE); TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(out, TIFFTAG_PHOTOMETRIC, format); TIFFSetField(out, TIFFTAG_MINSAMPLEVALUE, 0); int max = 0xff; if (nob == 2) max = 0xffff; else max = 0xffffffff; TIFFSetField(out, TIFFTAG_MAXSAMPLEVALUE, max); tdata_t buf = _TIFFmalloc(TIFFScanlineSize(out)); if (buf == NULL) { cout << "memory allocation error" << endl; return 4; } Block block(0, 0, dpx.header.Width()-1, 0); int y; for (y = 0; y < dpx.header.Height(); y++) { block.y1 = y; block.y2 = y; if (dpx.ReadBlock(buf, size, block, dpx.header.ImageDescriptor(0)) == false) { cout << "unable to read line " << y << " with component data size " << size << endl; return 5; } if (TIFFWriteScanline(out, buf, y, 0) < 0) { cout << "unable to write tiff scanline " << y << endl; return 6; } } _TIFFfree(buf); img.Close(); TIFFClose(out); return 0; }
OIIO_PLUGIN_EXPORTS_END bool CineonInput::open (const std::string &name, ImageSpec &newspec) { // open the image m_stream = new InStream(); if (! m_stream->Open(name.c_str())) { error ("Could not open file \"%s\"", name.c_str()); return false; } m_cin.SetInStream(m_stream); if (! m_cin.ReadHeader()) { error ("Could not read header"); return false; } // create imagespec TypeDesc typedesc; int maxbits = 0; for (int i = 0; i < m_cin.header.NumberOfElements (); i++) { if (maxbits < m_cin.header.BitDepth (i)) maxbits = m_cin.header.BitDepth (i); } switch ((maxbits + 7) / 8) { case 1: typedesc = TypeDesc::UINT8; break; case 2: typedesc = TypeDesc::UINT16; break; case 3: case 4: typedesc = TypeDesc::UINT32; break; default: error ("Unsupported bit depth %d", maxbits); return false; } m_spec = ImageSpec (m_cin.header.Width(), m_cin.header.Height(), m_cin.header.NumberOfElements (), typedesc); // fill channel names m_spec.channelnames.clear (); int gscount = 0, rcount = 0, gcount = 0, bcount = 0; char buf[3]; for (int i = 0; i < m_cin.header.NumberOfElements (); i++) { switch (m_cin.header.ImageDescriptor (i)) { case cineon::kGrayscale: if (++gscount > 1) { std::string ch = Strutil::format ("I%d", gscount); m_spec.channelnames.push_back (ch); } else m_spec.channelnames.emplace_back("I"); break; case cineon::kPrintingDensityRed: case cineon::kRec709Red: if (++gscount > 1) { std::string ch = Strutil::format ("R%d", rcount); m_spec.channelnames.push_back (ch); } else m_spec.channelnames.emplace_back("R"); break; case cineon::kPrintingDensityGreen: case cineon::kRec709Green: if (++gcount > 1) { std::string ch = Strutil::format ("G%d", gcount); m_spec.channelnames.push_back (ch); } else m_spec.channelnames.emplace_back("G"); break; case cineon::kPrintingDensityBlue: case cineon::kRec709Blue: if (++bcount > 1) { std::string ch = Strutil::format ("B%d", bcount); m_spec.channelnames.push_back (ch); } else m_spec.channelnames.emplace_back("B"); break; default: std::string ch = Strutil::format ("channel%d", (int)m_spec.channelnames.size()); m_spec.channelnames.push_back (ch); break; } } // bits per sample m_spec.attribute ("oiio:BitsPerSample", maxbits); // image orientation - see appendix B.2 of the OIIO documentation int orientation; switch (m_cin.header.ImageOrientation ()) { case cineon::kLeftToRightTopToBottom: orientation = 1; break; case cineon::kRightToLeftTopToBottom: orientation = 2; break; case cineon::kLeftToRightBottomToTop: orientation = 4; break; case cineon::kRightToLeftBottomToTop: orientation = 3; break; case cineon::kTopToBottomLeftToRight: orientation = 5; break; case cineon::kTopToBottomRightToLeft: orientation = 6; break; case cineon::kBottomToTopLeftToRight: orientation = 8; break; case cineon::kBottomToTopRightToLeft: orientation = 7; break; default: orientation = 0; break; } m_spec.attribute ("Orientation", orientation); #if 1 // This is not very smart, but it seems that as a practical matter, // all Cineon files are log. So ignore the gamma field and just set // the color space to KodakLog. m_spec.attribute ("oiio:ColorSpace", "KodakLog"); #else // image linearity // FIXME: making this more robust would require the per-channel transfer // function functionality which isn't yet in OIIO switch (m_cin.header.ImageDescriptor (0)) { case cineon::kRec709Red: case cineon::kRec709Green: case cineon::kRec709Blue: m_spec.attribute ("oiio:ColorSpace", "Rec709"); default: // either grayscale or printing density if (!isinf (m_cin.header.Gamma ()) && m_cin.header.Gamma () != 0.0f) // actual gamma value is read later on m_spec.attribute ("oiio:ColorSpace", Strutil::format("GammaCorrected%.2g", g)); break; } // gamma exponent if (!isinf (m_cin.header.Gamma ()) && m_cin.header.Gamma () != 0.0f) m_spec.attribute ("oiio:Gamma", (float) m_cin.header.Gamma ()); #endif // general metadata // some non-compliant writers will dump a field filled with 0xFF rather // than a NULL string termination on the first character, so take that // into account, too if (m_cin.header.creationDate[0] && m_cin.header.creationTime[0]) { // libcineon's date/time format is pretty close to OIIO's (libcineon // uses %Y:%m:%d:%H:%M:%S%Z) m_spec.attribute ("DateTime", Strutil::format ("%s %s", m_cin.header.creationDate, m_cin.header.creationTime)); // FIXME: do something about the time zone } // cineon-specific metadata char *strings[8]; int ints[8]; float floats[8]; // image descriptor for (int i = 0; i < m_cin.header.NumberOfElements (); i++) strings[i] = get_descriptor_string (m_cin.header.ImageDescriptor (i)); m_spec.attribute ("cineon:ImageDescriptor", TypeDesc (TypeDesc::STRING, m_cin.header.NumberOfElements ()), &strings); // save some typing by using macros // "internal" macros // per-file attribs #define CINEON_SET_ATTRIB_S(x, n, s) m_spec.attribute (s, \ m_cin.header.x (n)) #define CINEON_SET_ATTRIB(x, n) CINEON_SET_ATTRIB_S(x, n, \ "cineon:" #x) #define CINEON_SET_ATTRIB_BYTE(x) if (m_cin.header.x () != 0xFF) \ CINEON_SET_ATTRIB(x, ) #define CINEON_SET_ATTRIB_INT(x) if (static_cast<unsigned int> \ (m_cin.header.x ()) \ != 0xFFFFFFFF) \ CINEON_SET_ATTRIB(x, ) #define CINEON_SET_ATTRIB_FLOAT(x) if (! isinf(m_cin.header.x ())) \ CINEON_SET_ATTRIB(x, ) #define CINEON_SET_ATTRIB_COORDS(x) m_cin.header.x (floats); \ if (!isinf (floats[0]) \ && !isinf (floats[1]) \ && !(floats[0] == 0. && floats[1] == 0.)) \ m_spec.attribute ("cineon:" #x, \ TypeDesc (TypeDesc::FLOAT, 2), \ &floats[0]) #define CINEON_SET_ATTRIB_STR(X, x) if (m_cin.header.x[0] \ && m_cin.header.x[0] != char(-1)) \ m_spec.attribute ("cineon:" #X, \ m_cin.header.x) // per-element attribs #define CINEON_SET_ATTRIB_N(x, a, t, c) for (int i = 0; i < m_cin.header. \ NumberOfElements (); i++) { \ c(x) \ a[i] = m_cin.header.x (i); \ } \ m_spec.attribute ("cineon:" #x, \ TypeDesc (TypeDesc::t, \ m_cin.header.NumberOfElements()),\ &a) #define CINEON_CHECK_ATTRIB_FLOAT(x) if (!isinf (m_cin.header.x (i))) #define CINEON_SET_ATTRIB_FLOAT_N(x) CINEON_SET_ATTRIB_N(x, floats, \ FLOAT, CINEON_CHECK_ATTRIB_FLOAT) #define CINEON_CHECK_ATTRIB_INT(x) if (m_cin.header.x (i) != 0xFFFFFFFF) #define CINEON_SET_ATTRIB_INT_N(x) CINEON_SET_ATTRIB_N(x, ints, \ UINT32, CINEON_CHECK_ATTRIB_INT) #define CINEON_CHECK_ATTRIB_BYTE(x) if (m_cin.header.x (i) != 0xFF) #define CINEON_SET_ATTRIB_BYTE_N(x) CINEON_SET_ATTRIB_N(x, ints, \ UINT32, CINEON_CHECK_ATTRIB_BYTE) CINEON_SET_ATTRIB_STR(Version, version); // per-element data CINEON_SET_ATTRIB_BYTE_N(Metric); CINEON_SET_ATTRIB_BYTE_N(BitDepth); CINEON_SET_ATTRIB_INT_N(PixelsPerLine); CINEON_SET_ATTRIB_INT_N(LinesPerElement); CINEON_SET_ATTRIB_FLOAT_N(LowData); CINEON_SET_ATTRIB_FLOAT_N(LowQuantity); CINEON_SET_ATTRIB_FLOAT_N(HighData); CINEON_SET_ATTRIB_FLOAT_N(HighQuantity); CINEON_SET_ATTRIB_COORDS(WhitePoint); CINEON_SET_ATTRIB_COORDS(RedPrimary); CINEON_SET_ATTRIB_COORDS(GreenPrimary); CINEON_SET_ATTRIB_COORDS(BluePrimary); CINEON_SET_ATTRIB_STR(LabelText, labelText); CINEON_SET_ATTRIB_INT(XOffset); CINEON_SET_ATTRIB_INT(YOffset); CINEON_SET_ATTRIB_STR(SourceImageFileName, sourceImageFileName); CINEON_SET_ATTRIB_STR(InputDevice, inputDevice); CINEON_SET_ATTRIB_STR(InputDeviceModelNumber, inputDeviceModelNumber); CINEON_SET_ATTRIB_STR(InputDeviceSerialNumber, inputDeviceSerialNumber); CINEON_SET_ATTRIB_FLOAT(XDevicePitch); CINEON_SET_ATTRIB_FLOAT(YDevicePitch); CINEON_SET_ATTRIB_INT(FramePosition); CINEON_SET_ATTRIB_FLOAT(FrameRate); CINEON_SET_ATTRIB_STR(Format, format); CINEON_SET_ATTRIB_STR(FrameId, frameId); CINEON_SET_ATTRIB_STR(SlateInfo, slateInfo); #undef CINEON_SET_ATTRIB_BYTE_N #undef CINEON_CHECK_ATTRIB_BYTE #undef CINEON_SET_ATTRIB_INT_N #undef CINEON_CHECK_ATTRIB_INT #undef CINEON_SET_ATTRIB_FLOAT_N #undef CINEON_CHECK_ATTRIB_FLOAT #undef CINEON_SET_ATTRIB_N #undef CINEON_SET_ATTRIB_STR #undef CINEON_SET_ATTRIB_COORDS #undef CINEON_SET_ATTRIB_FLOAT #undef CINEON_SET_ATTRIB_INT #undef CINEON_SET_ATTRIB #undef CINEON_SET_ATTRIB_S std::string tmpstr; switch (m_cin.header.ImagePacking () & ~cineon::kPackAsManyAsPossible) { case cineon::kPacked: tmpstr = "Packed"; break; case cineon::kByteLeft: tmpstr = "8-bit boundary, left justified"; break; case cineon::kByteRight: tmpstr = "8-bit boundary, right justified"; break; case cineon::kWordLeft: tmpstr = "16-bit boundary, left justified"; break; case cineon::kWordRight: tmpstr = "16-bit boundary, right justified"; break; case cineon::kLongWordLeft: tmpstr = "32-bit boundary, left justified"; break; case cineon::kLongWordRight: tmpstr = "32-bit boundary, right justified"; break; } if (m_cin.header.ImagePacking () & cineon::kPackAsManyAsPossible) tmpstr += ", as many fields as possible per cell"; else tmpstr += ", at most one pixel per cell"; if (!tmpstr.empty ()) m_spec.attribute ("cineon:Packing", tmpstr); if (m_cin.header.sourceDate[0] && m_cin.header.sourceTime[0]) { // libcineon's date/time format is pretty close to OIIO's (libcineon // uses %Y:%m:%d:%H:%M:%S%Z) m_spec.attribute ("DateTime", Strutil::format ("%s %s", m_cin.header.sourceDate, m_cin.header.sourceTime)); // FIXME: do something about the time zone } m_cin.header.FilmEdgeCode(buf); if (buf[0]) m_spec.attribute ("cineon:FilmEdgeCode", buf); // read in user data if (m_cin.header.UserSize () != 0 && m_cin.header.UserSize () != 0xFFFFFFFF) { m_userBuf.resize (m_cin.header.UserSize ()); m_cin.ReadUserData (&m_userBuf[0]); } if (!m_userBuf.empty ()) m_spec.attribute ("cineon:UserData", TypeDesc (TypeDesc::UCHAR, m_cin.header.UserSize ()), &m_userBuf[0]); newspec = spec (); return true; }