Beispiel #1
0
bool
HdrInput::read_native_scanline (int y, int z, void *data)
{
    if (m_next_scanline > y) {
        // User is trying to read an earlier scanline than the one we're
        // up to.  Easy fix: close the file and re-open.
        ImageSpec dummyspec;
        int subimage = current_subimage();
        int miplevel = current_miplevel();
        if (! close ()  ||
            ! open (m_filename, dummyspec)  ||
            ! seek_subimage (subimage, miplevel, dummyspec))
            return false;    // Somehow, the re-open failed
        assert (m_next_scanline == 0 && current_subimage() == subimage &&
                current_miplevel() == miplevel);
    }
    while (m_next_scanline <= y) {
        // Keep reading until we're read the scanline we really need
        int r = RGBE_ReadPixels_RLE (m_fd, (float *)data, m_spec.width, 1, rgbe_error);
        ++m_next_scanline;
        if (r != RGBE_RETURN_SUCCESS) {
            error ("%s", rgbe_error);
            return false;
        }
    }
    return true;
}
Beispiel #2
0
bool
ZfileInput::read_native_scanline(int subimage, int miplevel, int y, int z,
                                 void* data)
{
    lock_guard lock(m_mutex);
    if (!seek_subimage(subimage, miplevel))
        return false;

    if (m_next_scanline > y) {
        // User is trying to read an earlier scanline than the one we're
        // up to.  Easy fix: close the file and re-open.
        ImageSpec dummyspec;
        int subimage = current_subimage();
        if (!close() || !open(m_filename, dummyspec)
            || !seek_subimage(subimage, miplevel))
            return false;  // Somehow, the re-open failed
        ASSERT(m_next_scanline == 0 && current_subimage() == subimage);
    }
    while (m_next_scanline <= y) {
        // Keep reading until we're read the scanline we really need
        gzread(m_gz, data, m_spec.width * sizeof(float));
        ++m_next_scanline;
    }
    if (m_swab)
        swap_endian((float*)data, m_spec.width);
    return true;
}
Beispiel #3
0
bool
PNGInput::read_native_scanline (int y, int z, void *data)
{
    y -= m_spec.y;
    if (y < 0 || y >= m_spec.height)   // out of range scanline
        return false;

    if (m_interlace_type != 0) {
        // Interlaced.  Punt and read the whole image
        if (m_buf.empty ())
            readimg ();
        size_t size = spec().scanline_bytes();
        memcpy (data, &m_buf[0] + y * size, size);
    } else {
        // Not an interlaced image -- read just one row
        if (m_next_scanline > y) {
            // User is trying to read an earlier scanline than the one we're
            // up to.  Easy fix: close the file and re-open.
            ImageSpec dummyspec;
            int subimage = current_subimage();
            if (! close ()  ||
                ! open (m_filename, dummyspec)  ||
                ! seek_subimage (subimage, dummyspec))
                return false;    // Somehow, the re-open failed
            assert (m_next_scanline == 0 && current_subimage() == subimage);
        }
        while (m_next_scanline <= y) {
            // Keep reading until we're read the scanline we really need
            // std::cerr << "reading scanline " << m_next_scanline << "\n";
            std::string s = PNG_pvt::read_next_scanline (m_png, data);
            if (s.length ()) {
                close ();
                error ("%s", s.c_str ());
                return false;
            }
            ++m_next_scanline;
        }
    }

    // PNG specifically dictates unassociated (un-"premultiplied") alpha.
    // Convert to associated unless we were requested not to do so.
    if (m_spec.alpha_channel != -1 && !m_keep_unassociated_alpha) {
        float gamma = m_spec.get_float_attribute ("oiio:Gamma", 1.0f);
        if (m_spec.format == TypeDesc::UINT16)
            associateAlpha ((unsigned short *)data, m_spec.width,
                            m_spec.nchannels, m_spec.alpha_channel, 
                            gamma);
        else
            associateAlpha ((unsigned char *)data, m_spec.width,
                            m_spec.nchannels, m_spec.alpha_channel, 
                            gamma);
    }

    return true;
}
bool
JpgInput::read_native_scanline(int subimage, int miplevel, int y, int z,
                               void* data)
{
    if (!seek_subimage(subimage, miplevel))
        return false;
    if (m_raw)
        return false;
    if (y < 0 || y >= (int)m_cinfo.output_height)  // out of range scanline
        return false;
    if (m_next_scanline > y) {
        // User is trying to read an earlier scanline than the one we're
        // up to.  Easy fix: close the file and re-open.
        ImageSpec dummyspec;
        int subimage = current_subimage();
        if (!close() || !open(m_filename, dummyspec)
            || !seek_subimage(subimage, 0))
            return false;  // Somehow, the re-open failed
        assert(m_next_scanline == 0 && current_subimage() == subimage);
    }

    // Set up our custom error handler
    if (setjmp(m_jerr.setjmp_buffer)) {
        // Jump to here if there's a libjpeg internal error
        return false;
    }

    void* readdata = data;
    if (m_cmyk) {
        // If the file's data is CMYK, read into a 4-channel buffer, then
        // we'll have to convert.
        m_cmyk_buf.resize(m_spec.width * 4);
        readdata = &m_cmyk_buf[0];
        ASSERT(m_spec.nchannels == 3);
    }

    for (; m_next_scanline <= y; ++m_next_scanline) {
        // Keep reading until we've read the scanline we really need
        if (jpeg_read_scanlines(&m_cinfo, (JSAMPLE**)&readdata, 1) != 1
            || m_fatalerr) {
            error("JPEG failed scanline read (\"%s\")", filename().c_str());
            return false;
        }
    }

    if (m_cmyk)
        cmyk_to_rgb(m_spec.width, (unsigned char*)readdata, 4,
                    (unsigned char*)data, 3);

    return true;
}
Beispiel #5
0
bool
NullInput::seek_subimage(int subimage, int miplevel)
{
    if (subimage == current_subimage() && miplevel == current_miplevel()) {
        return true;
    }

    if (subimage != 0)
        return false;  // We only make one subimage
    m_subimage = subimage;

    if (miplevel > 0 && !m_mip)
        return false;  // Asked for MIP levels but we aren't makign them

    m_spec = m_topspec;
    for (m_miplevel = 0; m_miplevel < miplevel; ++m_miplevel) {
        if (m_spec.width == 1 && m_spec.height == 1 && m_spec.depth == 1)
            return false;  // Asked for more MIP levels than were available
        m_spec.width       = std::max(1, m_spec.width / 2);
        m_spec.height      = std::max(1, m_spec.height / 2);
        m_spec.depth       = std::max(1, m_spec.depth / 2);
        m_spec.full_width  = m_spec.width;
        m_spec.full_height = m_spec.height;
        m_spec.full_depth  = m_spec.depth;
    }
    return true;
}
Beispiel #6
0
bool
HdrInput::seek_subimage(int subimage, int miplevel)
{
    // HDR doesn't support multiple subimages or mipmaps
    if (subimage != 0 || miplevel != 0)
        return false;

    // Skip the hard work if we're already on the requested subimage
    if (subimage == current_subimage()) {
        return true;
    }

    close();

    // Check that file exists and can be opened
    m_fd = Filesystem::fopen(m_filename, "rb");
    if (m_fd == NULL) {
        error("Could not open file \"%s\"", m_filename.c_str());
        return false;
    }

    rgbe_header_info h;
    int width, height;
    int r = RGBE_ReadHeader(m_fd, &width, &height, &h, rgbe_error);
    if (r != RGBE_RETURN_SUCCESS) {
        error("%s", rgbe_error);
        close();
        return false;
    }

    m_spec = ImageSpec(width, height, 3, TypeDesc::FLOAT);

    if (h.valid & RGBE_VALID_GAMMA) {
        // Round gamma to the nearest hundredth to prevent stupid
        // precision choices and make it easier for apps to make
        // decisions based on known gamma values. For example, you want
        // 2.2, not 2.19998.
        float g = float(1.0 / h.gamma);
        g       = roundf(100.0 * g) / 100.0f;
        m_spec.attribute("oiio:Gamma", g);
        if (g == 1.0f)
            m_spec.attribute("oiio:ColorSpace", "linear");
        else
            m_spec.attribute("oiio:ColorSpace",
                             Strutil::sprintf("GammaCorrected%.2g", g));
    } else {
        // Presume linear color space
        m_spec.attribute("oiio:ColorSpace", "linear");
    }
    if (h.valid & RGBE_VALID_ORIENTATION)
        m_spec.attribute("Orientation", h.orientation);

    // FIXME -- should we do anything about exposure, software,
    // pixaspect, primaries?  (N.B. rgbe.c doesn't even handle most of them)

    m_subimage      = subimage;
    m_next_scanline = 0;
    return true;
}
Beispiel #7
0
bool
HdrInput::seek_subimage (int subimage, int miplevel, ImageSpec &newspec)
{
    // HDR doesn't support multiple subimages or mipmaps
    if (subimage != 0 || miplevel != 0)
        return false;

    // Skip the hard work if we're already on the requested subimage
    if (subimage == current_subimage()) {
        newspec = spec();
        return true;
    }

    close();

    // Check that file exists and can be opened
    m_fd = Filesystem::fopen (m_filename, "rb");
    if (m_fd == NULL) {
        error ("Could not open file \"%s\"", m_filename.c_str());
        return false;
    }

    rgbe_header_info h;
    int width, height;
    int r = RGBE_ReadHeader (m_fd, &width, &height, &h, rgbe_error);
    if (r != RGBE_RETURN_SUCCESS) {
        error ("%s", rgbe_error);
        close ();
        return false;
    }

    m_spec = ImageSpec (width, height, 3, TypeDesc::FLOAT);

    if (h.valid & RGBE_VALID_GAMMA)
        m_spec.attribute ("oiio:Gamma", h.gamma);
    if (h.valid & RGBE_VALID_ORIENTATION)
        m_spec.attribute ("Orientation", h.orientation);

    // FIXME -- should we do anything about exposure, software,
    // pixaspect, primaries?  (N.B. rgbe.c doesn't even handle most of them)

    m_subimage = subimage;
    m_next_scanline = 0;
    newspec = m_spec;
    return true;
}
Beispiel #8
0
bool
TIFFInput::read_native_scanline (int y, int z, void *data)
{
    y -= m_spec.y;

    // For compression modes that don't support random access to scanlines
    // (which I *think* is only LZW), we need to emulate random access by
    // re-seeking.
    if (m_no_random_access) {
        if (m_next_scanline > y) {
            // User is trying to read an earlier scanline than the one we're
            // up to.  Easy fix: start over.
            // FIXME: I'm too tired to look into it now, but I wonder if
            // it is able to randomly seek to the first line in any
            // "strip", in which case we don't need to start from 0, just
            // start from the beginning of the strip we need.
            ImageSpec dummyspec;
            int old_subimage = current_subimage();
            int old_miplevel = current_miplevel();
            if (! close ()  ||
                ! open (m_filename, dummyspec)  ||
                ! seek_subimage (old_subimage, old_miplevel, dummyspec)) {
                return false;    // Somehow, the re-open failed
            }
            ASSERT (m_next_scanline == 0 &&
                    current_subimage() == old_subimage &&
                    current_miplevel() == old_miplevel);
        }
        while (m_next_scanline < y) {
            // Keep reading until we're read the scanline we really need
            m_scratch.resize (m_spec.scanline_bytes());
            if (TIFFReadScanline (m_tif, &m_scratch[0], m_next_scanline) < 0) {
                error ("%s", lasterr.c_str());
                return false;
            }
            ++m_next_scanline;
        }
    }
    m_next_scanline = y+1;

    int nvals = m_spec.width * m_spec.nchannels;
    m_scratch.resize (m_spec.scanline_bytes());
    bool no_bit_convert = (m_bitspersample == 8 || m_bitspersample == 16 ||
                           m_bitspersample == 32);
    if (m_photometric == PHOTOMETRIC_PALETTE) {
        // Convert from palette to RGB
        if (TIFFReadScanline (m_tif, &m_scratch[0], y) < 0) {
            error ("%s", lasterr.c_str());
            return false;
        }
        palette_to_rgb (m_spec.width, &m_scratch[0], (unsigned char *)data);
    } else {
        // Not palette
        int plane_bytes = m_spec.width * m_spec.format.size();
        int planes = m_separate ? m_spec.nchannels : 1;
        std::vector<unsigned char> scratch2 (m_separate ? m_spec.scanline_bytes() : 0);
        // Where to read?  Directly into user data if no channel shuffling
        // or bit shifting is needed, otherwise into scratch space.
        unsigned char *readbuf = (no_bit_convert && !m_separate) ? (unsigned char *)data : &m_scratch[0];
        // Perform the reads.  Note that for contig, planes==1, so it will
        // only do one TIFFReadScanline.
        for (int c = 0;  c < planes;  ++c)  /* planes==1 for contig */
            if (TIFFReadScanline (m_tif, &readbuf[plane_bytes*c], y, c) < 0) {
                error ("%s", lasterr.c_str());
                return false;
            }
        if (m_bitspersample < 8) {
            // m_scratch now holds nvals n-bit values, contig or separate
            std::swap (m_scratch, scratch2);
            for (int c = 0;  c < planes;  ++c)  /* planes==1 for contig */
                bit_convert (m_separate ? m_spec.width : nvals,
                             &scratch2[plane_bytes*c], m_bitspersample,
                             m_separate ? &m_scratch[plane_bytes*c] : (unsigned char *)data+plane_bytes*c, 8);
        } else if (m_bitspersample > 8 && m_bitspersample < 16) {
            // m_scratch now holds nvals n-bit values, contig or separate
            std::swap (m_scratch, scratch2);
            for (int c = 0;  c < planes;  ++c)  /* planes==1 for contig */
                bit_convert (m_separate ? m_spec.width : nvals,
                             &scratch2[plane_bytes*c], m_bitspersample,
                             m_separate ? &m_scratch[plane_bytes*c] : (unsigned char *)data+plane_bytes*c, 16);
        }
        if (m_separate) {
            // Convert from separate (RRRGGGBBB) to contiguous (RGBRGBRGB).
            // We know the data is in m_scratch at this point, so 
            // contiguize it into the user data area.
            separate_to_contig (m_spec.width, &m_scratch[0], (unsigned char *)data);
        }
    }

    if (m_photometric == PHOTOMETRIC_MINISWHITE)
        invert_photometric (nvals, data);

    // If alpha is unassociated and we aren't requested to keep it that
    // way, multiply the colors by alpha per the usual OIIO conventions
    // to deliver associated color & alpha.
    if (m_convert_alpha)
        unassalpha_to_assocalpha (m_spec.width, data);

    return true;
}
Beispiel #9
0
bool
TIFFInput::read_native_scanline (int y, int z, void *data)
{
    y -= m_spec.y;

    // For compression modes that don't support random access to scanlines
    // (which I *think* is only LZW), we need to emulate random access by
    // re-seeking.
    if (m_no_random_access) {
        if (m_next_scanline > y) {
            // User is trying to read an earlier scanline than the one we're
            // up to.  Easy fix: start over.
            // FIXME: I'm too tired to look into it now, but I wonder if
            // it is able to randomly seek to the first line in any
            // "strip", in which case we don't need to start from 0, just
            // start from the beginning of the strip we need.
            ImageSpec dummyspec;
            int old_subimage = current_subimage();
            int old_miplevel = current_miplevel();
            if (! close ()  ||
                ! open (m_filename, dummyspec)  ||
                ! seek_subimage (old_subimage, old_miplevel, dummyspec)) {
                return false;    // Somehow, the re-open failed
            }
            ASSERT (m_next_scanline == 0 &&
                    current_subimage() == old_subimage &&
                    current_miplevel() == old_miplevel);
        }
        while (m_next_scanline < y) {
            // Keep reading until we're read the scanline we really need
            m_scratch.resize (m_spec.scanline_bytes());
            if (TIFFReadScanline (m_tif, &m_scratch[0], m_next_scanline) < 0) {
                error ("%s", lasterr.c_str());
                return false;
            }
            ++m_next_scanline;
        }
    }
    m_next_scanline = y+1;

    if (m_photometric == PHOTOMETRIC_PALETTE) {
        // Convert from palette to RGB
        m_scratch.resize (m_spec.width);
        if (TIFFReadScanline (m_tif, &m_scratch[0], y) < 0) {
            error ("%s", lasterr.c_str());
            return false;
        }
        palette_to_rgb (m_spec.width, &m_scratch[0], (unsigned char *)data);
    } else if (m_planarconfig == PLANARCONFIG_SEPARATE && m_spec.nchannels > 1) {
        // Convert from separate (RRRGGGBBB) to contiguous (RGBRGBRGB)
        m_scratch.resize (m_spec.scanline_bytes());
        int plane_bytes = m_spec.width * m_spec.format.size();
        for (int c = 0;  c < m_spec.nchannels;  ++c)
            if (TIFFReadScanline (m_tif, &m_scratch[plane_bytes*c], y, c) < 0) {
                error ("%s", lasterr.c_str());
                return false;
            }
        separate_to_contig (m_spec.width, &m_scratch[0], (unsigned char *)data);
    } else if (m_bitspersample == 1 || m_bitspersample == 2 || 
               m_bitspersample == 4) {
        // <8 bit images
        m_scratch.resize (m_spec.width);
        if (TIFFReadScanline (m_tif, &m_scratch[0], y) < 0) {
            error ("%s", lasterr.c_str());
            return false;
        }
        nbit_to_8bit (m_spec.width, &m_scratch[0], (unsigned char *)data,
                      m_bitspersample);
    } else {
        // Contiguous, >= 8 bit per sample -- the "usual" case
        if (TIFFReadScanline (m_tif, data, y) < 0) {
            error ("%s", lasterr.c_str());
            return false;
        }
    }

    if (m_photometric == PHOTOMETRIC_MINISWHITE)
        invert_photometric (m_spec.width * m_spec.nchannels, data);

    // If alpha is unassociated and we aren't requested to keep it that
    // way, multiply the colors by alpha per the usual OIIO conventions
    // to deliver associated color & alpha.
    if (m_convert_alpha)
        unassalpha_to_assocalpha (m_spec.width, data);

    return true;
}