bool PNGOutput::write_scanline(int y, int z, TypeDesc format, const void* data, stride_t xstride) { y -= m_spec.y; m_spec.auto_stride(xstride, format, spec().nchannels); const void* origdata = data; data = to_native_scanline(format, data, xstride, m_scratch, m_dither, y, z); if (data == origdata) { m_scratch.assign((unsigned char*)data, (unsigned char*)data + m_spec.scanline_bytes()); data = &m_scratch[0]; } // PNG specifically dictates unassociated (un-"premultiplied") alpha if (m_convert_alpha) { if (m_spec.format == TypeDesc::UINT16) deassociateAlpha((unsigned short*)data, m_spec.width, m_spec.nchannels, m_spec.alpha_channel, m_gamma); else deassociateAlpha((unsigned char*)data, m_spec.width, m_spec.nchannels, m_spec.alpha_channel, m_gamma); } // PNG is always big endian if (littleendian() && m_spec.format == TypeDesc::UINT16) swap_endian((unsigned short*)data, m_spec.width * m_spec.nchannels); if (!PNG_pvt::write_row(m_png, (png_byte*)data)) { error("PNG library error"); return false; } return true; }
bool SgiInput::read_header() { if (!fread(&m_sgi_header.magic, sizeof(m_sgi_header.magic), 1) || !fread(&m_sgi_header.storage, sizeof(m_sgi_header.storage), 1) || !fread(&m_sgi_header.bpc, sizeof(m_sgi_header.bpc), 1) || !fread(&m_sgi_header.dimension, sizeof(m_sgi_header.dimension), 1) || !fread(&m_sgi_header.xsize, sizeof(m_sgi_header.xsize), 1) || !fread(&m_sgi_header.ysize, sizeof(m_sgi_header.ysize), 1) || !fread(&m_sgi_header.zsize, sizeof(m_sgi_header.zsize), 1) || !fread(&m_sgi_header.pixmin, sizeof(m_sgi_header.pixmin), 1) || !fread(&m_sgi_header.pixmax, sizeof(m_sgi_header.pixmax), 1) || !fread(&m_sgi_header.dummy, sizeof(m_sgi_header.dummy), 1) || !fread(&m_sgi_header.imagename, sizeof(m_sgi_header.imagename), 1)) return false; m_sgi_header.imagename[79] = '\0'; if (! fread(&m_sgi_header.colormap, sizeof(m_sgi_header.colormap), 1)) return false; //don't read dummy bytes fseek (m_fd, 404, SEEK_CUR); if (littleendian()) { swap_endian(&m_sgi_header.magic); swap_endian(&m_sgi_header.dimension); swap_endian(&m_sgi_header.xsize); swap_endian(&m_sgi_header.ysize); swap_endian(&m_sgi_header.zsize); swap_endian(&m_sgi_header.pixmin); swap_endian(&m_sgi_header.pixmax); swap_endian(&m_sgi_header.colormap); } return true; }
bool SgiOutput::create_and_write_header() { sgi_pvt::SgiHeader sgi_header; sgi_header.magic = sgi_pvt::SGI_MAGIC; sgi_header.storage = sgi_pvt::VERBATIM; sgi_header.bpc = m_spec.format.size(); if (m_spec.height == 1 && m_spec.nchannels == 1) sgi_header.dimension = sgi_pvt::ONE_SCANLINE_ONE_CHANNEL; else if (m_spec.nchannels == 1) sgi_header.dimension = sgi_pvt::MULTI_SCANLINE_ONE_CHANNEL; else sgi_header.dimension = sgi_pvt::MULTI_SCANLINE_MULTI_CHANNEL; sgi_header.xsize = m_spec.width; sgi_header.ysize = m_spec.height; sgi_header.zsize = m_spec.nchannels; sgi_header.pixmin = 0; sgi_header.pixmax = (sgi_header.bpc == 1) ? 255 : 65535; sgi_header.dummy = 0; ParamValue* ip = m_spec.find_attribute("ImageDescription", TypeDesc::STRING); if (ip && ip->data()) { const char** img_descr = (const char**)ip->data(); strncpy(sgi_header.imagename, *img_descr, 80); sgi_header.imagename[79] = 0; } sgi_header.colormap = sgi_pvt::NORMAL; if (littleendian()) { swap_endian(&sgi_header.magic); swap_endian(&sgi_header.dimension); swap_endian(&sgi_header.xsize); swap_endian(&sgi_header.ysize); swap_endian(&sgi_header.zsize); swap_endian(&sgi_header.pixmin); swap_endian(&sgi_header.pixmax); swap_endian(&sgi_header.colormap); } char dummy[404] = { 0 }; if (!fwrite(&sgi_header.magic) || !fwrite(&sgi_header.storage) || !fwrite(&sgi_header.bpc) || !fwrite(&sgi_header.dimension) || !fwrite(&sgi_header.xsize) || !fwrite(&sgi_header.ysize) || !fwrite(&sgi_header.zsize) || !fwrite(&sgi_header.pixmin) || !fwrite(&sgi_header.pixmax) || !fwrite(&sgi_header.dummy) || !fwrite(sgi_header.imagename, 1, 80) || !fwrite(&sgi_header.colormap) || !fwrite(dummy, 404, 1)) { error("Error writing to \"%s\"", m_filename); return false; } return true; }
bool PicFileHeader::read_header (FILE* fd) { int byte_count = 0; byte_count += fread (this, 1, sizeof (PicFileHeader), fd); // Check if we're running on a little endian processor if (littleendian ()) swap_endian(); return (byte_count == sizeof (PicFileHeader)); }
bool SgiInput::read_native_scanline (int y, int z, void *data) { if (y < 0 || y > m_spec.height) return false; y = m_spec.height - y - 1; int bpc = m_sgi_header.bpc; std::vector<std::vector<unsigned char> > channeldata (m_spec.nchannels); if (m_sgi_header.storage == sgi_pvt::RLE) { // reading and uncompressing first channel (red in RGBA images) for (int c = 0; c < m_spec.nchannels; ++c) { int off = y + c*m_spec.height; // offset for this scanline/channel int scanline_offset = start_tab[off]; int scanline_length = length_tab[off]; channeldata[c].resize (m_spec.width * bpc); uncompress_rle_channel (scanline_offset, scanline_length, &(channeldata[c][0])); } } else { // non-RLE case -- just read directly into our channel data for (int c = 0; c < m_spec.nchannels; ++c) { int off = y + c*m_spec.height; // offset for this scanline/channel int scanline_offset = sgi_pvt::SGI_HEADER_LEN + off * m_spec.width * bpc; fseek (m_fd, scanline_offset, SEEK_SET); channeldata[c].resize (m_spec.width * bpc); if (! fread (&(channeldata[c][0]), 1, m_spec.width * bpc)) return false; } } if (m_spec.nchannels == 1) { // If just one channel, no interleaving is necessary, just memcpy memcpy (data, &(channeldata[0][0]), channeldata[0].size()); } else { unsigned char *cdata = (unsigned char *)data; for (int x = 0; x < m_spec.width; ++x) { for (int c = 0; c < m_spec.nchannels; ++c) { *cdata++ = channeldata[c][x*bpc]; if (bpc == 2) *cdata++ = channeldata[c][x*bpc+1]; } } } // Swap endianness if needed if (bpc == 2 && littleendian()) swap_endian ((unsigned short *)data, m_spec.width*m_spec.nchannels); return true; }
bool SgiInput::read_offset_tables () { int tables_size = m_sgi_header.ysize * m_sgi_header.zsize; start_tab.resize(tables_size); length_tab.resize(tables_size); if (!fread (&start_tab[0], sizeof(uint32_t), tables_size) || !fread (&length_tab[0], sizeof(uint32_t), tables_size)) return false; if (littleendian ()) { swap_endian (&length_tab[0], length_tab.size ()); swap_endian (&start_tab[0], start_tab.size()); } return true; }
bool TIFFInput::valid_file (const std::string &filename) const { FILE *file = Filesystem::fopen (filename, "r"); if (! file) return false; // needs to be able to open unsigned short magic[2] = { 0, 0 }; fread (magic, sizeof(unsigned short), 2, file); fclose (file); if (magic[0] != TIFF_LITTLEENDIAN && magic[0] != TIFF_BIGENDIAN) return false; // not the right byte order if ((magic[0] == TIFF_LITTLEENDIAN) != littleendian()) swap_endian (&magic[1], 1); return (magic[1] == 42 /* Classic TIFF */ || magic[1] == 43 /* Big TIFF */); }
bool FitsInput::read_native_scanline (int y, int z, void *data) { // we return true just to support 0x0 images if (!m_naxes) return true; std::vector<unsigned char> data_tmp (m_spec.scanline_bytes ()); long scanline_off = (m_spec.height - y) * m_spec.scanline_bytes (); fseek (m_fd, scanline_off, SEEK_CUR); size_t n = fread (&data_tmp[0], 1, m_spec.scanline_bytes(), m_fd); if (n != m_spec.scanline_bytes()) { if (feof (m_fd)) error ("Hit end of file unexpectedly"); else error ("read error"); return false; // Read failed } // in FITS image data is stored in big-endian so we have to switch to // little-endian on little-endian machines if (littleendian ()) { if (m_spec.format == TypeDesc::USHORT) swap_endian ((unsigned short*)&data_tmp[0], data_tmp.size () / sizeof (unsigned short)); else if (m_spec.format == TypeDesc::UINT) swap_endian ((unsigned int*)&data_tmp[0], data_tmp.size () / sizeof (unsigned int)); else if (m_spec.format == TypeDesc::FLOAT) swap_endian ((float*)&data_tmp[0], data_tmp.size () / sizeof (float)); else if (m_spec.format == TypeDesc::DOUBLE) swap_endian ((double*)&data_tmp[0], data_tmp.size () / sizeof (double)); } memcpy (data, &data_tmp[0], data_tmp.size ()); // after reading scanline we set file pointer to the start of image data fsetpos (m_fd, &m_filepos); return true; };
bool SgiOutput::write_scanline (int y, int z, TypeDesc format, const void *data, stride_t xstride) { y = m_spec.height - y - 1; data = to_native_scanline (format, data, xstride, m_scratch, m_dither, y, z); // In SGI format all channels are saved to file separately: firsty all // channel 1 scanlines are saved, then all channel2 scanlines are saved // and so on. // // Note that since SGI images are pretty archaic and most probably // people won't be too picky about full flexibility writing them, we // content ourselves with only writing uncompressed data, and don't // attempt to write with RLE encoding. int bpc = m_spec.format.size(); // bytes per channel std::vector<unsigned char> channeldata (m_spec.width * bpc); for (int c = 0; c < m_spec.nchannels; ++c) { unsigned char *cdata = (unsigned char *)data + c*bpc; for (int x = 0; x < m_spec.width; ++x) { channeldata[x*bpc] = cdata[0]; if (bpc == 2) channeldata[x*bpc+1] = cdata[1]; cdata += m_spec.nchannels * bpc; // advance to next pixel } if (bpc == 2 && littleendian()) swap_endian ((unsigned short *)&channeldata[0], m_spec.width); long scanline_offset = sgi_pvt::SGI_HEADER_LEN + (c * m_spec.height + y) * m_spec.width * bpc; fseek (m_fd, scanline_offset, SEEK_SET); if (!fwrite (&channeldata[0], 1, m_spec.width * bpc)) { return false; } } return true; }
static void convert_pack_bits (T *data, int nvals) { const int BITS_FROM = sizeof(T)*8; T *in = data; T *out = in - 1; // because we'll increment first time through int bitstofill = 0; // Invariant: the next value to convert is *in. We're going to write // the result of the conversion starting at *out, which still has // bitstofill bits left before moving on to the next slot. for (int i = 0; i < nvals; ++i) { // Grab the next value and convert it T val = bit_range_convert<BITS_FROM,BITS_TO> (*in++); // If we have no more bits to fill in the slot, move on to the // next slot. if (bitstofill == 0) { ++out; *out = 0; // move to next slot and clear its bits bitstofill = BITS_FROM; // all bits are for the taking } if (bitstofill >= BITS_TO) { // we can fit the whole val in this slot *out |= val << (bitstofill - BITS_TO); bitstofill -= BITS_TO; // printf ("\t\t%d bits left\n", bitstofill); } else { // not enough bits -- will need to split across slots int bitsinnext = BITS_TO - bitstofill; *out |= val >> bitsinnext; val &= (1 << bitsinnext) - 1; // mask out bits we saved ++out; *out = 0; // move to next slot and clear its bits *out |= val << (BITS_FROM - bitsinnext); bitstofill = BITS_FROM - bitsinnext; } } // Because we filled in a big-endian way, swap bytes if we need to if (littleendian()) swap_endian (data, nvals); }
int savebmp(char *filename, unsigned char *buf, int w, int h, enum BMPPIXELFORMAT f, int srcpitch, int srcbottomup) { int fd=-1, byteswritten, dstpitch, retcode=0; int flags=O_RDWR|O_CREAT|O_TRUNC; unsigned char *tempbuf=NULL; char *temp; bmphdr bh; int mode; #ifdef _WIN32 flags|=O_BINARY; mode=_S_IREAD|_S_IWRITE; #else mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; #endif if(!filename || !buf || w<1 || h<1 || f<0 || f>BMPPIXELFORMATS-1 || srcpitch<0) _throw("bad argument to savebmp()"); if(srcpitch==0) srcpitch=w*ps[f]; if((temp=strrchr(filename, '.'))!=NULL) { if(!stricmp(temp, ".ppm")) return saveppm(filename, buf, w, h, f, srcpitch, srcbottomup); } _unix(fd=open(filename, flags, mode)); dstpitch=((w*3)+3)&(~3); bh.bfType=0x4d42; bh.bfSize=BMPHDRSIZE+dstpitch*h; bh.bfReserved1=0; bh.bfReserved2=0; bh.bfOffBits=BMPHDRSIZE; bh.biSize=40; bh.biWidth=w; bh.biHeight=h; bh.biPlanes=0; bh.biBitCount=24; bh.biCompression=BI_RGB; bh.biSizeImage=0; bh.biXPelsPerMeter=0; bh.biYPelsPerMeter=0; bh.biClrUsed=0; bh.biClrImportant=0; if(!littleendian()) { bh.bfType=byteswap16(bh.bfType); bh.bfSize=byteswap(bh.bfSize); bh.bfOffBits=byteswap(bh.bfOffBits); bh.biSize=byteswap(bh.biSize); bh.biWidth=byteswap(bh.biWidth); bh.biHeight=byteswap(bh.biHeight); bh.biPlanes=byteswap16(bh.biPlanes); bh.biBitCount=byteswap16(bh.biBitCount); bh.biCompression=byteswap(bh.biCompression); bh.biSizeImage=byteswap(bh.biSizeImage); bh.biXPelsPerMeter=byteswap(bh.biXPelsPerMeter); bh.biYPelsPerMeter=byteswap(bh.biYPelsPerMeter); bh.biClrUsed=byteswap(bh.biClrUsed); bh.biClrImportant=byteswap(bh.biClrImportant); } writeme(fd, &bh.bfType, sizeof(unsigned short)); writeme(fd, &bh.bfSize, sizeof(unsigned int)); writeme(fd, &bh.bfReserved1, sizeof(unsigned short)); writeme(fd, &bh.bfReserved2, sizeof(unsigned short)); writeme(fd, &bh.bfOffBits, sizeof(unsigned int)); writeme(fd, &bh.biSize, sizeof(unsigned int)); writeme(fd, &bh.biWidth, sizeof(int)); writeme(fd, &bh.biHeight, sizeof(int)); writeme(fd, &bh.biPlanes, sizeof(unsigned short)); writeme(fd, &bh.biBitCount, sizeof(unsigned short)); writeme(fd, &bh.biCompression, sizeof(unsigned int)); writeme(fd, &bh.biSizeImage, sizeof(unsigned int)); writeme(fd, &bh.biXPelsPerMeter, sizeof(int)); writeme(fd, &bh.biYPelsPerMeter, sizeof(int)); writeme(fd, &bh.biClrUsed, sizeof(unsigned int)); writeme(fd, &bh.biClrImportant, sizeof(unsigned int)); if((tempbuf=(unsigned char *)malloc(dstpitch*h))==NULL) _throw("Memory allocation error"); pixelconvert(buf, f, srcpitch, tempbuf, BMP_BGR, dstpitch, w, h, !srcbottomup); if((byteswritten=write(fd, tempbuf, dstpitch*h))!=dstpitch*h) _throw(strerror(errno)); finally: if(tempbuf) free(tempbuf); if(fd!=-1) close(fd); return retcode; }
int loadbmp(char *filename, unsigned char **buf, int *w, int *h, enum BMPPIXELFORMAT f, int align, int dstbottomup) { int fd=-1, bytesread, srcpitch, srcbottomup=1, srcps, dstpitch, retcode=0; unsigned char *tempbuf=NULL; bmphdr bh; int flags=O_RDONLY; dstbottomup=dstbottomup? 1:0; #ifdef _WIN32 flags|=O_BINARY; #endif if(!filename || !buf || !w || !h || f<0 || f>BMPPIXELFORMATS-1 || align<1) _throw("invalid argument to loadbmp()"); if((align&(align-1))!=0) _throw("Alignment must be a power of 2"); _unix(fd=open(filename, flags)); readme(fd, &bh.bfType, sizeof(unsigned short)); if(!littleendian()) bh.bfType=byteswap16(bh.bfType); if(bh.bfType==0x3650) { _catch(loadppm(&fd, buf, w, h, f, align, dstbottomup, 0)); goto finally; } if(bh.bfType==0x3350) { _catch(loadppm(&fd, buf, w, h, f, align, dstbottomup, 1)); goto finally; } readme(fd, &bh.bfSize, sizeof(unsigned int)); readme(fd, &bh.bfReserved1, sizeof(unsigned short)); readme(fd, &bh.bfReserved2, sizeof(unsigned short)); readme(fd, &bh.bfOffBits, sizeof(unsigned int)); readme(fd, &bh.biSize, sizeof(unsigned int)); readme(fd, &bh.biWidth, sizeof(int)); readme(fd, &bh.biHeight, sizeof(int)); readme(fd, &bh.biPlanes, sizeof(unsigned short)); readme(fd, &bh.biBitCount, sizeof(unsigned short)); readme(fd, &bh.biCompression, sizeof(unsigned int)); readme(fd, &bh.biSizeImage, sizeof(unsigned int)); readme(fd, &bh.biXPelsPerMeter, sizeof(int)); readme(fd, &bh.biYPelsPerMeter, sizeof(int)); readme(fd, &bh.biClrUsed, sizeof(unsigned int)); readme(fd, &bh.biClrImportant, sizeof(unsigned int)); if(!littleendian()) { bh.bfSize=byteswap(bh.bfSize); bh.bfOffBits=byteswap(bh.bfOffBits); bh.biSize=byteswap(bh.biSize); bh.biWidth=byteswap(bh.biWidth); bh.biHeight=byteswap(bh.biHeight); bh.biPlanes=byteswap16(bh.biPlanes); bh.biBitCount=byteswap16(bh.biBitCount); bh.biCompression=byteswap(bh.biCompression); bh.biSizeImage=byteswap(bh.biSizeImage); bh.biXPelsPerMeter=byteswap(bh.biXPelsPerMeter); bh.biYPelsPerMeter=byteswap(bh.biYPelsPerMeter); bh.biClrUsed=byteswap(bh.biClrUsed); bh.biClrImportant=byteswap(bh.biClrImportant); } if(bh.bfType!=0x4d42 || bh.bfOffBits<BMPHDRSIZE || bh.biWidth<1 || bh.biHeight==0) _throw("Corrupt bitmap header"); if((bh.biBitCount!=24 && bh.biBitCount!=32) || bh.biCompression!=BI_RGB) _throw("Only uncompessed RGB bitmaps are supported"); *w=bh.biWidth; *h=bh.biHeight; srcps=bh.biBitCount/8; if(*h<0) {*h=-(*h); srcbottomup=0;} srcpitch=(((*w)*srcps)+3)&(~3); dstpitch=(((*w)*ps[f])+(align-1))&(~(align-1)); if(srcpitch*(*h)+bh.bfOffBits!=bh.bfSize) _throw("Corrupt bitmap header"); if((tempbuf=(unsigned char *)malloc(srcpitch*(*h)))==NULL || (*buf=(unsigned char *)malloc(dstpitch*(*h)))==NULL) _throw("Memory allocation error"); if(lseek(fd, (long)bh.bfOffBits, SEEK_SET)!=(long)bh.bfOffBits) _throw(strerror(errno)); _unix(bytesread=read(fd, tempbuf, srcpitch*(*h))); if(bytesread!=srcpitch*(*h)) _throw("Read error"); pixelconvert(tempbuf, BMP_BGR, srcpitch, *buf, f, dstpitch, *w, *h, srcbottomup!=dstbottomup); finally: if(tempbuf) free(tempbuf); if(fd!=-1) close(fd); return retcode; }
int main(int argc,char * argv[]) { int b1,b2,b3 = 0; FILE * fi = stdin; if(argc > 1) { fi = fopen(argv[1],"rb"); } if(argc > 2) { type = argv[2]; char * valid[] = {"LE" ,"BE" ,"UCS-2" ,"UCS-2-LE" ,"UCS-2-BE" ,"BIN" ,"UTF-16" ,"UTF-16-LE" ,"UTF-16-BE" ,"ASCII" ,"ISO" ,"UTF-8" ,"UTF-8-BOM" }; int i; for(i = sizeof(valid)/sizeof(valid[0]);--i >= 0;) if(!strcmp(type,valid[i])) break; if(i < 0) { printf("second argument must be one of:\n"); for(i = 0;i < sizeof(valid)/sizeof(valid[0]);++i) printf("%s\n",valid[i]); return 1; } } if(!fi) { printf("Cannot open input %s\n",argv[1]); return 1; } makeDuples(); b1 = fgetc(fi); b2 = fgetc(fi); if(b1 == 0xff && b2 == 0xfe) { if(type[0]) { le = true; if(!strcmp(type,"LE")) result = 1; } else { printf("Byte order: little endian\n"); } littleendian(fi); } else if(b1 == 0xfe && b2 == 0xff) { bigendian(fi,true); } else if(b1 == 0 || b2 == 0) // No BOM, but still looks like UTF-16 { // assume big endian surrogate((b1 << 8) + b2); bigendian(fi,false); } else { FILE * ftempInput = tmpfile(); b3 = fgetc(fi); if(b3 == 0)// No BOM, but still looks like UTF-16 { // assume big endian surrogate((b1 << 8) + b2); surrogate((b3 << 8) + fgetc(fi)); bigendian(fi,false); } else { if(b1 == 0xEF && b2 == 0xBB && b3 == 0xBF) // BOM found, probably UTF8 { ;// remove BOM } else { fputc(b1,ftempInput); fputc(b2,ftempInput); fputc(b3,ftempInput); b1 = b2 = b3 = 0; } int k; bool zeroFound = false; while((k = fgetc(fi)) != EOF) { if(k == 0) zeroFound = true; fputc(k,ftempInput); } rewind(ftempInput); if(zeroFound) { if(b1 && b2 && b3) { surrogate((b1 << 8) + b2); surrogate((b3 << 8) + fgetc(ftempInput)); } bigendian(ftempInput,false); } else { bool bom = false; if(b1 && b2 && b3) { if(type[0]) { bom = true; } else printf("BOM found, but not UTF-16. (UTF-8 file created in Windows?)\n"); } if(UTF8(ftempInput)) { utf8 = true; if(ascii) { if(type[0]) { if( !bom && (!strcmp(type,"ASCII") || !strcmp(type,"ISO")) || !strcmp(type,"UTF-8") || bom && !strcmp(type,"UTF-8-BOM") ) result = 1; } else { printf("encoding: ASCII (subset of UTF-8 and all ISO-8859 encodings)\n"); } } else { if(type[0]) { if(!strcmp(type,"UTF-8") || bom && !strcmp(type,"UTF-8-BOM")) result = 1; } else { printf("encoding: UTF-8\n"); } } } else { int c = 0; while((k = fgetc(ftempInput)) != EOF) getbyte(k); if(type[0]) { if(!bom && (!strcmp(type,"ASCII") || !strcmp(type,"ISO"))) result = 1; } else { printf("encoding: 8-bits\n"); } } } } } if(fi != stdin) fclose(fi); if(!type[0]) fprintf(stderr,"%s",report()); if(!utf8 && ascii) if(!type[0]) printf("File could have been encoded in ASCII!\n"); deleteDuples(); if(type[0]) { printf("[%d]\t%s\n",result,argv[1]); } return 0; }
bool DPXOutput::open (const std::string &name, const ImageSpec &userspec, OpenMode mode) { close (); // Close any already-opened file if (mode != Create) { error ("%s does not support subimages or MIP levels", format_name()); return false; } m_spec = userspec; // Stash the spec // open the image m_stream = new OutStream(); if (! m_stream->Open(name.c_str ())) { error ("Could not open file \"%s\"", name.c_str ()); return false; } // Check for things this format doesn't support if (m_spec.width < 1 || m_spec.height < 1) { error ("Image resolution must be at least 1x1, you asked for %d x %d", m_spec.width, m_spec.height); return false; } if (m_spec.depth < 1) m_spec.depth = 1; else if (m_spec.depth > 1) { error ("DPX does not support volume images (depth > 1)"); return false; } if (m_spec.format == TypeDesc::UINT8 || m_spec.format == TypeDesc::INT8) m_datasize = dpx::kByte; else if (m_spec.format == TypeDesc::UINT16 || m_spec.format == TypeDesc::INT16) m_datasize = dpx::kWord; else if (m_spec.format == TypeDesc::FLOAT || m_spec.format == TypeDesc::HALF) { m_spec.format = TypeDesc::FLOAT; m_datasize = dpx::kFloat; } else if (m_spec.format == TypeDesc::DOUBLE) m_datasize = dpx::kDouble; else { // use 16-bit unsigned integers as a failsafe m_spec.format = TypeDesc::UINT16; m_datasize = dpx::kWord; } // check if the client is giving us raw data to write m_wantRaw = m_spec.get_int_attribute ("dpx:RawData", 0) != 0; // check if the client wants endianness reverse to native // assume big endian per Jeremy's request, unless little endian is // explicitly specified std::string tmpstr = m_spec.get_string_attribute ("oiio:Endian", littleendian() ? "little" : "big"); m_wantSwap = (littleendian() != Strutil::iequals (tmpstr, "little")); m_dpx.SetOutStream (m_stream); // start out the file m_dpx.Start (); // some metadata std::string project = m_spec.get_string_attribute ("DocumentName", ""); std::string copyright = m_spec.get_string_attribute ("Copyright", ""); tmpstr = m_spec.get_string_attribute ("DateTime", ""); if (tmpstr.size () >= 19) { // libdpx's date/time format is pretty close to OIIO's (libdpx uses // %Y:%m:%d:%H:%M:%S%Z) // NOTE: the following code relies on the DateTime attribute being properly // formatted! // assume UTC for simplicity's sake, fix it if someone complains tmpstr[10] = ':'; tmpstr.replace (19, -1, "Z"); } m_dpx.SetFileInfo (name.c_str (), // filename tmpstr.c_str (), // cr. date OIIO_INTRO_STRING, // creator project.empty () ? NULL : project.c_str (), // project copyright.empty () ? NULL : copyright.c_str (), // copyright m_spec.get_int_attribute ("dpx:EncryptKey", ~0), // encryption key m_wantSwap); // image info m_dpx.SetImageInfo (m_spec.width, m_spec.height); // determine descriptor m_desc = get_descriptor_from_string (m_spec.get_string_attribute ("dpx:ImageDescriptor", "")); // transfer function dpx::Characteristic transfer; std::string colorspace = m_spec.get_string_attribute ("oiio:ColorSpace", ""); if (Strutil::iequals (colorspace, "Linear")) transfer = dpx::kLinear; else if (Strutil::iequals (colorspace, "GammaCorrected")) transfer = dpx::kUserDefined; else if (Strutil::iequals (colorspace, "Rec709")) transfer = dpx::kITUR709; else if (Strutil::iequals (colorspace, "KodakLog")) transfer = dpx::kLogarithmic; else { std::string dpxtransfer = m_spec.get_string_attribute ("dpx:Transfer", ""); transfer = get_characteristic_from_string (dpxtransfer); } // colorimetric m_cmetr = get_characteristic_from_string (m_spec.get_string_attribute ("dpx:Colorimetric", "User defined")); // select packing method dpx::Packing packing; tmpstr = m_spec.get_string_attribute ("dpx:Packing", "Filled, method A"); if (Strutil::iequals (tmpstr, "Packed")) packing = dpx::kPacked; else if (Strutil::iequals (tmpstr, "Filled, method B")) packing = dpx::kFilledMethodB; else packing = dpx::kFilledMethodA; // calculate target bit depth int bitDepth = m_spec.format.size () * 8; if (m_spec.format == TypeDesc::UINT16) { bitDepth = m_spec.get_int_attribute ("oiio:BitsPerSample", 16); if (bitDepth != 10 && bitDepth != 12 && bitDepth != 16) { error ("Unsupported bit depth %d", bitDepth); return false; } } m_dpx.header.SetBitDepth (0, bitDepth); // Bug workaround: libDPX doesn't appear to correctly support // "filled method A" for 12 bit data. Does anybody care what // packing/filling we use? Punt and just use "packed". if (bitDepth == 12) packing = dpx::kPacked; // see if we'll need to convert or not if (m_desc == dpx::kRGB || m_desc == dpx::kRGBA) { // shortcut for RGB(A) that gets the job done m_bytes = m_spec.scanline_bytes (); m_wantRaw = true; } else { m_bytes = dpx::QueryNativeBufferSize (m_desc, m_datasize, m_spec.width, 1); if (m_bytes == 0 && !m_wantRaw) { error ("Unable to deliver native format data from source data"); return false; } else if (m_bytes < 0) { // no need to allocate another buffer if (!m_wantRaw) m_bytes = m_spec.scanline_bytes (); else m_bytes = -m_bytes; } } if (m_bytes < 0) m_bytes = -m_bytes; m_dpx.SetElement (0, m_desc, bitDepth, transfer, m_cmetr, packing, dpx::kNone, (m_spec.format == TypeDesc::INT8 || m_spec.format == TypeDesc::INT16) ? 1 : 0, m_spec.get_int_attribute ("dpx:LowData", 0xFFFFFFFF), m_spec.get_float_attribute ("dpx:LowQuantity", std::numeric_limits<float>::quiet_NaN()), m_spec.get_int_attribute ("dpx:HighData", 0xFFFFFFFF), m_spec.get_float_attribute ("dpx:HighQuantity", std::numeric_limits<float>::quiet_NaN()), m_spec.get_int_attribute ("dpx:EndOfLinePadding", 0), m_spec.get_int_attribute ("dpx:EndOfImagePadding", 0)); m_dpx.header.SetXScannedSize (m_spec.get_float_attribute ("dpx:XScannedSize", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetYScannedSize (m_spec.get_float_attribute ("dpx:YScannedSize", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetFramePosition (m_spec.get_int_attribute ("dpx:FramePosition", 0xFFFFFFFF)); m_dpx.header.SetSequenceLength (m_spec.get_int_attribute ("dpx:SequenceLength", 0xFFFFFFFF)); m_dpx.header.SetHeldCount (m_spec.get_int_attribute ("dpx:HeldCount", 0xFFFFFFFF)); m_dpx.header.SetFrameRate (m_spec.get_float_attribute ("dpx:FrameRate", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetShutterAngle (m_spec.get_float_attribute ("dpx:ShutterAngle", std::numeric_limits<float>::quiet_NaN())); // FIXME: should we write the input version through or always default to 2.0? /*tmpstr = m_spec.get_string_attribute ("dpx:Version", ""); if (tmpstr.size () > 0) m_dpx.header.SetVersion (tmpstr.c_str ());*/ tmpstr = m_spec.get_string_attribute ("dpx:Format", ""); if (tmpstr.size () > 0) m_dpx.header.SetFormat (tmpstr.c_str ()); tmpstr = m_spec.get_string_attribute ("dpx:FrameId", ""); if (tmpstr.size () > 0) m_dpx.header.SetFrameId (tmpstr.c_str ()); tmpstr = m_spec.get_string_attribute ("dpx:SlateInfo", ""); if (tmpstr.size () > 0) m_dpx.header.SetSlateInfo (tmpstr.c_str ()); tmpstr = m_spec.get_string_attribute ("dpx:SourceImageFileName", ""); if (tmpstr.size () > 0) m_dpx.header.SetSourceImageFileName (tmpstr.c_str ()); tmpstr = m_spec.get_string_attribute ("dpx:InputDevice", ""); if (tmpstr.size () > 0) m_dpx.header.SetInputDevice (tmpstr.c_str ()); tmpstr = m_spec.get_string_attribute ("dpx:InputDeviceSerialNumber", ""); if (tmpstr.size () > 0) m_dpx.header.SetInputDeviceSerialNumber (tmpstr.c_str ()); m_dpx.header.SetInterlace (m_spec.get_int_attribute ("dpx:Interlace", 0xFF)); m_dpx.header.SetFieldNumber (m_spec.get_int_attribute ("dpx:FieldNumber", 0xFF)); m_dpx.header.SetHorizontalSampleRate (m_spec.get_float_attribute ("dpx:HorizontalSampleRate", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetVerticalSampleRate (m_spec.get_float_attribute ("dpx:VerticalSampleRate", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetTemporalFrameRate (m_spec.get_float_attribute ("dpx:TemporalFrameRate", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetTimeOffset (m_spec.get_float_attribute ("dpx:TimeOffset", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetBlackLevel (m_spec.get_float_attribute ("dpx:BlackLevel", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetBlackGain (m_spec.get_float_attribute ("dpx:BlackGain", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetBreakPoint (m_spec.get_float_attribute ("dpx:BreakPoint", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetWhiteLevel (m_spec.get_float_attribute ("dpx:WhiteLevel", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetIntegrationTimes (m_spec.get_float_attribute ("dpx:IntegrationTimes", std::numeric_limits<float>::quiet_NaN())); float aspect = m_spec.get_float_attribute ("PixelAspectRatio", 1.0f); int aspect_num, aspect_den; float_to_rational (aspect, aspect_num, aspect_den); m_dpx.header.SetAspectRatio (0, aspect_num); m_dpx.header.SetAspectRatio (1, aspect_den); tmpstr = m_spec.get_string_attribute ("dpx:TimeCode", ""); int tmpint = m_spec.get_int_attribute ("dpx:TimeCode", ~0); if (tmpstr.size () > 0) m_dpx.header.SetTimeCode (tmpstr.c_str ()); else if (tmpint != ~0) m_dpx.header.timeCode = tmpint; m_dpx.header.userBits = m_spec.get_int_attribute ("dpx:UserBits", ~0); tmpstr = m_spec.get_string_attribute ("dpx:SourceDateTime", ""); if (tmpstr.size () >= 19) { // libdpx's date/time format is pretty close to OIIO's (libdpx uses // %Y:%m:%d:%H:%M:%S%Z) // NOTE: the following code relies on the DateTime attribute being properly // formatted! // assume UTC for simplicity's sake, fix it if someone complains tmpstr[10] = ':'; tmpstr.replace (19, -1, "Z"); m_dpx.header.SetSourceTimeDate (tmpstr.c_str ()); } // commit! if (!m_dpx.WriteHeader ()) { error ("Failed to write DPX header"); return false; } // user data ImageIOParameter *user = m_spec.find_attribute ("dpx:UserData"); if (user && user->datasize () > 0) { if (user->datasize () > 1024 * 1024) { error ("User data block size exceeds 1 MB"); return false; } // FIXME: write the missing libdpx code /*m_dpx.SetUserData (user->datasize ()); if (!m_dpx.WriteUserData ((void *)user->data ())) { error ("Failed to write user data"); return false; }*/ } // reserve space for the image data buffer m_buf.reserve (m_bytes * m_spec.height); return true; }
int main(int argc,char * argv[]) { int b1,b2,b3 = 0; FILE * fi = stdin; FILE * fo = stdout; if(argc > 1) { fi = fopen(argv[1],"rb"); if(argc > 2) fo = fopen(argv[2],"wb"); } if(!fi || !fo) return 1; makeDuples(); b1 = fgetc(fi); b2 = fgetc(fi); if(b1 == 0xff && b2 == 0xfe) littleendian(fi,fo); else if(b1 == 0xfe && b2 == 0xff) bigendian(fi,fo); else if(b1 == 0 || b2 == 0) // No BOM, but still looks like UTF-16 { // assume big endian surrogate((b1 << 8) + b2,fo); bigendian(fi,fo); } else { FILE * ftempInput = tmpfile(); b3 = fgetc(fi); if(b3 == 0)// No BOM, but still looks like UTF-16 { // assume big endian surrogate((b1 << 8) + b2,fo); surrogate((b3 << 8) + fgetc(fi),fo); bigendian(fi,fo); } else { if(b1 == 0xEF && b2 == 0xBB && b3 == 0xBF) // BOM found, probably UTF8 ; // remove BOM else { fputc(b1,ftempInput); fputc(b2,ftempInput); fputc(b3,ftempInput); b1 = b2 = b3 = 0; } int k; bool zeroFound = false; while((k = fgetc(fi)) != EOF) { if(k == 0) zeroFound = true; fputc(k,ftempInput); } rewind(ftempInput); if(zeroFound) { if(b1 && b2 && b3) { surrogate((b1 << 8) + b2,fo); surrogate((b3 << 8) + fgetc(ftempInput),fo); } bigendian(ftempInput,fo); } else if(!UTF8(ftempInput,fo)) { rewind(ftempInput); if(b1 && b2 && b3) // "BOM" found, but not in UTF8 file! { // write "BOM" fputc(b1,fo); fputc(b2,fo); fputc(b3,fo); } copy(ftempInput,fo); } } } if(fi != stdin) fclose(fi); if(fo != stdout) fclose(fo); fprintf(stderr,"%s",report()); deleteDuples(); return 0; }
bool DPXOutput::open (const std::string &name, const ImageSpec &userspec, OpenMode mode) { if (mode == Create) { m_subimage = 0; if (m_subimage_specs.size() < 1) { m_subimage_specs.resize (1); m_subimage_specs[0] = userspec; m_subimages_to_write = 1; } } else if (mode == AppendSubimage) { if (m_write_pending) write_buffer (); ++m_subimage; if (m_subimage >= m_subimages_to_write) { error ("Exceeded the pre-declared number of subimages (%d)", m_subimages_to_write); return false; } return prep_subimage (m_subimage, true); // Nothing else to do, the header taken care of when we opened with // Create. } else if (mode == AppendMIPLevel) { error ("DPX does not support MIP-maps"); return false; } // From here out, all the heavy lifting is done for Create ASSERT (mode == Create); if (is_opened()) close (); // Close any already-opened file m_stream = new OutStream(); if (! m_stream->Open(name.c_str ())) { error ("Could not open file \"%s\"", name.c_str ()); return false; } m_dpx.SetOutStream (m_stream); m_dpx.Start (); m_subimage = 0; ImageSpec &m_spec (m_subimage_specs[m_subimage]); // alias the spec // Check for things this format doesn't support if (m_spec.width < 1 || m_spec.height < 1) { error ("Image resolution must be at least 1x1, you asked for %d x %d", m_spec.width, m_spec.height); return false; } if (m_spec.depth < 1) m_spec.depth = 1; else if (m_spec.depth > 1) { error ("DPX does not support volume images (depth > 1)"); return false; } // some metadata std::string software = m_spec.get_string_attribute ("Software", ""); std::string project = m_spec.get_string_attribute ("DocumentName", ""); std::string copyright = m_spec.get_string_attribute ("Copyright", ""); std::string datestr = m_spec.get_string_attribute ("DateTime", ""); if (datestr.size () >= 19) { // libdpx's date/time format is pretty close to OIIO's (libdpx uses // %Y:%m:%d:%H:%M:%S%Z) // NOTE: the following code relies on the DateTime attribute being properly // formatted! // assume UTC for simplicity's sake, fix it if someone complains datestr[10] = ':'; datestr.replace (19, -1, "Z"); } // check if the client wants endianness reverse to native // assume big endian per Jeremy's request, unless little endian is // explicitly specified std::string endian = m_spec.get_string_attribute ("oiio:Endian", littleendian() ? "little" : "big"); m_wantSwap = (littleendian() != Strutil::iequals (endian, "little")); m_dpx.SetFileInfo (name.c_str (), // filename datestr.c_str (), // cr. date software.empty () ? OIIO_INTRO_STRING : software.c_str (), // creator project.empty () ? NULL : project.c_str (), // project copyright.empty () ? NULL : copyright.c_str (), // copyright m_spec.get_int_attribute ("dpx:EncryptKey", ~0), // encryption key m_wantSwap); // image info m_dpx.SetImageInfo (m_spec.width, m_spec.height); for (int s = 0; s < m_subimages_to_write; ++s) { prep_subimage (s, false); m_dpx.header.SetBitDepth (s, m_bitdepth); ImageSpec &spec (m_subimage_specs[s]); bool datasign = (spec.format == TypeDesc::INT8 || spec.format == TypeDesc::INT16); m_dpx.SetElement (s, m_desc, m_bitdepth, m_transfer, m_cmetr, m_packing, dpx::kNone, datasign, spec.get_int_attribute ("dpx:LowData", 0xFFFFFFFF), spec.get_float_attribute ("dpx:LowQuantity", std::numeric_limits<float>::quiet_NaN()), spec.get_int_attribute ("dpx:HighData", 0xFFFFFFFF), spec.get_float_attribute ("dpx:HighQuantity", std::numeric_limits<float>::quiet_NaN()), spec.get_int_attribute ("dpx:EndOfLinePadding", 0), spec.get_int_attribute ("dpx:EndOfImagePadding", 0)); std::string desc = spec.get_string_attribute ("ImageDescription", ""); m_dpx.header.SetDescription (s, desc.c_str()); } m_dpx.header.SetXScannedSize (m_spec.get_float_attribute ("dpx:XScannedSize", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetYScannedSize (m_spec.get_float_attribute ("dpx:YScannedSize", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetFramePosition (m_spec.get_int_attribute ("dpx:FramePosition", 0xFFFFFFFF)); m_dpx.header.SetSequenceLength (m_spec.get_int_attribute ("dpx:SequenceLength", 0xFFFFFFFF)); m_dpx.header.SetHeldCount (m_spec.get_int_attribute ("dpx:HeldCount", 0xFFFFFFFF)); m_dpx.header.SetFrameRate (m_spec.get_float_attribute ("dpx:FrameRate", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetShutterAngle (m_spec.get_float_attribute ("dpx:ShutterAngle", std::numeric_limits<float>::quiet_NaN())); // FIXME: should we write the input version through or always default to 2.0? /*tmpstr = m_spec.get_string_attribute ("dpx:Version", ""); if (tmpstr.size () > 0) m_dpx.header.SetVersion (tmpstr.c_str ());*/ std::string tmpstr; tmpstr = m_spec.get_string_attribute ("dpx:FrameId", ""); if (tmpstr.size () > 0) m_dpx.header.SetFrameId (tmpstr.c_str ()); tmpstr = m_spec.get_string_attribute ("dpx:SlateInfo", ""); if (tmpstr.size () > 0) m_dpx.header.SetSlateInfo (tmpstr.c_str ()); tmpstr = m_spec.get_string_attribute ("dpx:SourceImageFileName", ""); if (tmpstr.size () > 0) m_dpx.header.SetSourceImageFileName (tmpstr.c_str ()); tmpstr = m_spec.get_string_attribute ("dpx:InputDevice", ""); if (tmpstr.size () > 0) m_dpx.header.SetInputDevice (tmpstr.c_str ()); tmpstr = m_spec.get_string_attribute ("dpx:InputDeviceSerialNumber", ""); if (tmpstr.size () > 0) m_dpx.header.SetInputDeviceSerialNumber (tmpstr.c_str ()); m_dpx.header.SetInterlace (m_spec.get_int_attribute ("dpx:Interlace", 0xFF)); m_dpx.header.SetFieldNumber (m_spec.get_int_attribute ("dpx:FieldNumber", 0xFF)); m_dpx.header.SetHorizontalSampleRate (m_spec.get_float_attribute ("dpx:HorizontalSampleRate", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetVerticalSampleRate (m_spec.get_float_attribute ("dpx:VerticalSampleRate", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetTemporalFrameRate (m_spec.get_float_attribute ("dpx:TemporalFrameRate", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetTimeOffset (m_spec.get_float_attribute ("dpx:TimeOffset", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetBlackLevel (m_spec.get_float_attribute ("dpx:BlackLevel", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetBlackGain (m_spec.get_float_attribute ("dpx:BlackGain", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetBreakPoint (m_spec.get_float_attribute ("dpx:BreakPoint", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetWhiteLevel (m_spec.get_float_attribute ("dpx:WhiteLevel", std::numeric_limits<float>::quiet_NaN())); m_dpx.header.SetIntegrationTimes (m_spec.get_float_attribute ("dpx:IntegrationTimes", std::numeric_limits<float>::quiet_NaN())); float aspect = m_spec.get_float_attribute ("PixelAspectRatio", 1.0f); int aspect_num, aspect_den; float_to_rational (aspect, aspect_num, aspect_den); m_dpx.header.SetAspectRatio (0, aspect_num); m_dpx.header.SetAspectRatio (1, aspect_den); m_dpx.header.SetXOffset ((unsigned int)std::max (0, m_spec.x)); m_dpx.header.SetYOffset ((unsigned int)std::max (0, m_spec.y)); m_dpx.header.SetXOriginalSize ((unsigned int)m_spec.full_width); m_dpx.header.SetYOriginalSize ((unsigned int)m_spec.full_height); static int DpxOrientations[] = { 0, dpx::kLeftToRightTopToBottom, dpx::kRightToLeftTopToBottom, dpx::kLeftToRightBottomToTop, dpx::kRightToLeftBottomToTop, dpx::kTopToBottomLeftToRight, dpx::kTopToBottomRightToLeft, dpx::kBottomToTopLeftToRight, dpx::kBottomToTopRightToLeft }; int orient = m_spec.get_int_attribute ("Orientation", 0); orient = DpxOrientations[clamp (orient, 0, 8)]; m_dpx.header.SetImageOrientation ((dpx::Orientation)orient); ImageIOParameter *tc = m_spec.find_attribute("smpte:TimeCode", TypeDesc::TypeTimeCode, false); if (tc) { unsigned int *timecode = (unsigned int*) tc->data(); m_dpx.header.timeCode = timecode[0]; m_dpx.header.userBits = timecode[1]; } else { std::string timecode = m_spec.get_string_attribute ("dpx:TimeCode", ""); int tmpint = m_spec.get_int_attribute ("dpx:TimeCode", ~0); if (timecode.size () > 0) m_dpx.header.SetTimeCode (timecode.c_str ()); else if (tmpint != ~0) m_dpx.header.timeCode = tmpint; m_dpx.header.userBits = m_spec.get_int_attribute ("dpx:UserBits", ~0); } ImageIOParameter *kc = m_spec.find_attribute("smpte:KeyCode", TypeDesc::TypeKeyCode, false); if (kc) { int *array = (int*) kc->data(); set_keycode_values(array); // See if there is an overloaded dpx:Format std::string format = m_spec.get_string_attribute ("dpx:Format", ""); if (format.size () > 0) m_dpx.header.SetFormat (format.c_str ()); } std::string srcdate = m_spec.get_string_attribute ("dpx:SourceDateTime", ""); if (srcdate.size () >= 19) { // libdpx's date/time format is pretty close to OIIO's (libdpx uses // %Y:%m:%d:%H:%M:%S%Z) // NOTE: the following code relies on the DateTime attribute being properly // formatted! // assume UTC for simplicity's sake, fix it if someone complains srcdate[10] = ':'; srcdate.replace (19, -1, "Z"); m_dpx.header.SetSourceTimeDate (srcdate.c_str ()); } // set the user data size ImageIOParameter *user = m_spec.find_attribute ("dpx:UserData"); if (user && user->datasize () > 0 && user->datasize () <= 1024 * 1024) { m_dpx.SetUserData (user->datasize ()); } // commit! if (!m_dpx.WriteHeader ()) { error ("Failed to write DPX header"); return false; } // write the user data if (user && user->datasize () > 0 && user->datasize() <= 1024 * 1024) { if (!m_dpx.WriteUserData ((void *)user->data ())) { error ("Failed to write user data"); return false; } } m_dither = (m_spec.format == TypeDesc::UINT8) ? m_spec.get_int_attribute ("oiio:dither", 0) : 0; // If user asked for tiles -- which this format doesn't support, emulate // it by buffering the whole image. if (m_spec.tile_width && m_spec.tile_height) m_tilebuffer.resize (m_spec.image_bytes()); return prep_subimage (m_subimage, true); }
void RRPlugin::sendvgl(rrdisplayclient *rrdpy, GLint drawbuf, bool spoillast, int compress, int qual, int subsamp, bool block) { #if 0 while(block && !rrdpy->frameready()) { fprintf(stderr, "pause "); fflush(stderr); usleep(100000); } #else (void)block; #endif osgViewer::GraphicsWindow *win = coVRConfig::instance()->windows[0].window; int x, y, w, h; win->getWindowRectangle(x, y, w, h); if (spoillast && fconfig.spoil && !rrdpy->frameready()) return; rrframe *b; int flags = RRBMP_BOTTOMUP, format = GL_RGB; #ifdef GL_BGR_EXT if (littleendian() && compress != RRCOMP_RGB) { format = GL_BGR_EXT; flags |= RRBMP_BGR; } #endif if (m_cudaReadBack && m_cudapinnedmemory) flags |= RRBMP_CUDAALLOC; errifnot(b = rrdpy->getbitmap(w, h, 3, flags, false /*stereo*/, fconfig.spoil)); GLint buf = drawbuf; //b->_h.winid=_win; b->_h.dpynum = 0; b->_h.winid = 0; b->_h.framew = b->_h.width; b->_h.frameh = b->_h.height; b->_h.x = 0; b->_h.y = 0; b->_h.qual = qual; b->_h.subsamp = subsamp; b->_h.compress = (unsigned char)compress; double start = 0.; if (benchmark) start = cover->currentTime(); double bpp = 4.; #ifdef HAVE_CUDA if (m_cudaReadBack) { int hs = tjMCUWidth[jpegsub(subsamp)] / 8; int vs = tjMCUHeight[jpegsub(subsamp)] / 8; if (fconfig.compress == RRCOMP_YUV2JPEG) { m_cudaReadBack->readpixelsyuv(0, 0, b->_h.framew, b->_pitch, b->_h.frameh, format, b->_pixelsize, b->_bits, buf, hs, vs); bpp = 1. + 2. / hs / vs; } else m_cudaReadBack->readpixels(0, 0, b->_h.framew, b->_pitch, b->_h.frameh, format, b->_pixelsize, b->_bits, buf); } else #endif readpixels(0, 0, b->_h.framew, b->_pitch, b->_h.frameh, format, b->_pixelsize, b->_bits, buf); double dur = 0.; if (benchmark) dur = cover->currentTime() - start; double pix = b->_h.framew * b->_h.frameh; double bytes = pix * bpp; if (benchmark) fprintf(stderr, "%fs: %f mpix/s, %f gb/s (cuda=%d, yuv=%d)\n", dur, pix / dur / 1e6, bytes / dur / (1024 * 1024 * 1024), m_cudaReadBack != NULL, fconfig.compress == RRCOMP_YUV2JPEG); //b->_h.winid=_win; b->_h.dpynum = 0; b->_h.winid = 0; b->_h.framew = b->_h.width; b->_h.frameh = b->_h.height; b->_h.x = 0; b->_h.y = 0; b->_h.qual = qual; b->_h.subsamp = subsamp; b->_h.compress = (unsigned char)compress; if (m_sendThread) { m_sendThread->send(rrdpy, b); } else rrdpy->sendframe(b); }
static void exif_parser_cb (ImageSpec* spec, int tag, int tifftype, int len, unsigned int byteorder, LibRaw_abstract_datastream* ifp) { // Oy, the data offsets are all going to be relative to the start of the // stream, not relative to our current position and data block. So we // need to remember that offset and pass its negative as the // offset_adjustment to the handler. size_t streampos = ifp->tell(); // std::cerr << "Stream position " << streampos << "\n"; TypeDesc type = tiff_datatype_to_typedesc (TIFFDataType(tifftype), size_t(len)); const TagInfo* taginfo = tag_lookup ("Exif", tag); if (! taginfo) { // Strutil::fprintf (std::cerr, "NO TAGINFO FOR CALLBACK tag=%d (0x%x): tifftype=%d,len=%d (%s), byteorder=0x%x\n", // tag, tag, tifftype, len, type, byteorder); return; } if (type.size() >= (1<<20)) return; // sanity check -- too much memory size_t size = tiff_data_size(TIFFDataType(tifftype)) * len; std::vector<unsigned char> buf (size); ifp->read (buf.data(), size, 1); // debug scaffolding // Strutil::fprintf (std::cerr, "CALLBACK tag=%s: tifftype=%d,len=%d (%s), byteorder=0x%x\n", // taginfo->name, tifftype, len, type, byteorder); // for (int i = 0; i < std::min(16UL,size); ++i) { // if (buf[i] >= ' ' && buf[i] < 128) // std::cerr << char(buf[i]); // Strutil::fprintf (std::cerr, "(%d) ", int(buf[i])); // } // std::cerr << "\n"; bool swab = (littleendian() != (byteorder == 0x4949)); if (swab) { if (type.basetype == TypeDesc::UINT16) swap_endian ((uint16_t *)buf.data(), len); if (type.basetype == TypeDesc::UINT32) swap_endian ((uint32_t *)buf.data(), len); } if (taginfo->handler) { TIFFDirEntry dir; dir.tdir_tag = uint16_t(tag); dir.tdir_type = uint16_t(tifftype); dir.tdir_count = uint32_t(len); dir.tdir_offset = 0; taginfo->handler (*taginfo, dir, buf, *spec, swab, -int(streampos)); // std::cerr << "HANDLED " << taginfo->name << "\n"; return; } if (taginfo->tifftype == TIFF_NOTYPE) return; // skip if (tifftype == TIFF_RATIONAL || tifftype == TIFF_SRATIONAL) { spec->attribute (taginfo->name, type, buf.data()); return; } if (type.basetype == TypeDesc::UINT16) { spec->attribute (taginfo->name, type, buf.data()); return; } if (type.basetype == TypeDesc::UINT32) { spec->attribute (taginfo->name, type, buf.data()); return; } if (type == TypeString) { spec->attribute (taginfo->name, string_view((char*)buf.data(), size)); return; } // Strutil::fprintf (std::cerr, "RAW metadata NOT HANDLED: tag=%s: tifftype=%d,len=%d (%s), byteorder=0x%x\n", // taginfo->name, tifftype, len, type, byteorder); }