// -*- c-basic-offset: 4 -*- /** @file impexalpha.hxx * * Routines to save images with alpha masks. * * These routines handle the conversion of byte alpha * channels into the final output types. * * @author Pablo d'Angelo * * $Id: impexalpha.hxx 1951 2007-04-15 20:54:49Z dangelo $ * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef VIGRA_EXT_IMPEX_ALPHA_IMAGE_H #define VIGRA_EXT_IMPEX_ALPHA_IMAGE_H #include #include #include #include #include #include namespace vigra { #if 0 /** define values for mask true value. max for integers, 1 for floats */ template struct GetMaskTrue; #define VIGRA_EXT_GETMASKTRUE(T1, S) \ template<> \ struct GetMaskTrue \ { \ static T1 get() \ { \ return S; \ } \ }; #define VIGRA_EXT_GETMASKMAX(T1) \ template<> \ struct GetMaskTrue \ { \ static T1 get() \ { \ return vigra::NumericTraits::max(); \ } \ }; VIGRA_EXT_GETMASKMAX(vigra::UInt8) VIGRA_EXT_GETMASKMAX(vigra::Int16) VIGRA_EXT_GETMASKMAX(vigra::UInt16) VIGRA_EXT_GETMASKMAX(vigra::Int32) VIGRA_EXT_GETMASKMAX(vigra::UInt32) VIGRA_EXT_GETMASKTRUE(float, 1.0f) VIGRA_EXT_GETMASKTRUE(double, 1.0) #endif template struct MaskConv; template<> struct MaskConv { static vigra::UInt8 toUInt8(vigra::UInt8 v) { return v; } static vigra::UInt8 fromUInt8(vigra::UInt8 v) { return v; } }; template<> struct MaskConv { static vigra::UInt8 toUInt8(vigra::UInt16 v) { return v>>8; } static vigra::UInt16 fromUInt8(vigra::UInt8 v) { return (v<<8) + v; } }; template<> struct MaskConv { static vigra::UInt8 toUInt8(vigra::Int16 v) { return v>>7; } static vigra::Int16 fromUInt8(vigra::UInt8 v) { return (v<<7)+ (v & 127); } }; template<> struct MaskConv { static vigra::UInt8 toUInt8(vigra::UInt32 v) { return v>>24; } static vigra::UInt32 fromUInt8(vigra::UInt8 v) { return (v<<24) + (v<<16) + (v<<8) + v; } }; template<> struct MaskConv { static vigra::UInt8 toUInt8(vigra::Int32 v) { return v>>23; } static vigra::Int32 fromUInt8(vigra::UInt8 v) { return (v<<23) + (v<<15) + (v<<7) + (v & 127); } }; template<> struct MaskConv { static vigra::UInt8 toUInt8(float v) { return vigra::NumericTraits::fromRealPromote(v*255); } static float fromUInt8(vigra::UInt8 v) { return v/255.0f; } }; template<> struct MaskConv { static vigra::UInt8 toUInt8(double v) { return vigra::NumericTraits::fromRealPromote(v*255); } static double fromUInt8(vigra::UInt8 v) { return v/255.0; } }; template class MultiImageMaskAccessor2 { public: /** The accessors value_type: construct a pair that contains the corresponding image values. */ typedef vigra::TinyVector value_type; typedef typename Acc1::value_type component_type; typedef typename Acc2::value_type alpha_type; /** Construct from two image iterators and associated accessors. */ MultiImageMaskAccessor2(Iter1 i1, Acc1 a1, Iter2 i2, Acc2 a2) : i1_(i1), a1_(a1), i2_(i2), a2_(a2) {} /** read the current data item */ template value_type operator()(DIFFERENCE const & d) const { return value_type(a1_(i1_, d), MaskConv::fromUInt8(a2_(i2_, d))); } /** read the data item at an offset */ template value_type operator()(DIFFERENCE1 d, DIFFERENCE2 const & d2) const { d += d2; return value_type(a1_(i1_, d), MaskConv::fromUInt8(a2_(i2_, d))); // a2_(i2_, d)? GetMaskTrue::get() * a2_(i2_, d) : vigra::NumericTraits::zero()); // return std::make_pair(a1_(i1_, d1), a2_(i2_, d1)); } /** write the current data item */ template value_type set(const value_type & vt, DIFFERENCE const & d) const { a1_.set(vt[0], i1_, d); a2_.set(MaskConv::toUInt8(vt[1])); //GetMaskTrue::get() : vigra::NumericTraits::zero(), i2_, d); } /** scalar & scalar image */ template void setComponent( V const & value, ITERATOR const & i, int idx ) const { switch (idx) { case 0: a1_.set(value, i1_, *i); break; case 1: a2_.set(MaskConv::toUInt8(value), i2_, *i); // ? GetMaskTrue::get() : vigra::NumericTraits::zero()); break; default: vigra_fail("too many components in input value"); } } /** read one component */ template component_type getComponent(ITERATOR const & i, int idx) const { switch (idx) { case 0: return a1_( i1_, *i ); case 1: return MaskConv::fromUInt8(a2_( i2_, *i )); //? GetMaskTrue::get() : vigra::NumericTraits::zero(); default: vigra_fail("too many components in input value"); // never reached, but here to silence compiler exit(1); } } template unsigned int size ( ITERATOR const & i ) const { return 2; } private: Iter1 i1_; Acc1 a1_; Iter2 i2_; Acc2 a2_; }; // get: convert from UInt8 mask to native type // read: convert from native type to UInt8 mask template class MultiImageVectorMaskAccessor4 { public: /** The accessors value_type: construct a pair that contains the corresponding image values. */ typedef typename Acc1::value_type VT1; // todo.. check static_size, currently static_size == 4 enum { static_size = 4 }; typedef vigra::TinyVector value_type; typedef typename value_type::value_type component_type; typedef typename Acc2::value_type alpha_type; /** Construct from two image iterators and associated accessors. */ MultiImageVectorMaskAccessor4(Iter1 i1, Acc1 a1, Iter2 i2, Acc2 a2) : i1_(i1), a1_(a1), i2_(i2), a2_(a2) {} /** read the current data item */ template value_type operator()(DIFFERENCE const & d) const { const VT1 & v1 = a1_.get(i1_,d); return value_type(v1[0], v1[1], v1[2], MaskConv::fromUInt8(a2_(i2_, d))); } /** read the data item at an offset */ template value_type operator()(DIFFERENCE1 d, DIFFERENCE2 const & d2) const { d += d2; const VT1 & v1 = a1_.get(i1_,d); return value_type(v1[0], v1[1], v1[2], MaskConv::fromUInt8(a2_(i2_, d))); } /** write the current data item */ template value_type set(const value_type & vt, DIFFERENCE const & d) const { Iter1 i1(i1_); i1 +=d; a1_.setComponent(vt[0], i1_, 0); a1_.setComponent(vt[1], i1_, 1); a1_.setComponent(vt[2], i1_, 2); a2_.set(MaskConv::toUInt8(vt[3]), i2_, d); } /** vector & scalar image */ template void setComponent( V const & value, ITERATOR const & i, int idx ) const { if ( idx < static_size - 1 ) { a1_.setComponent(value, i1_, *i, idx); } else if ( idx == static_size - 1 ) { a2_.set(MaskConv::toUInt8(value), i2_, *i); } else { vigra_fail("too many components in input value"); } } /** read one component */ template component_type getComponent(ITERATOR const & i, int idx) const { if ( idx < static_size - 1 ) { return a1_.getComponent(i1_, *i, idx); } else #ifndef DEBUG return MaskConv::fromUInt8(a2_(i2_, *i)); #else if ( idx == static_size - 1 ) { return MaskConv::fromUInt8(a2_(i2_, *i)); } else { vigra_fail("too many components in input value"); // just to silence the compiler warning. this is // never reached, since vigra_fail will always // throw an exception. throw 0; } #endif } template unsigned int size ( ITERATOR const & i ) const { return static_size; } private: Iter1 i1_; Acc1 a1_; Iter2 i2_; Acc2 a2_; }; // scalar image template void exportImageAlpha(vigra::triple image, std::pair alpha, vigra::ImageExportInfo const & info, vigra::VigraTrueType) { typedef MultiImageMaskAccessor2 MAcc; exportImage(vigra::CoordinateIterator(), vigra::CoordinateIterator() + (image.second - image.first), MAcc(image.first, image.third, alpha.first, alpha.second), info); } // vector image template void exportImageAlpha(vigra::triple image, std::pair alpha, vigra::ImageExportInfo const & info, vigra::VigraFalseType) { typedef MultiImageVectorMaskAccessor4 MAcc; exportImage(vigra::CoordinateIterator(), vigra::CoordinateIterator(image.second - image.first), MAcc(image.first, image.third, alpha.first, alpha.second), info ); } /** export an image with a differently typed alpha channel. * * This function handles the merging of the images and the * scales the alpha channel to the correct values. * * can write to all output formats that support 4 channel images. * (currently only png and tiff). */ template void exportImageAlpha(vigra::triple image, std::pair alpha, vigra::ImageExportInfo const & info) { typedef typename vigra::NumericTraits::isScalar is_scalar; // select function for scalar, or vector image, depending on source type. // the alpha image has to be scalar all the time. stuff will break with strange // compile error if it isn't exportImageAlpha( image, alpha, info, is_scalar()); } // vector image template void importImageAlpha(vigra::ImageImportInfo const & info, std::pair image, std::pair alpha, vigra::VigraFalseType) { vigra_precondition(image.second(image.first).size() == 3, "only scalar and 3 channel (vector) images supported by impexalpha.hxx"); typedef MultiImageVectorMaskAccessor4 MAcc; importImage(info, vigra::CoordinateIterator(), MAcc(image.first, image.second, alpha.first, alpha.second) ); } // scalar image template void importImageAlpha(vigra::ImageImportInfo const & info, std::pair image, std::pair alpha, vigra::VigraTrueType) { typedef MultiImageMaskAccessor2 MAcc; importImage(info, vigra::CoordinateIterator(), MAcc(image.first, image.second, alpha.first, alpha.second) ); } /** import an image with a differently typed alpha channel. * * This function loads an image, and splits it into a * color image and a separate alpha channel, the alpha channel * should be a 8 bit image. * * If the image doesn't contain any alpha channel, a completely * white one is created. * * can write to all output formats that support 4 channel images. * (currently only png and tiff). */ template void importImageAlpha(vigra::ImageImportInfo const & info, vigra::pair image, std::pair alpha ) { typedef typename vigra::NumericTraits::isScalar is_scalar; if (info.numExtraBands() == 1 ) { // import image and alpha channel importImageAlpha(info, image, alpha, is_scalar()); } else if (info.numExtraBands() == 0 ) { // no alphachannel in file, import as usual. importImage(info, image); // fill alpha image vigra::initImage(alpha.first , alpha.first + vigra::Diff2D(info.width(), info.height()), alpha.second, 255); } else { vigra_fail("Images with two or more channel are not supported"); } } } // namespace #endif // VIGRA_EXT_IMPEX_ALPHA_IMAGE_H