Exemple #1
0
void SaveExr(const Image<unsigned char>& image_in, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first)
{
    PANGOLIN_UNUSED(image_in);
    PANGOLIN_UNUSED(fmt);
    PANGOLIN_UNUSED(filename);
    PANGOLIN_UNUSED(top_line_first);

#ifdef HAVE_OPENEXR
    ManagedImage<unsigned char> flip_image;
    Image<unsigned char> image;

    if(top_line_first) {
        image = image_in;
    }else{
        flip_image.Reinitialise(image_in.pitch,image_in.h);
        for(size_t y=0; y<image_in.h; ++y) {
            std::memcpy(flip_image.RowPtr(y), image_in.RowPtr(y), image_in.pitch);
        }
        image = flip_image;
    }


    Imf::Header header (image.w, image.h);
    SetOpenEXRChannels(header.channels(), fmt);

    Imf::OutputFile file (filename.c_str(), header);
    Imf::FrameBuffer frameBuffer;

    int ch=0;
    size_t ch_bits = 0;
    for(Imf::ChannelList::Iterator it = header.channels().begin(); it != header.channels().end(); ++it)
    {
        frameBuffer.insert(
            it.name(),
            Imf::Slice(
                it.channel().type,
                (char*)image.ptr + ch_bits/8,
                fmt.channel_bits[ch]/8,
                image.pitch
            )
        );

        ch_bits += fmt.channel_bits[ch++];
    }

    file.setFrameBuffer(frameBuffer);
    file.writePixels(image.h);

#else
    throw std::runtime_error("EXR Support not enabled. Please rebuild Pangolin.");
#endif // HAVE_OPENEXR
}
Exemple #2
0
void SaveExr(const Image<unsigned char>& image_in, const pangolin::VideoPixelFormat& fmt, const std::string& filename, bool top_line_first)
{
#ifdef HAVE_OPENEXR
    Image<unsigned char> image;

    if(top_line_first) {
        image = image_in;
    }else{
        image.Alloc(image_in.w,image_in.h,image_in.pitch);
        for(size_t y=0; y<image_in.h; ++y) {
            std::memcpy(image.ptr + y*image.pitch, image_in.ptr + (image_in.h-y-1)*image_in.pitch, image.pitch);
        }
    }


    Imf::Header header (image.w, image.h);
    SetOpenEXRChannels(header.channels(), fmt);

    Imf::OutputFile file (filename.c_str(), header);
    Imf::FrameBuffer frameBuffer;

    int ch=0;
    size_t ch_bits = 0;
    for(Imf::ChannelList::Iterator it = header.channels().begin(); it != header.channels().end(); ++it)
    {
        frameBuffer.insert(
            it.name(),
            Imf::Slice(
                it.channel().type,
                (char*)image.ptr + ch_bits/8,
                fmt.channel_bits[ch]/8,
                image.pitch
            )
        );

        ch_bits += fmt.channel_bits[ch++];
    }

    file.setFrameBuffer(frameBuffer);
    file.writePixels(image.h);

    if(!top_line_first) {
        image.Dealloc();
    }

#else
    throw std::runtime_error("EXR Support not enabled. Please rebuild Pangolin.");
#endif // HAVE_OPENEXR
}
Exemple #3
0
bool
OpenEXROutput::write_scanline (int y, int z, TypeDesc format,
                               const void *data, stride_t xstride)
{
    bool native = (format == TypeDesc::UNKNOWN);
    size_t pixel_bytes = m_spec.pixel_bytes (native);
    if (native && xstride == AutoStride)
        xstride = (stride_t) pixel_bytes;
    m_spec.auto_stride (xstride, format, spec().nchannels);
    data = to_native_scanline (format, data, xstride, m_scratch);

    // Compute where OpenEXR needs to think the full buffers starts.
    // OpenImageIO requires that 'data' points to where the client wants
    // to put the pixels being read, but OpenEXR's frameBuffer.insert()
    // wants where the address of the "virtual framebuffer" for the
    // whole image.
    imagesize_t scanlinebytes = m_spec.scanline_bytes (native);
    char *buf = (char *)data
              - m_spec.x * pixel_bytes
              - y * scanlinebytes;

    try {
        Imf::FrameBuffer frameBuffer;
        size_t chanoffset = 0;
        for (int c = 0;  c < m_spec.nchannels;  ++c) {
            size_t chanbytes = m_spec.channelformats.size() 
                                  ? m_spec.channelformats[c].size() 
                                  : m_spec.format.size();
            frameBuffer.insert (m_spec.channelnames[c].c_str(),
                                Imf::Slice (m_pixeltype[c],
                                            buf + chanoffset,
                                            pixel_bytes, scanlinebytes));
            chanoffset += chanbytes;
        }
        m_output_scanline->setFrameBuffer (frameBuffer);
        m_output_scanline->writePixels (1);
    }
    catch (const std::exception &e) {
        error ("Failed OpenEXR write: %s", e.what());
        return false;
    }

    // FIXME -- can we checkpoint the file?

    return true;
}
Exemple #4
0
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
    const char *channel_name[4] = { "R", "G", "B", "A" };
    BOOL bIsFlipped = FALSE;
    half *halfData = NULL;

    if(!dib || !handle) return FALSE;

    try {
        // check for EXR_LC compression and verify that the format is RGB
        if((flags & EXR_LC) == EXR_LC) {
            FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
            if(((image_type != FIT_RGBF) && (image_type != FIT_RGBAF)) || ((flags & EXR_FLOAT) == EXR_FLOAT)) {
                THROW (Iex::IoExc, "EXR_LC compression is only available with RGB[A]F images");
            }
            if((FreeImage_GetWidth(dib) % 2) || (FreeImage_GetHeight(dib) % 2)) {
                THROW (Iex::IoExc, "EXR_LC compression only works when the width and height are a multiple of 2");
            }
        }

        // wrap the FreeImage IO stream
        C_OStream ostream(io, handle);

        // compression
        Imf::Compression compress;
        if((flags & EXR_NONE) == EXR_NONE) {
            // no compression
            compress = Imf::NO_COMPRESSION;
        } else if((flags & EXR_ZIP) == EXR_ZIP) {
            // zlib compression, in blocks of 16 scan lines
            compress = Imf::ZIP_COMPRESSION;
        } else if((flags & EXR_PIZ) == EXR_PIZ) {
            // piz-based wavelet compression
            compress = Imf::PIZ_COMPRESSION;
        } else if((flags & EXR_PXR24) == EXR_PXR24) {
            // lossy 24-bit float compression
            compress = Imf::PXR24_COMPRESSION;
        } else if((flags & EXR_B44) == EXR_B44) {
            // lossy 44% float compression
            compress = Imf::B44_COMPRESSION;
        } else {
            // default value
            compress = Imf::PIZ_COMPRESSION;
        }

        // create the header
        int width  = FreeImage_GetWidth(dib);
        int height = FreeImage_GetHeight(dib);
        int dx = 0, dy = 0;

        Imath::Box2i dataWindow (Imath::V2i (0, 0), Imath::V2i (width - 1, height - 1));
        Imath::Box2i displayWindow (Imath::V2i (-dx, -dy), Imath::V2i (width - dx - 1, height - dy - 1));

        Imf::Header header = Imf::Header(displayWindow, dataWindow, 1,
                                         Imath::V2f(0,0), 1,
                                         Imf::INCREASING_Y, compress);

        // handle thumbnail
        SetPreviewImage(dib, header);

        // check for EXR_LC compression
        if((flags & EXR_LC) == EXR_LC) {
            return SaveAsEXR_LC(ostream, dib, header, width, height);
        }

        // output pixel type
        Imf::PixelType pixelType;
        if((flags & EXR_FLOAT) == EXR_FLOAT) {
            pixelType = Imf::FLOAT;	// save as float data type
        } else {
            // default value
            pixelType = Imf::HALF;	// save as half data type
        }

        // check the data type and number of channels
        int components = 0;
        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
        switch(image_type) {
        case FIT_FLOAT:
            components = 1;
            // insert luminance channel
            header.channels().insert ("Y", Imf::Channel(pixelType));
            break;
        case FIT_RGBF:
            components = 3;
            for(int c = 0; c < components; c++) {
                // insert R, G and B channels
                header.channels().insert (channel_name[c], Imf::Channel(pixelType));
            }
            break;
        case FIT_RGBAF:
            components = 4;
            for(int c = 0; c < components; c++) {
                // insert R, G, B and A channels
                header.channels().insert (channel_name[c], Imf::Channel(pixelType));
            }
            break;
        default:
            THROW (Iex::ArgExc, "Cannot save: invalid data type.\nConvert the image to float before saving as OpenEXR.");
        }

        // build a frame buffer (i.e. what we have on input)
        Imf::FrameBuffer frameBuffer;

        BYTE *bits = NULL;	// pointer to our pixel buffer
        size_t bytespp = 0;	// size of our pixel in bytes
        size_t bytespc = 0;	// size of our pixel component in bytes
        unsigned pitch = 0;	// size of our yStride in bytes


        if(pixelType == Imf::HALF) {
            // convert from float to half
            halfData = new(std::nothrow) half[width * height * components];
            if(!halfData) THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY);

            for(int y = 0; y < height; y++) {
                float *src_bits = (float*)FreeImage_GetScanLine(dib, height - 1 - y);
                half *dst_bits = halfData + y * width * components;
                for(int x = 0; x < width; x++) {
                    for(int c = 0; c < components; c++) {
                        dst_bits[c] = src_bits[c];
                    }
                    src_bits += components;
                    dst_bits += components;
                }
            }
            bits = (BYTE*)halfData;
            bytespc = sizeof(half);
            bytespp = sizeof(half) * components;
            pitch = sizeof(half) * width * components;
        } else if(pixelType == Imf::FLOAT) {
            // invert dib scanlines
            bIsFlipped = FreeImage_FlipVertical(dib);

            bits = FreeImage_GetBits(dib);
            bytespc = sizeof(float);
            bytespp = sizeof(float) * components;
            pitch = FreeImage_GetPitch(dib);
        }

        if(image_type == FIT_FLOAT) {
            frameBuffer.insert ("Y",	// name
                                Imf::Slice (pixelType,	// type
                                            (char*)(bits),			// base
                                            bytespp,				// xStride
                                            pitch));				// yStride
        } else if((image_type == FIT_RGBF) || (image_type == FIT_RGBAF)) {
            for(int c = 0; c < components; c++) {
                char *channel_base = (char*)(bits) + c*bytespc;
                frameBuffer.insert (channel_name[c],// name
                                    Imf::Slice (pixelType,			// type
                                                channel_base,					// base
                                                bytespp,	// xStride
                                                pitch));	// yStride
            }
        }

        // write the data
        Imf::OutputFile file (ostream, header);
        file.setFrameBuffer (frameBuffer);
        file.writePixels (height);

        if(halfData != NULL) delete[] halfData;
        if(bIsFlipped) {
            // invert dib scanlines
            FreeImage_FlipVertical(dib);
        }

        return TRUE;

    } catch(Iex::BaseExc & e) {
        if(halfData != NULL) delete[] halfData;
        if(bIsFlipped) {
            // invert dib scanlines
            FreeImage_FlipVertical(dib);
        }

        FreeImage_OutputMessageProc(s_format_id, e.what());

        return FALSE;
    }
}
Exemple #5
0
bool
OpenEXROutput::write_scanlines (int ybegin, int yend, int z,
                                TypeDesc format, const void *data,
                                stride_t xstride, stride_t ystride)
{
    yend = std::min (yend, spec().y+spec().height);
    bool native = (format == TypeDesc::UNKNOWN);
    imagesize_t scanlinebytes = spec().scanline_bytes(native);
    size_t pixel_bytes = m_spec.pixel_bytes (native);
    if (native && xstride == AutoStride)
        xstride = (stride_t) pixel_bytes;
    stride_t zstride = AutoStride;
    m_spec.auto_stride (xstride, ystride, zstride, format, m_spec.nchannels,
                        m_spec.width, m_spec.height);

    const imagesize_t limit = 16*1024*1024;   // Allocate 16 MB, or 1 scanline
    int chunk = std::max (1, int(limit / scanlinebytes));

    bool ok = true;
    for ( ;  ok && ybegin < yend;  ybegin += chunk) {
        int y1 = std::min (ybegin+chunk, yend);
        int nscanlines = y1 - ybegin;
        const void *d = to_native_rectangle (m_spec.x, m_spec.x+m_spec.width,
                                             ybegin, y1, z, z+1, format, data,
                                             xstride, ystride, zstride,
                                             m_scratch);

        // Compute where OpenEXR needs to think the full buffers starts.
        // OpenImageIO requires that 'data' points to where the client wants
        // to put the pixels being read, but OpenEXR's frameBuffer.insert()
        // wants where the address of the "virtual framebuffer" for the
        // whole image.
        char *buf = (char *)d
                  - m_spec.x * pixel_bytes
                  - ybegin * scanlinebytes;
        try {
            Imf::FrameBuffer frameBuffer;
            size_t chanoffset = 0;
            for (int c = 0;  c < m_spec.nchannels;  ++c) {
                size_t chanbytes = m_spec.channelformats.size() 
                                      ? m_spec.channelformats[c].size() 
                                      : m_spec.format.size();
                frameBuffer.insert (m_spec.channelnames[c].c_str(),
                                    Imf::Slice (m_pixeltype[c],
                                                buf + chanoffset,
                                                pixel_bytes, scanlinebytes));
                chanoffset += chanbytes;
            }
            m_output_scanline->setFrameBuffer (frameBuffer);
            m_output_scanline->writePixels (nscanlines);
        }
        catch (const std::exception &e) {
            error ("Failed OpenEXR write: %s", e.what());
            return false;
        }

        data = (const char *)data + ystride*nscanlines;
    }

    // If we allocated more than 1M, free the memory.  It's not wasteful,
    // because it means we're writing big chunks at a time, and therefore
    // there will be few allocations and deletions.
    if (m_scratch.size() > 1*1024*1024) {
        std::vector<unsigned char> dummy;
        std::swap (m_scratch, dummy);
    }
    return true;
}