povray/source/base/image/encoding.h
2013-11-06 13:07:19 -05:00

219 lines
12 KiB
C++

/*******************************************************************************
* encoding.h
*
* This file contains code for handling image data quantization.
*
* ---------------------------------------------------------------------------
* Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
* Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
*
* POV-Ray is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* POV-Ray 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ---------------------------------------------------------------------------
* POV-Ray is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
* ---------------------------------------------------------------------------
* $File: //depot/public/povray/3.x/source/base/image/encoding.h $
* $Revision: #1 $
* $Change: 6069 $
* $DateTime: 2013/11/06 11:59:40 $
* $Author: chrisc $
*******************************************************************************/
#ifndef POVRAY_BASE_IMAGE_ENCODING_H
#define POVRAY_BASE_IMAGE_ENCODING_H
#include <boost/thread.hpp>
#include "base/configbase.h"
#include "base/types.h"
#include "base/image/colourspace.h"
namespace pov_base
{
class Image;
/// Abstract class representing dithering rules and respective state information.
class DitherHandler
{
public:
struct OffsetInfo
{
union { float red, gray; }; float green, blue, alpha;
OffsetInfo() : red(0.0f), green(0.0f), blue(0.0f), alpha(0.0f) { }
OffsetInfo(float r, float g, float b, float a) : red(r), green(g), blue(b), alpha(a) { }
void clear() { red = 0.0f; green = 0.0f; blue = 0.0f; alpha = 0.0f; }
void setAll(float v) { red = v; green = v; blue = v; alpha = v; }
OffsetInfo operator*(float b) const { return OffsetInfo(red*b, green*b, blue*b, alpha*b); }
OffsetInfo operator+(const OffsetInfo& b) const { return OffsetInfo(red+b.red, green+b.green, blue+b.blue, alpha+b.alpha); }
void operator+=(const OffsetInfo& b) { red+=b.red; green+=b.green; blue+=b.blue; alpha+=b.alpha; }
};
virtual ~DitherHandler() {}
/// Computes an offset to be added to the pixel value.
/// @param[in] x X coordinate of the pixel (may or may not be relevant to the handler).
/// @param[in] y Y coordinate of the pixel (may or may not be relevant to the handler).
/// @param[out] offLin Linear offset to add before any encoding steps
/// @param[out] offQnt Offset to add right before quantization (even after scaling)
virtual void getOffset(unsigned int x, unsigned int y, OffsetInfo& offLin, OffsetInfo& offQnt) = 0;
/// Informs the handler about the actual quantization error observed for one particular pixel.
/// @param[in] x X coordinate of the pixel (may or may not be relevant to the handler).
/// @param[in] y Y coordinate of the pixel (may or may not be relevant to the handler).
/// @param[in] err Linear quantization error.
virtual void setError(unsigned int x, unsigned int y, const OffsetInfo& err) {}
};
typedef boost::shared_ptr<DitherHandler> DitherHandlerPtr;
/// Factory class to get a dithering rule and state.
DitherHandlerPtr GetDitherHandler(int method, unsigned int imageWidth);
/// Factory class to get a no-op dithering rule.
DitherHandlerPtr GetNoOpDitherHandler();
/// Computes an offset to be added to a pixel value right before quantization (even after scaling).
/// The value returned by this function is based on a default stateless dithering rule.
float GetDitherOffset(unsigned int x, unsigned int y);
/*******************************************************************************/
/**
* Linear decoding function.
* This function maps an integer value in the range 0..max linearly to a floating-point value in the range 0..1.
* @param x value to decode
* @param max encoded value representing 1.0
*/
inline float IntDecode(unsigned int x, unsigned int max) { return float(x) / float(max); }
/**
* Generic decoding function.
* This function maps an integer value in the range 0..max to a floating-point value in the range 0..1
* using a specific transfer function (gamma curve).
* @param g transfer function (gamma curve) to use
* @param x value to decode
* @param max encoded value representing 1.0
*/
inline float IntDecode(const GammaCurvePtr& g, unsigned int x, unsigned int max) { return GammaCurve::Decode(g,IntDecode(x,max)); }
/**
* Linear encoding function.
* This function maps a floating-point value in the range 0..1 linearly to in an integer value in the range 0..max.
* @note Floating-point values outside the range 0..1 are clipped, mapping them to 0 or max, respectively.
* @param[in] x value to encode
* @param[in] max encoded value representing 1.0
*/
inline unsigned int IntEncode(float x, unsigned int max) { return (unsigned int)floor( clip(x,0.0f,1.0f) * float(max) + 0.5f ); }
/**
* Linear encoding function.
* This function maps a floating-point value in the range 0..1 linearly to in an integer value in the range 0..max.
* @note Floating-point values outside the range 0..1 are clipped, mapping them to 0 or max, respectively.
* @param[in] x value to encode
* @param[in] max encoded value representing 1.0
* @param[in] qOff offset to add before quantization
*/
inline unsigned int IntEncode(float x, unsigned int max, float qOff)
{
return IntEncode(x+qOff/float(max),max);
}
/**
* Linear encoding function.
* This function maps a floating-point value in the range 0..1 linearly to in an integer value in the range 0..max.
* @note Floating-point values outside the range 0..1 are clipped, mapping them to 0 or max, respectively.
* @param[in] x value to encode
* @param[in] max encoded value representing 1.0
* @param[in] qOff offset to add before quantization
* @param[out] err quantization error (including effects due to adding qOff)
*/
inline unsigned int IntEncode(float x, unsigned int max, float qOff, float& err)
{
unsigned int v = IntEncode(x,max,qOff);
err = clip(x,0.0f,1.0f) - IntDecode(v,max);
return v;
}
/**
* Generic encoding function.
* This function maps a floating-point value in the range 0..1 to in an integer value in the range 0..max.
* @note Floating-point values outside the range 0..1 (after applying the transfer function) are clipped,
* mapping them to 0 or max, respectively.
* @param[in] g transfer function (gamma curve) to use
* @param[in] x value to encode
* @param[in] max encoded value representing 1.0
*/
inline unsigned int IntEncode(const GammaCurvePtr& g, float x, unsigned int max) { return IntEncode(GammaCurve::Encode(g,x),max); }
/**
* Generic encoding function.
* This function maps a floating-point value in the range 0..1 to in an integer value in the range 0..max.
* @note Floating-point values outside the range 0..1 (after applying the transfer function) are clipped,
* mapping them to 0 or max, respectively.
* @param[in] g transfer function (gamma curve) to use
* @param[in] x value to encode
* @param[in] max encoded value representing 1.0
* @param[in] qOff offset to add before quantization
*/
inline unsigned int IntEncode(const GammaCurvePtr& g, float x, unsigned int max, float qOff)
{
return IntEncode(GammaCurve::Encode(g,x)+qOff/float(max),max);
}
/**
* Generic encoding function.
* This function maps a floating-point value in the range 0..1 to in an integer value in the range 0..max.
* @note Floating-point values outside the range 0..1 (after applying the transfer function) are clipped,
* mapping them to 0 or max, respectively.
* @param[in] g transfer function (gamma curve) to use
* @param[in] x value to encode
* @param[in] max encoded value representing 1.0
* @param[in] qOff offset to add before quantization
* @param[out] err quantization error (including effects due to adding qOff)
*/
inline unsigned int IntEncode(const GammaCurvePtr& g, float x, unsigned int max, float qOff, float& err)
{
unsigned int v = IntEncode(g,x,max,qOff);
err = clip(x,0.0f,1.0f) - IntDecode(g,v,max);
return v;
}
/*******************************************************************************/
// convenience functions for image file decoding
void SetEncodedGrayValue(Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, unsigned int max, unsigned int gray);
void SetEncodedGrayAValue(Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, unsigned int max, unsigned int gray, unsigned int alpha, bool premul = false);
void SetEncodedRGBValue(Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, unsigned int max, unsigned int red, unsigned int green, unsigned int blue);
void SetEncodedRGBAValue(Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, unsigned int max, unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha, bool premul = false);
void SetEncodedGrayValue(Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, float gray);
void SetEncodedGrayAValue(Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, float gray, float alpha, bool premul = false);
void SetEncodedRGBValue(Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, float red, float green, float blue);
void SetEncodedRGBAValue(Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, float red, float green, float blue, float alpha, bool premul = false);
// convenience functions for image file encoding
unsigned int GetEncodedGrayValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, unsigned int max, DitherHandler& dh);
void GetEncodedGrayAValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, unsigned int max, unsigned int& gray, unsigned int& alpha, DitherHandler& dh, bool premul = false);
void GetEncodedRGBValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, unsigned int max, unsigned int& red, unsigned int& green, unsigned int& blue, DitherHandler& dh);
void GetEncodedRGBAValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, unsigned int max, unsigned int& red, unsigned int& green, unsigned int& blue, unsigned int& alpha, DitherHandler& dh, bool premul = false);
float GetEncodedGrayValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&);
void GetEncodedGrayAValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, float& gray, float& alpha, bool premul = false);
void GetEncodedRGBValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, float& red, float& green, float& blue);
void GetEncodedRGBAValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr&, float& red, float& green, float& blue, float& alpha, bool premul = false);
}
#endif // POVRAY_BASE_IMAGE_ENCODING_H