//
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) Contributors to the OpenEXR Project.
//

#ifndef INCLUDED_IMF_MISC_H
#define INCLUDED_IMF_MISC_H

//-----------------------------------------------------------------------------
//
//	Miscellaneous helper functions for OpenEXR image file I/O
//
//-----------------------------------------------------------------------------

#include "ImfForward.h"

#include "ImfArray.h"
#include "ImfCompressor.h"
#include "ImfPixelType.h"

#include <cstddef>
#include <vector>

OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER

//
// Return the size of a single value of the indicated type,
// in the machine's native format.
//

IMF_EXPORT
int pixelTypeSize (PixelType type);

//
// Return the number of samples a channel with subsampling rate
// s has in the interval [a, b].  For example, a channel with
// subsampling rate 2 (and samples at 0, 2, 4, 6, 8, etc.) has
// 2 samples in the interval [1, 5] and three samples in the
// interval [2, 6].
//

IMF_EXPORT
int numSamples (int s, int a, int b);

//
// Build a table that lists, for each scanline in a file's
// data window, how many bytes are required to store all
// pixels in all channels in that scanline (assuming that
// the pixel data are tightly packed).
//

IMF_EXPORT
size_t
bytesPerLineTable (const Header& header, std::vector<size_t>& bytesPerLine);

//
// Get the sample count for pixel (x, y) using the array base
// pointer, xStride and yStride.
//

inline int&
sampleCount (char* base, int xStride, int yStride, int x, int y)
{
    char* ptr    = base + y * ptrdiff_t (yStride) + x * ptrdiff_t (xStride);
    int*  intPtr = (int*) ptr;

    return *intPtr;
}

inline const int&
sampleCount (const char* base, int xStride, int yStride, int x, int y)
{
    const char* ptr = base + y * ptrdiff_t (yStride) + x * ptrdiff_t (xStride);
    int*        intPtr = (int*) ptr;

    return *intPtr;
}

//
// Build a table that lists, for each scanline in a DEEP file's
// data window, how many bytes are required to store all
// pixels in all channels in scanlines ranged in [minY, maxY]
// (assuming that the pixel data are tightly packed).
//

IMF_EXPORT
size_t bytesPerDeepLineTable (
    const Header&        header,
    int                  minY,
    int                  maxY,
    const char*          base,
    int                  xStride,
    int                  yStride,
    std::vector<size_t>& bytesPerLine);

//
// Build a table that lists, for each scanline in a DEEP file's
// data window, how many bytes are required to store all
// pixels in all channels in every scanline (assuming that
// the pixel data are tightly packed).
//

IMF_EXPORT
size_t bytesPerDeepLineTable (
    const Header&        header,
    char*                base,
    int                  xStride,
    int                  yStride,
    std::vector<size_t>& bytesPerLine);

//
// For scanline-based files, pixels are read or written in
// in multi-scanline blocks.  Internally, class OutputFile
// and class ScanLineInputFile store a block of scan lines
// in a "line buffer".  Function offsetInLineBufferTable()
// builds a table that lists, scanlines within range
// [scanline1, scanline2], the location of the pixel data
// for the scanline relative to the beginning of the line buffer,
// where scanline1 = 0 represents the first line in the DATA WINDOW.
// The one without specifying the range will make scanline1 = 0
// and scanline2 = bytesPerLine.size().
//

IMF_EXPORT
void offsetInLineBufferTable (
    const std::vector<size_t>& bytesPerLine,
    int                        scanline1,
    int                        scanline2,
    int                        linesInLineBuffer,
    std::vector<size_t>&       offsetInLineBuffer);

IMF_EXPORT
void offsetInLineBufferTable (
    const std::vector<size_t>& bytesPerLine,
    int                        linesInLineBuffer,
    std::vector<size_t>&       offsetInLineBuffer);

//
// For a scanline-based file, compute the range of scanlines
// that occupy the same line buffer as a given scanline, y.
// (minY is the minimum y coordinate of the file's data window.)
//

IMF_EXPORT int lineBufferMinY (int y, int minY, int linesInLineBuffer);
IMF_EXPORT int lineBufferMaxY (int y, int minY, int linesInLineBuffer);

//
// Return a compressor's data format (Compressor::NATIVE or Compressor::XDR).
// If compressor is 0, return Compressor::XDR.
//

IMF_EXPORT
Compressor::Format defaultFormat (Compressor* compressor);

//
// Return the number of scan lines a compressor wants to compress
// or uncompress at once.  If compressor is 0, return 1.
//

IMF_EXPORT
int numLinesInBuffer (Compressor* compressor);

//
// Copy a single channel of a horizontal row of pixels from an
// input file's internal line buffer or tile buffer into a
// frame buffer slice.  If necessary, perform on-the-fly data
// type conversion.
//
//    readPtr		initially points to the beginning of the
//			data in the line or tile buffer. readPtr
//			is advanced as the pixel data are copied;
//			when copyIntoFrameBuffer() returns,
//			readPtr points just past the end of the
//			copied data.
//
//    writePtr, endPtr	point to the lefmost and rightmost pixels
//			in the frame buffer slice
//
//    xStride		the xStride for the frame buffer slice
//
//    format		indicates if the line or tile buffer is
//			in NATIVE or XDR format.
//
//    typeInFrameBuffer the pixel data type of the frame buffer slice
//
//    typeInFile        the pixel data type in the input file's channel
//

IMF_EXPORT
void copyIntoFrameBuffer (
    const char*&       readPtr,
    char*              writePtr,
    char*              endPtr,
    size_t             xStride,
    bool               fill,
    double             fillValue,
    Compressor::Format format,
    PixelType          typeInFrameBuffer,
    PixelType          typeInFile);

//
// Copy a single channel of a horizontal row of pixels from an
// input file's internal line buffer or tile buffer into a
// frame buffer slice.  If necessary, perform on-the-fly data
// type conversion.
//
//    readPtr             initially points to the beginning of the
//                        data in the line or tile buffer. readPtr
//                        is advanced as the pixel data are copied;
//                        when copyIntoFrameBuffer() returns,
//                        readPtr points just past the end of the
//                        copied data.
//
//    base                point to each pixel in the framebuffer
//
//    sampleCountBase,    provide the number of samples in each pixel
//    sampleCountXStride,
//    sampleCountYStride
//
//    y                   the scanline to copy. The coordinate is
//                        relative to the datawindow.min.y.
//
//    minX, maxX          used to indicate which pixels in the scanline
//                        will be copied.
//
//    xOffsetForSampleCount,    used to offset the sample count array
//    yOffsetForSampleCount,    and the base array.
//    xOffsetForData,
//    yOffsetForData
//
//    xStride             the xStride for the frame buffer slice
//
//    format              indicates if the line or tile buffer is
//                        in NATIVE or XDR format.
//
//    typeInFrameBuffer   the pixel data type of the frame buffer slice
//
//    typeInFile          the pixel data type in the input file's channel
//

IMF_EXPORT
void copyIntoDeepFrameBuffer (
    const char*&       readPtr,
    char*              base,
    const char*        sampleCountBase,
    ptrdiff_t          sampleCountXStride,
    ptrdiff_t          sampleCountYStride,
    int                y,
    int                minX,
    int                maxX,
    int                xOffsetForSampleCount,
    int                yOffsetForSampleCount,
    int                xOffsetForData,
    int                yOffsetForData,
    ptrdiff_t          xStride,
    ptrdiff_t          xPointerStride,
    ptrdiff_t          yPointerStride,
    bool               fill,
    double             fillValue,
    Compressor::Format format,
    PixelType          typeInFrameBuffer,
    PixelType          typeInFile);

//
// Given a pointer into a an input file's line buffer or tile buffer,
// skip over the data for xSize pixels of type typeInFile.
// readPtr initially points to the beginning of the data to be skipped;
// when skipChannel() returns, readPtr points just past the end of the
// skipped data.
//

IMF_EXPORT
void skipChannel (const char*& readPtr, PixelType typeInFile, size_t xSize);

//
// Convert an array of pixel data from the machine's native
// representation to XDR format.
//
//    toPtr, fromPtr	initially point to the beginning of the input
//			and output pixel data arrays; when convertInPlace()
//			returns, toPtr and fromPtr point just past the
//			end of the input and output arrays.
// 			If the native representation of the data has the
//			same size as the XDR data, then the conversion
//			can take in place, without an intermediate
//			temporary buffer (toPtr and fromPtr can point
//			to the same location).
//
//    type		the pixel data type
//
//    numPixels		number of pixels in the input and output arrays
//

IMF_EXPORT
void convertInPlace (
    char*& toPtr, const char*& fromPtr, PixelType type, size_t numPixels);

//
// Copy a single channel of a horizontal row of pixels from a
// a frame buffer into an output file's internal line buffer or
// tile buffer.
//
//    writePtr		initially points to the beginning of the
//			data in the line or tile buffer. writePtr
//			is advanced as the pixel data are copied;
//			when copyFromFrameBuffer() returns,
//			writePtr points just past the end of the
//			copied data.
//
//    readPtr, endPtr	point to the lefmost and rightmost pixels
//			in the frame buffer slice
//
//    xStride		the xStride for the frame buffer slice
//
//    format		indicates if the line or tile buffer is
//			in NATIVE or XDR format.
//
//    type              the pixel data type in the frame buffer
//			and in the output file's channel (function
//			copyFromFrameBuffer() doesn't do on-the-fly
//			data type conversion)
//

IMF_EXPORT
void copyFromFrameBuffer (
    char*&             writePtr,
    const char*&       readPtr,
    const char*        endPtr,
    size_t             xStride,
    Compressor::Format format,
    PixelType          type);

//
// Copy a single channel of a horizontal row of pixels from a
// a frame buffer in a deep data file into an output file's
// internal line buffer or tile buffer.
//
//    writePtr                  initially points to the beginning of the
//                              data in the line or tile buffer. writePtr
//                              is advanced as the pixel data are copied;
//                              when copyFromDeepFrameBuffer() returns,
//                              writePtr points just past the end of the
//                              copied data.
//
//    base                      the start pointer of each pixel in this channel.
//                              It points to the real data in FrameBuffer.
//                              It is different for different channels.
//                              dataWindowMinX and dataWindowMinY are involved in
//                              locating for base.
//
//    sampleCountBase,          used to locate the position to get
//    sampleCountXStride,       the number of samples for each pixel.
//    sampleCountYStride        Used to determine how far we should
//                              read based on the pointer provided by base.
//
//    y                         the scanline to copy. If we are dealing
//                              with a tiled deep file, then probably a portion
//                              of the scanline is copied.
//
//    xMin, xMax                used to indicate which pixels in the scanline
//                              will be copied.
//
//    xOffsetForSampleCount,    used to offset the sample count array
//    yOffsetForSampleCount,    and the base array.
//    xOffsetForData,
//    yOffsetForData
//
//    xStride                   the xStride for the frame buffer slice
//
//    format                    indicates if the line or tile buffer is
//                              in NATIVE or XDR format.
//
//    type                      the pixel data type in the frame buffer
//                              and in the output file's channel (function
//                              copyFromFrameBuffer() doesn't do on-the-fly
//                              data type conversion)
//

IMF_EXPORT
void copyFromDeepFrameBuffer (
    char*&             writePtr,
    const char*        base,
    char*              sampleCountBase,
    ptrdiff_t          sampleCountXStride,
    ptrdiff_t          sampleCountYStride,
    int                y,
    int                xMin,
    int                xMax,
    int                xOffsetForSampleCount,
    int                yOffsetForSampleCount,
    int                xOffsetForData,
    int                yOffsetForData,
    ptrdiff_t          sampleStride,
    ptrdiff_t          xStrideForData,
    ptrdiff_t          yStrideForData,
    Compressor::Format format,
    PixelType          type);

//
// Fill part of an output file's line buffer or tile buffer with
// zeroes.  This routine is called when an output file contains
// a channel for which the frame buffer contains no corresponding
// slice.
//
//    writePtr		initially points to the beginning of the
//			data in the line or tile buffer.  When
//			fillChannelWithZeroes() returns, writePtr
//			points just past the end of the zeroed
//			data.
//
//    format		indicates if the line or tile buffer is
//			in NATIVE or XDR format.
//
//    type              the pixel data type in the line or frame buffer.
//
//    xSize             number of pixels to be filled with zeroes.
//

IMF_EXPORT
void fillChannelWithZeroes (
    char*& writePtr, Compressor::Format format, PixelType type, size_t xSize);

IMF_EXPORT
bool usesLongNames (const Header& header);

//
// compute size of chunk offset table - for existing types, computes
// the chunk size from the image size, compression type, and tile
// description (for tiled types). If the type is not supported, uses
// the chunkCount attribute if present, or throws an exception
// otherwise
//

IMF_EXPORT
int getChunkOffsetTableSize (const Header& header);

//
// Convert a filename to a wide string.  This is useful for working with
// filenames on Windows.
//

IMF_EXPORT
std::wstring WidenFilename (const char* filename);

//
// Return the string that describes the major.minor.patch release version
//

IMF_EXPORT const char* getLibraryVersion ();

OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT

#endif