/*****************************************************************************/
// Copyright 2006-2019 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/

/** \file
 *  Support for working with image data in DNG SDK.
 */

/*****************************************************************************/

#ifndef __dng_image__
#define __dng_image__

/*****************************************************************************/

#include "dng_assertions.h"
#include "dng_classes.h"
#include "dng_pixel_buffer.h"
#include "dng_point.h"
#include "dng_rect.h"
#include "dng_tag_types.h"
#include "dng_types.h"
#include "dng_uncopyable.h"

/*****************************************************************************/

/// @brief Class to get resource acquisition is instantiation behavior for tile
/// buffers. Can be dirty or constant tile access.

class dng_tile_buffer: public dng_pixel_buffer,
                       private dng_uncopyable
    {

    protected:

        const dng_image &fImage;

        void *fRefData;

    protected:

        /// Obtain a tile from an image.
        /// \param image Image tile will come from.
        /// \param tile Rectangle denoting extent of tile.
        /// \param dirty Flag indicating whether this is read-only or read-write acesss.

        dng_tile_buffer (const dng_image &image,
                         const dng_rect &tile,
                         bool dirty);

        virtual ~dng_tile_buffer ();

    public:

        void SetRefData (void *refData)
            {
            fRefData = refData;
            }

        void * GetRefData () const
            {
            return fRefData;
            }

    };

/*****************************************************************************/

/// @brief Class to get resource acquisition is instantiation behavior for
/// constant (read-only) tile buffers.

class dng_const_tile_buffer: public dng_tile_buffer
    {

    public:

        /// Obtain a read-only tile from an image.
        /// \param image Image tile will come from.
        /// \param tile Rectangle denoting extent of tile.

        dng_const_tile_buffer (const dng_image &image,
                               const dng_rect &tile);

        virtual ~dng_const_tile_buffer ();

    };

/*****************************************************************************/

/// @brief Class to get resource acquisition is instantiation behavior for
/// dirty (writable) tile buffers.

class dng_dirty_tile_buffer: public dng_tile_buffer
    {

    public:

        /// Obtain a writable tile from an image.
        /// \param image Image tile will come from.
        /// \param tile Rectangle denoting extent of tile.

        dng_dirty_tile_buffer (dng_image &image,
                               const dng_rect &tile);

        virtual ~dng_dirty_tile_buffer ();

    };

/*****************************************************************************/

/// @brief Base class for holding image data in DNG SDK. See dng_simple_image
/// for derived class most often used in DNG SDK.

class dng_image
    {

    friend class dng_tile_buffer;

    protected:

        // Bounds for this image.

        dng_rect fBounds;

        // Number of image planes.

        uint32 fPlanes;

        // Basic pixel type (TIFF tag type code).

        uint32 fPixelType;

    public:

        /// How to handle requests to get image areas outside the image bounds.

        enum edge_option
            {

            /// Leave edge pixels unchanged.

            edge_none,

            /// Pad with zeros.

            edge_zero,

            /// Repeat edge pixels.

            edge_repeat,

            /// Repeat edge pixels, except for last plane which is zero padded.

            edge_repeat_zero_last,

            /// Wrap edge pixels horizontally, repeat edge pixels vertically.

            edge_wrap_horizontal,

            /// Wrap edge pixels vertically, repeat edge pixels horizontally.

            edge_wrap_vertical,

            /// Wrap edge pixels in all directions (horizontal, vertical,
            /// diagonal).

            edge_wrap_all

            };

    protected:

        dng_image (const dng_rect &bounds,
                   uint32 planes,
                   uint32 pixelType);

    public:

        virtual ~dng_image ();

        virtual dng_image * Clone () const;

        /// Getter method for bounds of an image.

        const dng_rect & Bounds () const
            {
            return fBounds;
            }

        /// Getter method for size of an image.

        dng_point Size () const
            {
            return Bounds ().Size ();
            }

        /// Getter method for width of an image.

        uint32 Width () const
            {
            return Bounds ().W ();
            }

        /// Getter method for height of an image.

        uint32 Height () const
            {
            return Bounds ().H ();
            }

        /// Getter method for number of planes in an image.

        uint32 Planes () const
            {
            return fPlanes;
            }

        /// Getter for pixel type.
        /// \retval See dng_tagtypes.h . Valid values are ttByte, ttShort, ttSShort,
        /// ttLong, ttFloat .

        uint32 PixelType () const
            {
            return fPixelType;
            }

        /// Setter for pixel type.
        /// \param pixelType The new pixel type .

        virtual void SetPixelType (uint32 pixelType);

        /// Getter for pixel size.
        /// \retval Size, in bytes, of pixel type for this image .

        uint32 PixelSize () const;

        /// Getter for pixel range.
        /// For unsigned types, range is 0 to return value.
        /// For signed types, range is return value - 0x8000U.
        /// For ttFloat type, pixel range is 0.0 to 1.0 and this routine returns 1.

        uint32 PixelRange () const;

        /// Getter for best "tile stride" for accessing image.

        virtual dng_rect RepeatingTile () const;

        /// Get a pixel buffer of data on image with proper edge padding.
        /// \param buffer Receives resulting pixel buffer.
        /// \param edgeOption edge_option describing how to pad edges.
        /// \param repeatV Amount of repeated padding needed in vertical for
        /// edge_repeat, edge_repeat_zero_last, and edge_wrap_horizontal
        /// edgeOption cases.
        /// \param repeatH Amount of repeated padding needed in horizontal for
        /// edge_repeat, edge_repeat_zero_last, and edge_wrap_vertical
        /// edgeOption cases.

        void Get (dng_pixel_buffer &buffer,
                  edge_option edgeOption = edge_none,
                  uint32 repeatV = 1,
                  uint32 repeatH = 1) const;

        /// Put a pixel buffer into image.
        /// \param buffer Pixel buffer to copy from.

        void Put (const dng_pixel_buffer &buffer);

        /// Shrink bounds of image to given rectangle.
        /// \param r Rectangle to crop to.

        virtual void Trim (const dng_rect &r);

        /// Rotate image to reflect given orientation change.
        /// \param orientation Directive to rotate image in a certain way.

        virtual void Rotate (const dng_orientation &orientation);

        /// Offset image.
        /// \param offset Offset amount.

        virtual void Offset (const dng_point &offset);

        /// Copy image data from an area of one image to same area of another.
        /// \param src Image to copy from.
        /// \param area Rectangle of images to copy.
        /// \param srcPlane Plane to start copying in src.
        /// \param dstPlane Plane to start copying in this.
        /// \param planes Number of planes to copy.

        void CopyArea (const dng_image &src,
                       const dng_rect &area,
                       uint32 srcPlane,
                       uint32 dstPlane,
                       uint32 planes)
            {

            DoCopyArea (src, area, srcPlane, dstPlane, planes);

            }

        /// Copy image data from an area of one image to same area of another.
        /// \param src Image to copy from.
        /// \param area Rectangle of images to copy.
        /// \param plane Plane to start copying in src and this.
        /// \param planes Number of planes to copy.

        void CopyArea (const dng_image &src,
                       const dng_rect &area,
                       uint32 plane,
                       uint32 planes)
            {

            DoCopyArea (src, area, plane, plane, planes);

            }

        /// Return true if the contents of an area of the image are the same as those of another.
        /// \param rhs Image to compare against.
        /// \param area Rectangle of image to test.
        /// \param plane Plane to start comparing.
        /// \param planes Number of planes to compare.

        virtual bool EqualArea (const dng_image &rhs,
                                const dng_rect &area,
                                uint32 plane,
                                uint32 planes) const;

        // Routines to set the entire image to a constant value.

        void SetConstant_uint8 (uint8 value,
                                const dng_rect &area)
            {

            DNG_ASSERT (fPixelType == ttByte, "Mismatched pixel type");

            SetConstant ((uint32) value, area);

            }

        void SetConstant_uint8 (uint8 value)
            {
            SetConstant (value, Bounds ());
            }

        void SetConstant_uint16 (uint16 value,
                                 const dng_rect &area)
            {

            DNG_ASSERT (fPixelType == ttShort, "Mismatched pixel type");

            SetConstant ((uint32) value, area);

            }

        void SetConstant_uint16 (uint16 value)
            {
            SetConstant_uint16 (value, Bounds ());
            }

        void SetConstant_int16 (int16 value,
                                const dng_rect &area)
            {

            DNG_ASSERT (fPixelType == ttSShort, "Mismatched pixel type");

            SetConstant ((uint32) (uint16) value, area);

            }

        void SetConstant_int16 (int16 value)
            {
            SetConstant_int16 (value, Bounds ());
            }

        void SetConstant_uint32 (uint32 value,
                                 const dng_rect &area)
            {

            DNG_ASSERT (fPixelType == ttLong, "Mismatched pixel type");

            SetConstant (value, area);

            }

        void SetConstant_uint32 (uint32 value)
            {
            SetConstant_uint32 (value, Bounds ());
            }

        void SetConstant_real32 (real32 value,
                                 const dng_rect &area)
            {

            DNG_ASSERT (fPixelType == ttFloat, "Mismatched pixel type");

            union
                {
                uint32 i;
                real32 f;
                } x;

            x.f = value;

            SetConstant (x.i, area);

            }

        void SetConstant_real32 (real32 value)
            {
            SetConstant_real32 (value, Bounds ());
            }

        void SetZero (const dng_rect &area)
            {
            SetConstant (0, area);
            }

        virtual void GetRepeat (dng_pixel_buffer &buffer,
                                const dng_rect &srcArea,
                                const dng_rect &dstArea) const;

    protected:

        virtual void AcquireTileBuffer (dng_tile_buffer &buffer,
                                        const dng_rect &area,
                                        bool dirty) const;

        virtual void ReleaseTileBuffer (dng_tile_buffer &buffer) const;

        virtual void DoGet (dng_pixel_buffer &buffer) const;

        virtual void DoPut (const dng_pixel_buffer &buffer);

        virtual void DoCopyArea (const dng_image &src,
                                 const dng_rect &area,
                                 uint32 srcPlane,
                                 uint32 dstPlane,
                                 uint32 planes);

        void GetEdge (dng_pixel_buffer &buffer,
                      edge_option edgeOption,
                      const dng_rect &srcArea,
                      const dng_rect &dstArea) const;

        virtual void SetConstant (uint32 value,
                                  const dng_rect &area);

    };

/*****************************************************************************/

#endif

/*****************************************************************************/
