Beispiel #1
0
void
ImageBuf::copy_from (const ImageBuf &src)
{
    if (this == &src)
        return;
    ASSERT (m_spec.width == src.m_spec.width &&
            m_spec.height == src.m_spec.height &&
            m_spec.depth == src.m_spec.depth &&
            m_spec.nchannels == src.m_spec.nchannels);
    realloc ();
    if (m_spec.deep)
        m_deepdata = src.m_deepdata;
    else
        src.get_pixels (src.xbegin(), src.xend(), src.ybegin(), src.yend(),
                        src.zbegin(), src.zend(), m_spec.format, m_localpixels);
}
Beispiel #2
0
static bool
write_mipmap (ImageBufAlgo::MakeTextureMode mode,
              ImageBuf &img, const ImageSpec &outspec_template,
              std::string outputfilename, ImageOutput *out,
              TypeDesc outputdatatype, bool mipmap,
              Filter2D *filter, const ImageSpec &configspec,
              std::ostream &outstream,
              double &stat_writetime, double &stat_miptime)
{
    bool envlatlmode = (mode == ImageBufAlgo::MakeTxEnvLatl);

    ImageSpec outspec = outspec_template;
    outspec.set_format (outputdatatype);

    if (mipmap && !out->supports ("multiimage") && !out->supports ("mipmap")) {
        outstream << "maketx ERROR: \"" << outputfilename
                  << "\" format does not support multires images\n";
        return false;
    }

    if (! mipmap && ! strcmp (out->format_name(), "openexr")) {
        // Send hint to OpenEXR driver that we won't specify a MIPmap
        outspec.attribute ("openexr:levelmode", 0 /* ONE_LEVEL */);
    }

    if (mipmap && ! strcmp (out->format_name(), "openexr")) {
        outspec.attribute ("openexr:roundingmode", 0 /* ROUND_DOWN */);
    }

    // OpenEXR always uses border sampling for environment maps
    bool src_samples_border;
    if (envlatlmode && !strcmp(out->format_name(), "openexr")) {
        src_samples_border = true;
        outspec.attribute ("oiio:updirection", "y");
        outspec.attribute ("oiio:sampleborder", 1);
    }
    if (envlatlmode && src_samples_border)
        fix_latl_edges (img);

    Timer writetimer;
    if (! out->open (outputfilename.c_str(), outspec)) {
        outstream << "maketx ERROR: Could not open \"" << outputfilename
                  << "\" : " << out->geterror() << "\n";
        return false;
    }

    // Write out the image
    bool verbose = configspec.get_int_attribute ("maketx:verbose");
    if (verbose) {
        outstream << "  Writing file: " << outputfilename << std::endl;
        outstream << "  Filter \"" << filter->name() << "\" width = " 
                  << filter->width() << "\n";
        outstream << "  Top level is " << formatres(outspec) << std::endl;
    }

    if (! img.write (out)) {
        // ImageBuf::write transfers any errors from the ImageOutput to
        // the ImageBuf.
        outstream << "maketx ERROR: Write failed \" : " << img.geterror() << "\n";
        out->close ();
        return false;
    }

    stat_writetime += writetimer();

    if (mipmap) {  // Mipmap levels:
        if (verbose)
            outstream << "  Mipmapping...\n" << std::flush;
        std::vector<std::string> mipimages;
        std::string mipimages_unsplit = configspec.get_string_attribute ("maketx:mipimages");
        if (mipimages_unsplit.length())
            Strutil::split (mipimages_unsplit, mipimages, ";");
        ImageBuf tmp;
        ImageBuf *big = &img, *small = &tmp;
        while (outspec.width > 1 || outspec.height > 1) {
            Timer miptimer;
            ImageSpec smallspec;

            if (mipimages.size()) {
                // Special case -- the user specified a custom MIP level
                small->reset (mipimages[0]);
                small->read (0, 0, true, TypeDesc::FLOAT);
                smallspec = small->spec();
                if (smallspec.nchannels != outspec.nchannels) {
                    outstream << "WARNING: Custom mip level \"" << mipimages[0]
                              << " had the wrong number of channels.\n";
                    ImageBuf *t = new ImageBuf (mipimages[0], smallspec);
                    ImageBufAlgo::setNumChannels(*t, *small, outspec.nchannels);
                    std::swap (t, small);
                    delete t;
                }
                smallspec.tile_width = outspec.tile_width;
                smallspec.tile_height = outspec.tile_height;
                smallspec.tile_depth = outspec.tile_depth;
                mipimages.erase (mipimages.begin());
            } else {
                // Resize a factor of two smaller
                smallspec = outspec;
                smallspec.width = big->spec().width;
                smallspec.height = big->spec().height;
                smallspec.depth = big->spec().depth;
                if (smallspec.width > 1)
                    smallspec.width /= 2;
                if (smallspec.height > 1)
                    smallspec.height /= 2;
                smallspec.full_width = smallspec.width;
                smallspec.full_height = smallspec.height;
                smallspec.full_depth = smallspec.depth;
                smallspec.set_format (TypeDesc::FLOAT);

                // Trick: to get the resize working properly, we reset
                // both display and pixel windows to match, and have 0
                // offset, AND doctor the big image to have its display
                // and pixel windows match.  Don't worry, the texture
                // engine doesn't care what the upper MIP levels have
                // for the window sizes, it uses level 0 to determine
                // the relatinship between texture 0-1 space (display
                // window) and the pixels.
                smallspec.x = 0;
                smallspec.y = 0;
                smallspec.full_x = 0;
                smallspec.full_y = 0;
                small->alloc (smallspec);  // Realocate with new size
                big->set_full (big->xbegin(), big->xend(), big->ybegin(),
                               big->yend(), big->zbegin(), big->zend());

                if (filter->name() == "box" && filter->width() == 1.0f)
                    ImageBufAlgo::parallel_image (boost::bind(resize_block, small, big, _1, envlatlmode),
                                                  OIIO::get_roi(small->spec()));
                else
                    ImageBufAlgo::parallel_image (boost::bind(resize_block_HQ, small, big, _1, filter),
                                                  OIIO::get_roi(small->spec()));
            }

            stat_miptime += miptimer();
            outspec = smallspec;
            outspec.set_format (outputdatatype);
            if (envlatlmode && src_samples_border)
                fix_latl_edges (*small);

            Timer writetimer;
            // If the format explicitly supports MIP-maps, use that,
            // otherwise try to simulate MIP-mapping with multi-image.
            ImageOutput::OpenMode mode = out->supports ("mipmap") ?
                ImageOutput::AppendMIPLevel : ImageOutput::AppendSubimage;
            if (! out->open (outputfilename.c_str(), outspec, mode)) {
                outstream << "maketx ERROR: Could not append \"" << outputfilename
                          << "\" : " << out->geterror() << "\n";
                return false;
            }
            if (! small->write (out)) {
                // ImageBuf::write transfers any errors from the
                // ImageOutput to the ImageBuf.
                outstream << "maketx ERROR writing \"" << outputfilename
                          << "\" : " << small->geterror() << "\n";
                out->close ();
                return false;
            }
            stat_writetime += writetimer();
            if (verbose) {
                outstream << "    " << formatres(smallspec) << std::endl;
            }
            std::swap (big, small);
        }
    }

    if (verbose)
        outstream << "  Wrote file: " << outputfilename << std::endl;
    writetimer.reset ();
    writetimer.start ();
    if (! out->close ()) {
        outstream << "maketx ERROR writing \"" << outputfilename
                  << "\" : " << out->geterror() << "\n";
        return false;
    }
    stat_writetime += writetimer ();
    return true;
}
Beispiel #3
0
bool
ImageBuf::copy_pixels (const ImageBuf &src)
{
    // compute overlap
    int xbegin = std::max (this->xbegin(), src.xbegin());
    int xend = std::min (this->xend(), src.xend());
    int ybegin = std::max (this->ybegin(), src.ybegin());
    int yend = std::min (this->yend(), src.yend());
    int zbegin = std::max (this->zbegin(), src.zbegin());
    int zend = std::min (this->zend(), src.zend());
    int nchannels = std::min (this->nchannels(), src.nchannels());

    // If we aren't copying over all our pixels, zero out the pixels
    if (xbegin != this->xbegin() || xend != this->xend() ||
        ybegin != this->ybegin() || yend != this->yend() ||
        zbegin != this->zbegin() || zend != this->zend() ||
        nchannels != this->nchannels())
        ImageBufAlgo::zero (*this);

    // Call template copy_pixels_ based on src data type
    switch (src.spec().format.basetype) {
    case TypeDesc::FLOAT :
        copy_pixels_<float> (*this, src, xbegin, xend, ybegin, yend,
                             zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT8 :
        copy_pixels_<unsigned char> (*this, src, xbegin, xend, ybegin, yend,
                                     zbegin, zend, nchannels);
        break;
    case TypeDesc::INT8  :
        copy_pixels_<char> (*this, src, xbegin, xend, ybegin, yend,
                            zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT16:
        copy_pixels_<unsigned short> (*this, src, xbegin, xend, ybegin, yend,
                                      zbegin, zend, nchannels);
        break;
    case TypeDesc::INT16 :
        copy_pixels_<short> (*this, src, xbegin, xend, ybegin, yend,
                             zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT  :
        copy_pixels_<unsigned int> (*this, src, xbegin, xend, ybegin, yend,
                                    zbegin, zend, nchannels);
        break;
    case TypeDesc::INT   :
        copy_pixels_<int> (*this, src, xbegin, xend, ybegin, yend,
                           zbegin, zend, nchannels);
        break;
    case TypeDesc::HALF  :
        copy_pixels_<half> (*this, src, xbegin, xend, ybegin, yend,
                            zbegin, zend, nchannels);
        break;
    case TypeDesc::DOUBLE:
        copy_pixels_<double> (*this, src, xbegin, xend, ybegin, yend,
                              zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT64:
        copy_pixels_<unsigned long long> (*this, src, xbegin, xend, ybegin, yend,
                                          zbegin, zend, nchannels);
        break;
    case TypeDesc::INT64 :
        copy_pixels_<long long> (*this, src, xbegin, xend, ybegin, yend,
                                 zbegin, zend, nchannels);
        break;
    default:
        ASSERT (0);
    }
    return true;
}