void WriteHdrImage(const std::string outName, const int width, const int height, Color* image) { // Turn image from a 2D-bottom-up array of Vector3D to an top-down-array of floats float* data = new float[width*height * 3]; float* dp = data; for (int y = height - 1; y >= 0; --y) { for (int x = 0; x<width; ++x) { Color pixel = image[y*width + x]; *dp++ = pixel[0]; *dp++ = pixel[1]; *dp++ = pixel[2]; } } // Write image to file in HDR (a.k.a RADIANCE) format rgbe_header_info info; char errbuf[100] = { 0 }; FILE* fp = fopen(outName.c_str(), "wb"); info.valid = false; int r = RGBE_WriteHeader(fp, width, height, &info, errbuf); if (r != RGBE_RETURN_SUCCESS) printf("error: %s\n", errbuf); r = RGBE_WritePixels_RLE(fp, data, width, height, errbuf); if (r != RGBE_RETURN_SUCCESS) printf("error: %s\n", errbuf); fclose(fp); delete data; }
bool writeHDR(const char* path, const cv::Mat& hdr) { FILE* fp = std::fopen(path, "wb"); if (fp == NULL) { std::fprintf(stderr, "cannot write to %s\n", path); return false; } cv::Size size = hdr.size(); cv::Mat tmp = hdr.clone(); for (int y = 0; y < size.height; ++y) { for (int x = 0; x < size.width; ++x) { cv::Vec3f& c = tmp.at<cv::Vec3f>(y, x); std::swap(c[0], c[2]); } } float* data = (float*)((void*)(tmp.ptr())); RGBE_WriteHeader(fp, size.width, size.height, NULL); RGBE_WritePixels_RLE(fp, data, size.width, size.height); std::fclose(fp); return true; }
OIIO_PLUGIN_EXPORTS_END bool HdrOutput::open (const std::string &name, const ImageSpec &newspec, OpenMode mode) { if (mode != Create) { error ("%s does not support subimages or MIP levels", format_name()); return false; } // Save spec for later use m_spec = newspec; // HDR always behaves like floating point m_spec.set_format (TypeDesc::FLOAT); // Check for things HDR can't support if (m_spec.nchannels != 3) { error ("HDR can only support 3-channel images"); return false; } 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; if (m_spec.depth > 1) { error ("%s does not support volume images (depth > 1)", format_name()); return false; } m_spec.set_format (TypeDesc::FLOAT); // Native rgbe is float32 only m_fd = Filesystem::fopen (name, "wb"); if (m_fd == NULL) { error ("Unable to open file"); return false; } rgbe_header_info h; h.valid = 0; // Most readers seem to think that rgbe files are valid only if they // identify themselves as from "RADIANCE". h.valid |= RGBE_VALID_PROGRAMTYPE; Strutil::safe_strcpy (h.programtype, "RADIANCE", sizeof(h.programtype)); ParamValue *p; p = m_spec.find_attribute ("Orientation", TypeDesc::INT); if (p) { h.valid |= RGBE_VALID_ORIENTATION; h.orientation = * (int *)p->data(); } // FIXME -- should we do anything about gamma, exposure, software, // pixaspect, primaries? (N.B. rgbe.c doesn't even handle most of them) int r = RGBE_WriteHeader (m_fd, m_spec.width, m_spec.height, &h, rgbe_error); if (r != RGBE_RETURN_SUCCESS) error ("%s", rgbe_error); // 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 true; }
// Internal function used to save the Hdr. ILboolean iSaveHdrInternal() { ILimage *TempImage; rgbe_header_info stHeader; unsigned char rgbe[4]; ILubyte *buffer; ILfloat *data; ILuint i; ILboolean bRet; if (iCurImage == NULL) { ilSetError(IL_ILLEGAL_OPERATION); return IL_FALSE; } stHeader.exposure = 0; stHeader.gamma = 0; stHeader.programtype[0] = 0; stHeader.valid = 0; if (iCurImage->Format != IL_UNSIGNED_BYTE) { TempImage = iConvertImage(iCurImage, IL_RGB, IL_FLOAT); if (TempImage == NULL) return IL_FALSE; } else TempImage = iCurImage; if (!RGBE_WriteHeader(TempImage->Width, TempImage->Height, &stHeader)) return IL_FALSE; if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT) iFlipBuffer(TempImage->Data,TempImage->Depth,TempImage->Bps,TempImage->Height); data = (ILfloat*)TempImage->Data; if ((TempImage->Width < 8)||(TempImage->Width > 0x7fff)) { /* run length encoding is not allowed so write flat*/ bRet = RGBE_WritePixels(data,TempImage->Width*TempImage->Height); if (iCurImage != TempImage) ilCloseImage(TempImage); return bRet; } buffer = (ILubyte*)ialloc(sizeof(ILubyte)*4*TempImage->Width); if (buffer == NULL) { /* no buffer space so write flat */ bRet = RGBE_WritePixels(data,TempImage->Width*TempImage->Height); if (iCurImage != TempImage) ilCloseImage(TempImage); return bRet; } while(TempImage->Height-- > 0) { rgbe[0] = 2; rgbe[1] = 2; rgbe[2] = TempImage->Width >> 8; rgbe[3] = TempImage->Width & 0xFF; if (iwrite(rgbe, sizeof(rgbe), 1) < 1) { free(buffer); if (iCurImage != TempImage) ilCloseImage(TempImage); return IL_FALSE; } for(i=0;i<TempImage->Width;i++) { float2rgbe(rgbe,data[RGBE_DATA_RED],data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]); buffer[i] = rgbe[0]; buffer[i+TempImage->Width] = rgbe[1]; buffer[i+2*TempImage->Width] = rgbe[2]; buffer[i+3*TempImage->Width] = rgbe[3]; data += RGBE_DATA_SIZE; } /* write out each of the four channels separately run length encoded */ /* first red, then green, then blue, then exponent */ for(i=0;i<4;i++) { if (RGBE_WriteBytes_RLE(&buffer[i*TempImage->Width],TempImage->Width) != IL_TRUE) { ifree(buffer); if (iCurImage != TempImage) ilCloseImage(TempImage); return IL_FALSE; } } } ifree(buffer); if (iCurImage != TempImage) ilCloseImage(TempImage); return IL_TRUE; }