mirror of http://192.168.1.51:8099/lmh188/twain3.0
2340 lines
57 KiB
C
2340 lines
57 KiB
C
/*====================================================================*
|
|
- Copyright (C) 2001 Leptonica. All rights reserved.
|
|
-
|
|
- Redistribution and use in source and binary forms, with or without
|
|
- modification, are permitted provided that the following conditions
|
|
- are met:
|
|
- 1. Redistributions of source code must retain the above copyright
|
|
- notice, this list of conditions and the following disclaimer.
|
|
- 2. Redistributions in binary form must reproduce the above
|
|
- copyright notice, this list of conditions and the following
|
|
- disclaimer in the documentation and/or other materials
|
|
- provided with the distribution.
|
|
-
|
|
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
|
|
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*====================================================================*/
|
|
|
|
/*!
|
|
* \file fpix1.c
|
|
* <pre>
|
|
*
|
|
* ---------------------------------------------------
|
|
* This file has these FPix, FPixa and DPix utilities:
|
|
* - creation and destruction
|
|
* - accessors
|
|
* - serialization and deserialization
|
|
* ---------------------------------------------------
|
|
*
|
|
* FPix Create/copy/destroy
|
|
* FPIX *fpixCreate()
|
|
* FPIX *fpixCreateTemplate()
|
|
* FPIX *fpixClone()
|
|
* FPIX *fpixCopy()
|
|
* l_int32 fpixResizeImageData()
|
|
* void fpixDestroy()
|
|
*
|
|
* FPix accessors
|
|
* l_int32 fpixGetDimensions()
|
|
* l_int32 fpixSetDimensions()
|
|
* l_int32 fpixGetWpl()
|
|
* l_int32 fpixSetWpl()
|
|
* l_int32 fpixGetRefcount()
|
|
* l_int32 fpixChangeRefcount()
|
|
* l_int32 fpixGetResolution()
|
|
* l_int32 fpixSetResolution()
|
|
* l_int32 fpixCopyResolution()
|
|
* l_float32 *fpixGetData()
|
|
* l_int32 fpixSetData()
|
|
* l_int32 fpixGetPixel()
|
|
* l_int32 fpixSetPixel()
|
|
*
|
|
* FPixa Create/copy/destroy
|
|
* FPIXA *fpixaCreate()
|
|
* FPIXA *fpixaCopy()
|
|
* void fpixaDestroy()
|
|
*
|
|
* FPixa addition
|
|
* l_int32 fpixaAddFPix()
|
|
* static l_int32 fpixaExtendArray()
|
|
* static l_int32 fpixaExtendArrayToSize()
|
|
*
|
|
* FPixa accessors
|
|
* l_int32 fpixaGetCount()
|
|
* l_int32 fpixaChangeRefcount()
|
|
* FPIX *fpixaGetFPix()
|
|
* l_int32 fpixaGetFPixDimensions()
|
|
* l_float32 *fpixaGetData()
|
|
* l_int32 fpixaGetPixel()
|
|
* l_int32 fpixaSetPixel()
|
|
*
|
|
* DPix Create/copy/destroy
|
|
* DPIX *dpixCreate()
|
|
* DPIX *dpixCreateTemplate()
|
|
* DPIX *dpixClone()
|
|
* DPIX *dpixCopy()
|
|
* l_int32 dpixResizeImageData()
|
|
* void dpixDestroy()
|
|
*
|
|
* DPix accessors
|
|
* l_int32 dpixGetDimensions()
|
|
* l_int32 dpixSetDimensions()
|
|
* l_int32 dpixGetWpl()
|
|
* l_int32 dpixSetWpl()
|
|
* l_int32 dpixGetRefcount()
|
|
* l_int32 dpixChangeRefcount()
|
|
* l_int32 dpixGetResolution()
|
|
* l_int32 dpixSetResolution()
|
|
* l_int32 dpixCopyResolution()
|
|
* l_float64 *dpixGetData()
|
|
* l_int32 dpixSetData()
|
|
* l_int32 dpixGetPixel()
|
|
* l_int32 dpixSetPixel()
|
|
*
|
|
* FPix serialized I/O
|
|
* FPIX *fpixRead()
|
|
* FPIX *fpixReadStream()
|
|
* FPIX *fpixReadMem()
|
|
* l_int32 fpixWrite()
|
|
* l_int32 fpixWriteStream()
|
|
* l_int32 fpixWriteMem()
|
|
* FPIX *fpixEndianByteSwap()
|
|
*
|
|
* DPix serialized I/O
|
|
* DPIX *dpixRead()
|
|
* DPIX *dpixReadStream()
|
|
* DPIX *dpixReadMem()
|
|
* l_int32 dpixWrite()
|
|
* l_int32 dpixWriteStream()
|
|
* l_int32 dpixWriteMem()
|
|
* DPIX *dpixEndianByteSwap()
|
|
*
|
|
* Print FPix (subsampled, for debugging)
|
|
* l_int32 fpixPrintStream()
|
|
* </pre>
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "allheaders.h"
|
|
|
|
/* Bounds on initial array size */
|
|
static const l_uint32 MaxPtrArraySize = 100000;
|
|
static const l_int32 InitialPtrArraySize = 20; /*!< n'importe quoi */
|
|
|
|
/* Static functions */
|
|
static l_int32 fpixaExtendArray(FPIXA *fpixa);
|
|
static l_int32 fpixaExtendArrayToSize(FPIXA *fpixa, l_int32 size);
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* FPix Create/copy/destroy *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief fpixCreate()
|
|
*
|
|
* \param[in] width, height
|
|
* \return fpixd with data allocated and initialized to 0, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Makes a FPix of specified size, with the data array
|
|
* allocated and initialized to 0.
|
|
* (2) The number of pixels must be less than 2^29.
|
|
* </pre>
|
|
*/
|
|
FPIX *
|
|
fpixCreate(l_int32 width,
|
|
l_int32 height)
|
|
{
|
|
l_float32 *data;
|
|
l_uint64 npix64;
|
|
FPIX *fpixd;
|
|
|
|
PROCNAME("fpixCreate");
|
|
|
|
if (width <= 0)
|
|
return (FPIX *)ERROR_PTR("width must be > 0", procName, NULL);
|
|
if (height <= 0)
|
|
return (FPIX *)ERROR_PTR("height must be > 0", procName, NULL);
|
|
|
|
/* Avoid overflow in malloc arg, malicious or otherwise */
|
|
npix64 = (l_uint64)width * (l_uint64)height; /* # of 4-byte pixels */
|
|
if (npix64 >= (1LL << 29)) {
|
|
L_ERROR("requested w = %d, h = %d\n", procName, width, height);
|
|
return (FPIX *)ERROR_PTR("requested bytes >= 2^31", procName, NULL);
|
|
}
|
|
|
|
fpixd = (FPIX *)LEPT_CALLOC(1, sizeof(FPIX));
|
|
fpixSetDimensions(fpixd, width, height);
|
|
fpixSetWpl(fpixd, width); /* 4-byte words */
|
|
fpixd->refcount = 1;
|
|
|
|
data = (l_float32 *)LEPT_CALLOC((size_t)width * height, sizeof(l_float32));
|
|
if (!data) {
|
|
fpixDestroy(&fpixd);
|
|
return (FPIX *)ERROR_PTR("calloc fail for data", procName, NULL);
|
|
}
|
|
fpixSetData(fpixd, data);
|
|
return fpixd;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixCreateTemplate()
|
|
*
|
|
* \param[in] fpixs
|
|
* \return fpixd, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Makes a FPix of the same size as the input FPix, with the
|
|
* data array allocated and initialized to 0.
|
|
* (2) Copies the resolution.
|
|
* </pre>
|
|
*/
|
|
FPIX *
|
|
fpixCreateTemplate(FPIX *fpixs)
|
|
{
|
|
l_int32 w, h;
|
|
FPIX *fpixd;
|
|
|
|
PROCNAME("fpixCreateTemplate");
|
|
|
|
if (!fpixs)
|
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
|
|
|
fpixGetDimensions(fpixs, &w, &h);
|
|
if ((fpixd = fpixCreate(w, h)) == NULL)
|
|
return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
|
|
fpixCopyResolution(fpixd, fpixs);
|
|
return fpixd;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixClone()
|
|
*
|
|
* \param[in] fpix
|
|
* \return same fpix ptr, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) See pixClone() for definition and usage.
|
|
* </pre>
|
|
*/
|
|
FPIX *
|
|
fpixClone(FPIX *fpix)
|
|
{
|
|
PROCNAME("fpixClone");
|
|
|
|
if (!fpix)
|
|
return (FPIX *)ERROR_PTR("fpix not defined", procName, NULL);
|
|
fpixChangeRefcount(fpix, 1);
|
|
|
|
return fpix;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixCopy()
|
|
*
|
|
* \param[in] fpixd [optional] can be null, or equal to fpixs,
|
|
* or different from fpixs
|
|
* \param[in] fpixs
|
|
* \return fpixd, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) There are three cases:
|
|
* (a) fpixd == null (makes a new fpix; refcount = 1)
|
|
* (b) fpixd == fpixs (no-op)
|
|
* (c) fpixd != fpixs (data copy; no change in refcount)
|
|
* If the refcount of fpixd > 1, case (c) will side-effect
|
|
* these handles.
|
|
* (2) The general pattern of use is:
|
|
* fpixd = fpixCopy(fpixd, fpixs);
|
|
* This will work for all three cases.
|
|
* For clarity when the case is known, you can use:
|
|
* (a) fpixd = fpixCopy(NULL, fpixs);
|
|
* (c) fpixCopy(fpixd, fpixs);
|
|
* (3) For case (c), we check if fpixs and fpixd are the same size.
|
|
* If so, the data is copied directly.
|
|
* Otherwise, the data is reallocated to the correct size
|
|
* and the copy proceeds. The refcount of fpixd is unchanged.
|
|
* (4) This operation, like all others that may involve a pre-existing
|
|
* fpixd, will side-effect any existing clones of fpixd.
|
|
* </pre>
|
|
*/
|
|
FPIX *
|
|
fpixCopy(FPIX *fpixd, /* can be null */
|
|
FPIX *fpixs)
|
|
{
|
|
l_int32 w, h, bytes;
|
|
l_float32 *datas, *datad;
|
|
|
|
PROCNAME("fpixCopy");
|
|
|
|
if (!fpixs)
|
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
|
|
if (fpixs == fpixd)
|
|
return fpixd;
|
|
|
|
/* Total bytes in image data */
|
|
fpixGetDimensions(fpixs, &w, &h);
|
|
bytes = 4 * w * h;
|
|
|
|
/* If we're making a new fpix ... */
|
|
if (!fpixd) {
|
|
if ((fpixd = fpixCreateTemplate(fpixs)) == NULL)
|
|
return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
|
|
datas = fpixGetData(fpixs);
|
|
datad = fpixGetData(fpixd);
|
|
memcpy(datad, datas, bytes);
|
|
return fpixd;
|
|
}
|
|
|
|
/* Reallocate image data if sizes are different */
|
|
fpixResizeImageData(fpixd, fpixs);
|
|
|
|
/* Copy data */
|
|
fpixCopyResolution(fpixd, fpixs);
|
|
datas = fpixGetData(fpixs);
|
|
datad = fpixGetData(fpixd);
|
|
memcpy(datad, datas, bytes);
|
|
return fpixd;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixResizeImageData()
|
|
*
|
|
* \param[in] fpixd, fpixs
|
|
* \return 0 if OK, 1 on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) If the data sizes differ, this destroys the existing
|
|
* data in fpixd and allocates a new, uninitialized, data array
|
|
* of the same size as the data in fpixs. Otherwise, this
|
|
* doesn't do anything.
|
|
* </pre>
|
|
*/
|
|
l_ok
|
|
fpixResizeImageData(FPIX *fpixd,
|
|
FPIX *fpixs)
|
|
{
|
|
l_int32 ws, hs, wd, hd, bytes;
|
|
l_float32 *data;
|
|
|
|
PROCNAME("fpixResizeImageData");
|
|
|
|
if (!fpixs)
|
|
return ERROR_INT("fpixs not defined", procName, 1);
|
|
if (!fpixd)
|
|
return ERROR_INT("fpixd not defined", procName, 1);
|
|
|
|
fpixGetDimensions(fpixs, &ws, &hs);
|
|
fpixGetDimensions(fpixd, &wd, &hd);
|
|
if (ws == wd && hs == hd) /* nothing to do */
|
|
return 0;
|
|
|
|
fpixSetDimensions(fpixd, ws, hs);
|
|
fpixSetWpl(fpixd, ws);
|
|
bytes = 4 * ws * hs;
|
|
data = fpixGetData(fpixd);
|
|
if (data) LEPT_FREE(data);
|
|
if ((data = (l_float32 *)LEPT_MALLOC(bytes)) == NULL)
|
|
return ERROR_INT("LEPT_MALLOC fail for data", procName, 1);
|
|
fpixSetData(fpixd, data);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixDestroy()
|
|
*
|
|
* \param[in,out] pfpix will be set to null before returning
|
|
* \return void
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Decrements the ref count and, if 0, destroys the fpix.
|
|
* (2) Always nulls the input ptr.
|
|
* </pre>
|
|
*/
|
|
void
|
|
fpixDestroy(FPIX **pfpix)
|
|
{
|
|
l_float32 *data;
|
|
FPIX *fpix;
|
|
|
|
PROCNAME("fpixDestroy");
|
|
|
|
if (!pfpix) {
|
|
L_WARNING("ptr address is null!\n", procName);
|
|
return;
|
|
}
|
|
|
|
if ((fpix = *pfpix) == NULL)
|
|
return;
|
|
|
|
/* Decrement the ref count. If it is 0, destroy the fpix. */
|
|
fpixChangeRefcount(fpix, -1);
|
|
if (fpixGetRefcount(fpix) <= 0) {
|
|
if ((data = fpixGetData(fpix)) != NULL)
|
|
LEPT_FREE(data);
|
|
LEPT_FREE(fpix);
|
|
}
|
|
|
|
*pfpix = NULL;
|
|
return;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* FPix Accessors *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief fpixGetDimensions()
|
|
*
|
|
* \param[in] fpix
|
|
* \param[out] pw, ph [optional] each can be null
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixGetDimensions(FPIX *fpix,
|
|
l_int32 *pw,
|
|
l_int32 *ph)
|
|
{
|
|
PROCNAME("fpixGetDimensions");
|
|
|
|
if (!pw && !ph)
|
|
return ERROR_INT("no return val requested", procName, 1);
|
|
if (pw) *pw = 0;
|
|
if (ph) *ph = 0;
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
if (pw) *pw = fpix->w;
|
|
if (ph) *ph = fpix->h;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixSetDimensions()
|
|
*
|
|
* \param[in] fpix
|
|
* \param[in] w, h
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixSetDimensions(FPIX *fpix,
|
|
l_int32 w,
|
|
l_int32 h)
|
|
{
|
|
PROCNAME("fpixSetDimensions");
|
|
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
fpix->w = w;
|
|
fpix->h = h;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixGetWpl()
|
|
*
|
|
* \param[in] fpix
|
|
* \return wpl, or UNDEF on error
|
|
*/
|
|
l_int32
|
|
fpixGetWpl(FPIX *fpix)
|
|
{
|
|
PROCNAME("fpixGetWpl");
|
|
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, UNDEF);
|
|
return fpix->wpl;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixSetWpl()
|
|
*
|
|
* \param[in] fpix
|
|
* \param[in] wpl
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixSetWpl(FPIX *fpix,
|
|
l_int32 wpl)
|
|
{
|
|
PROCNAME("fpixSetWpl");
|
|
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
fpix->wpl = wpl;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixGetRefcount()
|
|
*
|
|
* \param[in] fpix
|
|
* \return refcount, or UNDEF on error
|
|
*/
|
|
l_int32
|
|
fpixGetRefcount(FPIX *fpix)
|
|
{
|
|
PROCNAME("fpixGetRefcount");
|
|
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, UNDEF);
|
|
return fpix->refcount;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixChangeRefcount()
|
|
*
|
|
* \param[in] fpix
|
|
* \param[in] delta
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixChangeRefcount(FPIX *fpix,
|
|
l_int32 delta)
|
|
{
|
|
PROCNAME("fpixChangeRefcount");
|
|
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
fpix->refcount += delta;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixGetResolution()
|
|
*
|
|
* \param[in] fpix
|
|
* \param[out] pxres, pyres [optional] x and y resolution
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixGetResolution(FPIX *fpix,
|
|
l_int32 *pxres,
|
|
l_int32 *pyres)
|
|
{
|
|
PROCNAME("fpixGetResolution");
|
|
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
if (pxres) *pxres = fpix->xres;
|
|
if (pyres) *pyres = fpix->yres;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixSetResolution()
|
|
*
|
|
* \param[in] fpix
|
|
* \param[in] xres, yres x and y resolution
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixSetResolution(FPIX *fpix,
|
|
l_int32 xres,
|
|
l_int32 yres)
|
|
{
|
|
PROCNAME("fpixSetResolution");
|
|
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
fpix->xres = xres;
|
|
fpix->yres = yres;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixCopyResolution()
|
|
*
|
|
* \param[in] fpixd, fpixs
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixCopyResolution(FPIX *fpixd,
|
|
FPIX *fpixs)
|
|
{
|
|
l_int32 xres, yres;
|
|
PROCNAME("fpixCopyResolution");
|
|
|
|
if (!fpixs || !fpixd)
|
|
return ERROR_INT("fpixs and fpixd not both defined", procName, 1);
|
|
|
|
fpixGetResolution(fpixs, &xres, &yres);
|
|
fpixSetResolution(fpixd, xres, yres);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixGetData()
|
|
*
|
|
* \param[in] fpix
|
|
* \return ptr to fpix data, or NULL on error
|
|
*/
|
|
l_float32 *
|
|
fpixGetData(FPIX *fpix)
|
|
{
|
|
PROCNAME("fpixGetData");
|
|
|
|
if (!fpix)
|
|
return (l_float32 *)ERROR_PTR("fpix not defined", procName, NULL);
|
|
return fpix->data;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixSetData()
|
|
*
|
|
* \param[in] fpix
|
|
* \param[in] data
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixSetData(FPIX *fpix,
|
|
l_float32 *data)
|
|
{
|
|
PROCNAME("fpixSetData");
|
|
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
fpix->data = data;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixGetPixel()
|
|
*
|
|
* \param[in] fpix
|
|
* \param[in] x,y pixel coords
|
|
* \param[out] pval pixel value
|
|
* \return 0 if OK; 1 or 2 on error
|
|
*
|
|
* Notes:
|
|
* (1) If the point is outside the image, this returns an error (2),
|
|
* with 0.0 in %pval. To avoid spamming output, it fails silently.
|
|
*/
|
|
l_ok
|
|
fpixGetPixel(FPIX *fpix,
|
|
l_int32 x,
|
|
l_int32 y,
|
|
l_float32 *pval)
|
|
{
|
|
l_int32 w, h;
|
|
|
|
PROCNAME("fpixGetPixel");
|
|
|
|
if (!pval)
|
|
return ERROR_INT("pval not defined", procName, 1);
|
|
*pval = 0.0;
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
fpixGetDimensions(fpix, &w, &h);
|
|
if (x < 0 || x >= w || y < 0 || y >= h)
|
|
return 2;
|
|
|
|
*pval = *(fpix->data + y * w + x);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixSetPixel()
|
|
*
|
|
* \param[in] fpix
|
|
* \param[in] x,y pixel coords
|
|
* \param[in] val pixel value
|
|
* \return 0 if OK; 1 or 2 on error
|
|
*
|
|
* Notes:
|
|
* (1) If the point is outside the image, this returns an error (2),
|
|
* with 0.0 in %pval. To avoid spamming output, it fails silently.
|
|
*/
|
|
l_ok
|
|
fpixSetPixel(FPIX *fpix,
|
|
l_int32 x,
|
|
l_int32 y,
|
|
l_float32 val)
|
|
{
|
|
l_int32 w, h;
|
|
|
|
PROCNAME("fpixSetPixel");
|
|
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
fpixGetDimensions(fpix, &w, &h);
|
|
if (x < 0 || x >= w || y < 0 || y >= h)
|
|
return 2;
|
|
|
|
*(fpix->data + y * w + x) = val;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* FPixa Create/copy/destroy *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief fpixaCreate()
|
|
*
|
|
* \param[in] n initial number of ptrs
|
|
* \return fpixa, or NULL on error
|
|
*/
|
|
FPIXA *
|
|
fpixaCreate(l_int32 n)
|
|
{
|
|
FPIXA *fpixa;
|
|
|
|
PROCNAME("fpixaCreate");
|
|
|
|
if (n <= 0 || n > MaxPtrArraySize)
|
|
n = InitialPtrArraySize;
|
|
|
|
fpixa = (FPIXA *)LEPT_CALLOC(1, sizeof(FPIXA));
|
|
fpixa->n = 0;
|
|
fpixa->nalloc = n;
|
|
fpixa->refcount = 1;
|
|
if ((fpixa->fpix = (FPIX **)LEPT_CALLOC(n, sizeof(FPIX *))) == NULL) {
|
|
fpixaDestroy(&fpixa);
|
|
return (FPIXA *)ERROR_PTR("fpixa ptrs not made", procName, NULL);
|
|
}
|
|
|
|
return fpixa;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaCopy()
|
|
*
|
|
* \param[in] fpixa
|
|
* \param[in] copyflag L_COPY, L_CLODE or L_COPY_CLONE
|
|
* \return new fpixa, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* copyflag may be one of
|
|
* ~ L_COPY makes a new fpixa and copies each fpix
|
|
* ~ L_CLONE gives a new ref-counted handle to the input fpixa
|
|
* ~ L_COPY_CLONE makes a new fpixa with clones of all fpix
|
|
* </pre>
|
|
*/
|
|
FPIXA *
|
|
fpixaCopy(FPIXA *fpixa,
|
|
l_int32 copyflag)
|
|
{
|
|
l_int32 i;
|
|
FPIX *fpixc;
|
|
FPIXA *fpixac;
|
|
|
|
PROCNAME("fpixaCopy");
|
|
|
|
if (!fpixa)
|
|
return (FPIXA *)ERROR_PTR("fpixa not defined", procName, NULL);
|
|
|
|
if (copyflag == L_CLONE) {
|
|
fpixaChangeRefcount(fpixa, 1);
|
|
return fpixa;
|
|
}
|
|
|
|
if (copyflag != L_COPY && copyflag != L_COPY_CLONE)
|
|
return (FPIXA *)ERROR_PTR("invalid copyflag", procName, NULL);
|
|
|
|
if ((fpixac = fpixaCreate(fpixa->n)) == NULL)
|
|
return (FPIXA *)ERROR_PTR("fpixac not made", procName, NULL);
|
|
for (i = 0; i < fpixa->n; i++) {
|
|
if (copyflag == L_COPY)
|
|
fpixc = fpixaGetFPix(fpixa, i, L_COPY);
|
|
else /* copy-clone */
|
|
fpixc = fpixaGetFPix(fpixa, i, L_CLONE);
|
|
fpixaAddFPix(fpixac, fpixc, L_INSERT);
|
|
}
|
|
|
|
return fpixac;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaDestroy()
|
|
*
|
|
* \param[in,out] pfpixa will be set to null before returning
|
|
* \return void
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Decrements the ref count and, if 0, destroys the fpixa.
|
|
* (2) Always nulls the input ptr.
|
|
* </pre>
|
|
*/
|
|
void
|
|
fpixaDestroy(FPIXA **pfpixa)
|
|
{
|
|
l_int32 i;
|
|
FPIXA *fpixa;
|
|
|
|
PROCNAME("fpixaDestroy");
|
|
|
|
if (pfpixa == NULL) {
|
|
L_WARNING("ptr address is NULL!\n", procName);
|
|
return;
|
|
}
|
|
|
|
if ((fpixa = *pfpixa) == NULL)
|
|
return;
|
|
|
|
/* Decrement the refcount. If it is 0, destroy the pixa. */
|
|
fpixaChangeRefcount(fpixa, -1);
|
|
if (fpixa->refcount <= 0) {
|
|
for (i = 0; i < fpixa->n; i++)
|
|
fpixDestroy(&fpixa->fpix[i]);
|
|
LEPT_FREE(fpixa->fpix);
|
|
LEPT_FREE(fpixa);
|
|
}
|
|
|
|
*pfpixa = NULL;
|
|
return;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* FPixa addition *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief fpixaAddFPix()
|
|
*
|
|
* \param[in] fpixa
|
|
* \param[in] fpix to be added
|
|
* \param[in] copyflag L_INSERT, L_COPY, L_CLONE
|
|
* \return 0 if OK; 1 on error
|
|
*/
|
|
l_ok
|
|
fpixaAddFPix(FPIXA *fpixa,
|
|
FPIX *fpix,
|
|
l_int32 copyflag)
|
|
{
|
|
l_int32 n;
|
|
FPIX *fpixc;
|
|
|
|
PROCNAME("fpixaAddFPix");
|
|
|
|
if (!fpixa)
|
|
return ERROR_INT("fpixa not defined", procName, 1);
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
if (copyflag == L_INSERT)
|
|
fpixc = fpix;
|
|
else if (copyflag == L_COPY)
|
|
fpixc = fpixCopy(NULL, fpix);
|
|
else if (copyflag == L_CLONE)
|
|
fpixc = fpixClone(fpix);
|
|
else
|
|
return ERROR_INT("invalid copyflag", procName, 1);
|
|
if (!fpixc)
|
|
return ERROR_INT("fpixc not made", procName, 1);
|
|
|
|
n = fpixaGetCount(fpixa);
|
|
if (n >= fpixa->nalloc)
|
|
fpixaExtendArray(fpixa);
|
|
fpixa->fpix[n] = fpixc;
|
|
fpixa->n++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaExtendArray()
|
|
*
|
|
* \param[in] fpixa
|
|
* \return 0 if OK; 1 on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Doubles the size of the fpixa ptr array.
|
|
* </pre>
|
|
*/
|
|
static l_int32
|
|
fpixaExtendArray(FPIXA *fpixa)
|
|
{
|
|
PROCNAME("fpixaExtendArray");
|
|
|
|
if (!fpixa)
|
|
return ERROR_INT("fpixa not defined", procName, 1);
|
|
|
|
return fpixaExtendArrayToSize(fpixa, 2 * fpixa->nalloc);
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaExtendArrayToSize()
|
|
*
|
|
* \param[in] fpixa
|
|
* \param[in] size new ptr array size
|
|
* \return 0 if OK; 1 on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) If necessary, reallocs new fpixa ptrs array to %size.
|
|
* </pre>
|
|
*/
|
|
static l_int32
|
|
fpixaExtendArrayToSize(FPIXA *fpixa,
|
|
l_int32 size)
|
|
{
|
|
PROCNAME("fpixaExtendArrayToSize");
|
|
|
|
if (!fpixa)
|
|
return ERROR_INT("fpixa not defined", procName, 1);
|
|
|
|
if (size > fpixa->nalloc) {
|
|
if ((fpixa->fpix = (FPIX **)reallocNew((void **)&fpixa->fpix,
|
|
sizeof(FPIX *) * fpixa->nalloc,
|
|
size * sizeof(FPIX *))) == NULL)
|
|
return ERROR_INT("new ptr array not returned", procName, 1);
|
|
fpixa->nalloc = size;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* FPixa accessors *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief fpixaGetCount()
|
|
*
|
|
* \param[in] fpixa
|
|
* \return count, or 0 if no pixa
|
|
*/
|
|
l_int32
|
|
fpixaGetCount(FPIXA *fpixa)
|
|
{
|
|
PROCNAME("fpixaGetCount");
|
|
|
|
if (!fpixa)
|
|
return ERROR_INT("fpixa not defined", procName, 0);
|
|
|
|
return fpixa->n;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaChangeRefcount()
|
|
*
|
|
* \param[in] fpixa
|
|
* \param[in] delta
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixaChangeRefcount(FPIXA *fpixa,
|
|
l_int32 delta)
|
|
{
|
|
PROCNAME("fpixaChangeRefcount");
|
|
|
|
if (!fpixa)
|
|
return ERROR_INT("fpixa not defined", procName, 1);
|
|
|
|
fpixa->refcount += delta;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaGetFPix()
|
|
*
|
|
* \param[in] fpixa
|
|
* \param[in] index to the index-th fpix
|
|
* \param[in] accesstype L_COPY or L_CLONE
|
|
* \return fpix, or NULL on error
|
|
*/
|
|
FPIX *
|
|
fpixaGetFPix(FPIXA *fpixa,
|
|
l_int32 index,
|
|
l_int32 accesstype)
|
|
{
|
|
PROCNAME("fpixaGetFPix");
|
|
|
|
if (!fpixa)
|
|
return (FPIX *)ERROR_PTR("fpixa not defined", procName, NULL);
|
|
if (index < 0 || index >= fpixa->n)
|
|
return (FPIX *)ERROR_PTR("index not valid", procName, NULL);
|
|
|
|
if (accesstype == L_COPY)
|
|
return fpixCopy(NULL, fpixa->fpix[index]);
|
|
else if (accesstype == L_CLONE)
|
|
return fpixClone(fpixa->fpix[index]);
|
|
else
|
|
return (FPIX *)ERROR_PTR("invalid accesstype", procName, NULL);
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaGetFPixDimensions()
|
|
*
|
|
* \param[in] fpixa
|
|
* \param[in] index to the index-th box
|
|
* \param[out] pw, ph [optional] each can be null
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixaGetFPixDimensions(FPIXA *fpixa,
|
|
l_int32 index,
|
|
l_int32 *pw,
|
|
l_int32 *ph)
|
|
{
|
|
FPIX *fpix;
|
|
|
|
PROCNAME("fpixaGetFPixDimensions");
|
|
|
|
if (!pw && !ph)
|
|
return ERROR_INT("no return val requested", procName, 1);
|
|
if (pw) *pw = 0;
|
|
if (ph) *ph = 0;
|
|
if (!fpixa)
|
|
return ERROR_INT("fpixa not defined", procName, 1);
|
|
if (index < 0 || index >= fpixa->n)
|
|
return ERROR_INT("index not valid", procName, 1);
|
|
|
|
if ((fpix = fpixaGetFPix(fpixa, index, L_CLONE)) == NULL)
|
|
return ERROR_INT("fpix not found!", procName, 1);
|
|
fpixGetDimensions(fpix, pw, ph);
|
|
fpixDestroy(&fpix);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaGetData()
|
|
*
|
|
* \param[in] fpixa
|
|
* \param[in] index into fpixa array
|
|
* \return data not a copy, or NULL on error
|
|
*/
|
|
l_float32 *
|
|
fpixaGetData(FPIXA *fpixa,
|
|
l_int32 index)
|
|
{
|
|
l_int32 n;
|
|
l_float32 *data;
|
|
FPIX *fpix;
|
|
|
|
PROCNAME("fpixaGetData");
|
|
|
|
if (!fpixa)
|
|
return (l_float32 *)ERROR_PTR("fpixa not defined", procName, NULL);
|
|
n = fpixaGetCount(fpixa);
|
|
if (index < 0 || index >= n)
|
|
return (l_float32 *)ERROR_PTR("invalid index", procName, NULL);
|
|
|
|
fpix = fpixaGetFPix(fpixa, index, L_CLONE);
|
|
data = fpixGetData(fpix);
|
|
fpixDestroy(&fpix);
|
|
return data;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaGetPixel()
|
|
*
|
|
* \param[in] fpixa
|
|
* \param[in] index into fpixa array
|
|
* \param[in] x,y pixel coords
|
|
* \param[out] pval pixel value
|
|
* \return 0 if OK; 1 on error
|
|
*/
|
|
l_ok
|
|
fpixaGetPixel(FPIXA *fpixa,
|
|
l_int32 index,
|
|
l_int32 x,
|
|
l_int32 y,
|
|
l_float32 *pval)
|
|
{
|
|
l_int32 n, ret;
|
|
FPIX *fpix;
|
|
|
|
PROCNAME("fpixaGetPixel");
|
|
|
|
if (!pval)
|
|
return ERROR_INT("pval not defined", procName, 1);
|
|
*pval = 0.0;
|
|
if (!fpixa)
|
|
return ERROR_INT("fpixa not defined", procName, 1);
|
|
n = fpixaGetCount(fpixa);
|
|
if (index < 0 || index >= n)
|
|
return ERROR_INT("invalid index into fpixa", procName, 1);
|
|
|
|
fpix = fpixaGetFPix(fpixa, index, L_CLONE);
|
|
ret = fpixGetPixel(fpix, x, y, pval);
|
|
fpixDestroy(&fpix);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixaSetPixel()
|
|
*
|
|
* \param[in] fpixa
|
|
* \param[in] index into fpixa array
|
|
* \param[in] x,y pixel coords
|
|
* \param[in] val pixel value
|
|
* \return 0 if OK; 1 on error
|
|
*/
|
|
l_ok
|
|
fpixaSetPixel(FPIXA *fpixa,
|
|
l_int32 index,
|
|
l_int32 x,
|
|
l_int32 y,
|
|
l_float32 val)
|
|
{
|
|
l_int32 n, ret;
|
|
FPIX *fpix;
|
|
|
|
PROCNAME("fpixaSetPixel");
|
|
|
|
if (!fpixa)
|
|
return ERROR_INT("fpixa not defined", procName, 1);
|
|
n = fpixaGetCount(fpixa);
|
|
if (index < 0 || index >= n)
|
|
return ERROR_INT("invalid index into fpixa", procName, 1);
|
|
|
|
fpix = fpixaGetFPix(fpixa, index, L_CLONE);
|
|
ret = fpixSetPixel(fpix, x, y, val);
|
|
fpixDestroy(&fpix);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* DPix Create/copy/destroy *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief dpixCreate()
|
|
*
|
|
* \param[in] width, height
|
|
* \return dpix with data allocated and initialized to 0, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Makes a DPix of specified size, with the data array
|
|
* allocated and initialized to 0.
|
|
* (2) The number of pixels must be less than 2^28.
|
|
* </pre>
|
|
*/
|
|
DPIX *
|
|
dpixCreate(l_int32 width,
|
|
l_int32 height)
|
|
{
|
|
l_float64 *data;
|
|
l_uint64 npix64;
|
|
DPIX *dpix;
|
|
|
|
PROCNAME("dpixCreate");
|
|
|
|
if (width <= 0)
|
|
return (DPIX *)ERROR_PTR("width must be > 0", procName, NULL);
|
|
if (height <= 0)
|
|
return (DPIX *)ERROR_PTR("height must be > 0", procName, NULL);
|
|
|
|
/* Avoid overflow in malloc arg, malicious or otherwise */
|
|
npix64 = (l_uint64)width * (l_uint64)height; /* # of 8 byte pixels */
|
|
if (npix64 >= (1LL << 28)) {
|
|
L_ERROR("requested w = %d, h = %d\n", procName, width, height);
|
|
return (DPIX *)ERROR_PTR("requested bytes >= 2^31", procName, NULL);
|
|
}
|
|
|
|
dpix = (DPIX *)LEPT_CALLOC(1, sizeof(DPIX));
|
|
dpixSetDimensions(dpix, width, height);
|
|
dpixSetWpl(dpix, width); /* 8 byte words */
|
|
dpix->refcount = 1;
|
|
|
|
data = (l_float64 *)LEPT_CALLOC((size_t)width * height, sizeof(l_float64));
|
|
if (!data) {
|
|
dpixDestroy(&dpix);
|
|
return (DPIX *)ERROR_PTR("calloc fail for data", procName, NULL);
|
|
}
|
|
dpixSetData(dpix, data);
|
|
return dpix;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixCreateTemplate()
|
|
*
|
|
* \param[in] dpixs
|
|
* \return dpixd, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Makes a DPix of the same size as the input DPix, with the
|
|
* data array allocated and initialized to 0.
|
|
* (2) Copies the resolution.
|
|
* </pre>
|
|
*/
|
|
DPIX *
|
|
dpixCreateTemplate(DPIX *dpixs)
|
|
{
|
|
l_int32 w, h;
|
|
DPIX *dpixd;
|
|
|
|
PROCNAME("dpixCreateTemplate");
|
|
|
|
if (!dpixs)
|
|
return (DPIX *)ERROR_PTR("dpixs not defined", procName, NULL);
|
|
|
|
dpixGetDimensions(dpixs, &w, &h);
|
|
dpixd = dpixCreate(w, h);
|
|
dpixCopyResolution(dpixd, dpixs);
|
|
return dpixd;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixClone()
|
|
*
|
|
* \param[in] dpix
|
|
* \return same dpix ptr, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) See pixClone() for definition and usage.
|
|
* </pre>
|
|
*/
|
|
DPIX *
|
|
dpixClone(DPIX *dpix)
|
|
{
|
|
PROCNAME("dpixClone");
|
|
|
|
if (!dpix)
|
|
return (DPIX *)ERROR_PTR("dpix not defined", procName, NULL);
|
|
dpixChangeRefcount(dpix, 1);
|
|
|
|
return dpix;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixCopy()
|
|
*
|
|
* \param[in] dpixd [optional] can be null, or equal to dpixs,
|
|
* or different from dpixs
|
|
* \param[in] dpixs
|
|
* \return dpixd, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) There are three cases:
|
|
* (a) dpixd == null (makes a new dpix; refcount = 1)
|
|
* (b) dpixd == dpixs (no-op)
|
|
* (c) dpixd != dpixs (data copy; no change in refcount)
|
|
* If the refcount of dpixd > 1, case (c) will side-effect
|
|
* these handles.
|
|
* (2) The general pattern of use is:
|
|
* dpixd = dpixCopy(dpixd, dpixs);
|
|
* This will work for all three cases.
|
|
* For clarity when the case is known, you can use:
|
|
* (a) dpixd = dpixCopy(NULL, dpixs);
|
|
* (c) dpixCopy(dpixd, dpixs);
|
|
* (3) For case (c), we check if dpixs and dpixd are the same size.
|
|
* If so, the data is copied directly.
|
|
* Otherwise, the data is reallocated to the correct size
|
|
* and the copy proceeds. The refcount of dpixd is unchanged.
|
|
* (4) This operation, like all others that may involve a pre-existing
|
|
* dpixd, will side-effect any existing clones of dpixd.
|
|
* </pre>
|
|
*/
|
|
DPIX *
|
|
dpixCopy(DPIX *dpixd, /* can be null */
|
|
DPIX *dpixs)
|
|
{
|
|
l_int32 w, h, bytes;
|
|
l_float64 *datas, *datad;
|
|
|
|
PROCNAME("dpixCopy");
|
|
|
|
if (!dpixs)
|
|
return (DPIX *)ERROR_PTR("dpixs not defined", procName, NULL);
|
|
if (dpixs == dpixd)
|
|
return dpixd;
|
|
|
|
/* Total bytes in image data */
|
|
dpixGetDimensions(dpixs, &w, &h);
|
|
bytes = 8 * w * h;
|
|
|
|
/* If we're making a new dpix ... */
|
|
if (!dpixd) {
|
|
if ((dpixd = dpixCreateTemplate(dpixs)) == NULL)
|
|
return (DPIX *)ERROR_PTR("dpixd not made", procName, NULL);
|
|
datas = dpixGetData(dpixs);
|
|
datad = dpixGetData(dpixd);
|
|
memcpy(datad, datas, bytes);
|
|
return dpixd;
|
|
}
|
|
|
|
/* Reallocate image data if sizes are different */
|
|
dpixResizeImageData(dpixd, dpixs);
|
|
|
|
/* Copy data */
|
|
dpixCopyResolution(dpixd, dpixs);
|
|
datas = dpixGetData(dpixs);
|
|
datad = dpixGetData(dpixd);
|
|
memcpy(datad, datas, bytes);
|
|
return dpixd;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixResizeImageData()
|
|
*
|
|
* \param[in] dpixd, dpixs
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixResizeImageData(DPIX *dpixd,
|
|
DPIX *dpixs)
|
|
{
|
|
l_int32 ws, hs, wd, hd, bytes;
|
|
l_float64 *data;
|
|
|
|
PROCNAME("dpixResizeImageData");
|
|
|
|
if (!dpixs)
|
|
return ERROR_INT("dpixs not defined", procName, 1);
|
|
if (!dpixd)
|
|
return ERROR_INT("dpixd not defined", procName, 1);
|
|
|
|
dpixGetDimensions(dpixs, &ws, &hs);
|
|
dpixGetDimensions(dpixd, &wd, &hd);
|
|
if (ws == wd && hs == hd) /* nothing to do */
|
|
return 0;
|
|
|
|
dpixSetDimensions(dpixd, ws, hs);
|
|
dpixSetWpl(dpixd, ws); /* 8 byte words */
|
|
bytes = 8 * ws * hs;
|
|
data = dpixGetData(dpixd);
|
|
if (data) LEPT_FREE(data);
|
|
if ((data = (l_float64 *)LEPT_MALLOC(bytes)) == NULL)
|
|
return ERROR_INT("LEPT_MALLOC fail for data", procName, 1);
|
|
dpixSetData(dpixd, data);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixDestroy()
|
|
*
|
|
* \param[in,out] pdpix will be set to null before returning
|
|
* \return void
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Decrements the ref count and, if 0, destroys the dpix.
|
|
* (2) Always nulls the input ptr.
|
|
* </pre>
|
|
*/
|
|
void
|
|
dpixDestroy(DPIX **pdpix)
|
|
{
|
|
l_float64 *data;
|
|
DPIX *dpix;
|
|
|
|
PROCNAME("dpixDestroy");
|
|
|
|
if (!pdpix) {
|
|
L_WARNING("ptr address is null!\n", procName);
|
|
return;
|
|
}
|
|
|
|
if ((dpix = *pdpix) == NULL)
|
|
return;
|
|
|
|
/* Decrement the ref count. If it is 0, destroy the dpix. */
|
|
dpixChangeRefcount(dpix, -1);
|
|
if (dpixGetRefcount(dpix) <= 0) {
|
|
if ((data = dpixGetData(dpix)) != NULL)
|
|
LEPT_FREE(data);
|
|
LEPT_FREE(dpix);
|
|
}
|
|
|
|
*pdpix = NULL;
|
|
return;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* DPix Accessors *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief dpixGetDimensions()
|
|
*
|
|
* \param[in] dpix
|
|
* \param[out] pw, ph [optional] each can be null
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixGetDimensions(DPIX *dpix,
|
|
l_int32 *pw,
|
|
l_int32 *ph)
|
|
{
|
|
PROCNAME("dpixGetDimensions");
|
|
|
|
if (!pw && !ph)
|
|
return ERROR_INT("no return val requested", procName, 1);
|
|
if (pw) *pw = 0;
|
|
if (ph) *ph = 0;
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
if (pw) *pw = dpix->w;
|
|
if (ph) *ph = dpix->h;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixSetDimensions()
|
|
*
|
|
* \param[in] dpix
|
|
* \param[in] w, h
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixSetDimensions(DPIX *dpix,
|
|
l_int32 w,
|
|
l_int32 h)
|
|
{
|
|
PROCNAME("dpixSetDimensions");
|
|
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
dpix->w = w;
|
|
dpix->h = h;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixGetWpl()
|
|
*
|
|
* \param[in] dpix
|
|
* \return wpl, or UNDEF on error
|
|
*/
|
|
l_int32
|
|
dpixGetWpl(DPIX *dpix)
|
|
{
|
|
PROCNAME("dpixGetWpl");
|
|
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
return dpix->wpl;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixSetWpl()
|
|
*
|
|
* \param[in] dpix
|
|
* \param[in] wpl
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixSetWpl(DPIX *dpix,
|
|
l_int32 wpl)
|
|
{
|
|
PROCNAME("dpixSetWpl");
|
|
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
|
|
dpix->wpl = wpl;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixGetRefcount()
|
|
*
|
|
* \param[in] dpix
|
|
* \return refcount, or UNDEF on error
|
|
*/
|
|
l_int32
|
|
dpixGetRefcount(DPIX *dpix)
|
|
{
|
|
PROCNAME("dpixGetRefcount");
|
|
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, UNDEF);
|
|
return dpix->refcount;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixChangeRefcount()
|
|
*
|
|
* \param[in] dpix
|
|
* \param[in] delta
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixChangeRefcount(DPIX *dpix,
|
|
l_int32 delta)
|
|
{
|
|
PROCNAME("dpixChangeRefcount");
|
|
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
|
|
dpix->refcount += delta;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixGetResolution()
|
|
*
|
|
* \param[in] dpix
|
|
* \param[out] pxres, pyres [optional] x and y resolution
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixGetResolution(DPIX *dpix,
|
|
l_int32 *pxres,
|
|
l_int32 *pyres)
|
|
{
|
|
PROCNAME("dpixGetResolution");
|
|
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
if (pxres) *pxres = dpix->xres;
|
|
if (pyres) *pyres = dpix->yres;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixSetResolution()
|
|
*
|
|
* \param[in] dpix
|
|
* \param[in] xres, yres x and y resolution
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixSetResolution(DPIX *dpix,
|
|
l_int32 xres,
|
|
l_int32 yres)
|
|
{
|
|
PROCNAME("dpixSetResolution");
|
|
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
|
|
dpix->xres = xres;
|
|
dpix->yres = yres;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixCopyResolution()
|
|
*
|
|
* \param[in] dpixd, dpixs
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixCopyResolution(DPIX *dpixd,
|
|
DPIX *dpixs)
|
|
{
|
|
l_int32 xres, yres;
|
|
PROCNAME("dpixCopyResolution");
|
|
|
|
if (!dpixs || !dpixd)
|
|
return ERROR_INT("dpixs and dpixd not both defined", procName, 1);
|
|
|
|
dpixGetResolution(dpixs, &xres, &yres);
|
|
dpixSetResolution(dpixd, xres, yres);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixGetData()
|
|
*
|
|
* \param[in] dpix
|
|
* \return ptr to dpix data, or NULL on error
|
|
*/
|
|
l_float64 *
|
|
dpixGetData(DPIX *dpix)
|
|
{
|
|
PROCNAME("dpixGetData");
|
|
|
|
if (!dpix)
|
|
return (l_float64 *)ERROR_PTR("dpix not defined", procName, NULL);
|
|
return dpix->data;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixSetData()
|
|
*
|
|
* \param[in] dpix
|
|
* \param[in] data
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixSetData(DPIX *dpix,
|
|
l_float64 *data)
|
|
{
|
|
PROCNAME("dpixSetData");
|
|
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
|
|
dpix->data = data;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixGetPixel()
|
|
*
|
|
* \param[in] dpix
|
|
* \param[in] x,y pixel coords
|
|
* \param[out] pval pixel value
|
|
* \return 0 if OK; 1 or 2 on error
|
|
*
|
|
* Notes:
|
|
* (1) If the point is outside the image, this returns an error (2),
|
|
* with 0.0 in %pval. To avoid spamming output, it fails silently.
|
|
*/
|
|
l_ok
|
|
dpixGetPixel(DPIX *dpix,
|
|
l_int32 x,
|
|
l_int32 y,
|
|
l_float64 *pval)
|
|
{
|
|
l_int32 w, h;
|
|
|
|
PROCNAME("dpixGetPixel");
|
|
|
|
if (!pval)
|
|
return ERROR_INT("pval not defined", procName, 1);
|
|
*pval = 0.0;
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
|
|
dpixGetDimensions(dpix, &w, &h);
|
|
if (x < 0 || x >= w || y < 0 || y >= h)
|
|
return 2;
|
|
|
|
*pval = *(dpix->data + y * w + x);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixSetPixel()
|
|
*
|
|
* \param[in] dpix
|
|
* \param[in] x,y pixel coords
|
|
* \param[in] val pixel value
|
|
* \return 0 if OK; 1 or 2 on error
|
|
*
|
|
* Notes:
|
|
* (1) If the point is outside the image, this returns an error (2),
|
|
* with 0.0 in %pval. To avoid spamming output, it fails silently.
|
|
*/
|
|
l_ok
|
|
dpixSetPixel(DPIX *dpix,
|
|
l_int32 x,
|
|
l_int32 y,
|
|
l_float64 val)
|
|
{
|
|
l_int32 w, h;
|
|
|
|
PROCNAME("dpixSetPixel");
|
|
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
|
|
dpixGetDimensions(dpix, &w, &h);
|
|
if (x < 0 || x >= w || y < 0 || y >= h)
|
|
return 2;
|
|
|
|
*(dpix->data + y * w + x) = val;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* FPix serialized I/O *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief fpixRead()
|
|
*
|
|
* \param[in] filename
|
|
* \return fpix, or NULL on error
|
|
*/
|
|
FPIX *
|
|
fpixRead(const char *filename)
|
|
{
|
|
FILE *fp;
|
|
FPIX *fpix;
|
|
|
|
PROCNAME("fpixRead");
|
|
|
|
if (!filename)
|
|
return (FPIX *)ERROR_PTR("filename not defined", procName, NULL);
|
|
|
|
if ((fp = fopenReadStream(filename)) == NULL)
|
|
return (FPIX *)ERROR_PTR("stream not opened", procName, NULL);
|
|
fpix = fpixReadStream(fp);
|
|
fclose(fp);
|
|
if (!fpix)
|
|
return (FPIX *)ERROR_PTR("fpix not read", procName, NULL);
|
|
return fpix;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixReadStream()
|
|
*
|
|
* \param[in] fp file stream
|
|
* \return fpix, or NULL on error
|
|
*/
|
|
FPIX *
|
|
fpixReadStream(FILE *fp)
|
|
{
|
|
char buf[256];
|
|
l_int32 w, h, nbytes, xres, yres, version;
|
|
l_float32 *data;
|
|
FPIX *fpix;
|
|
|
|
PROCNAME("fpixReadStream");
|
|
|
|
if (!fp)
|
|
return (FPIX *)ERROR_PTR("stream not defined", procName, NULL);
|
|
|
|
if (fscanf(fp, "\nFPix Version %d\n", &version) != 1)
|
|
return (FPIX *)ERROR_PTR("not a fpix file", procName, NULL);
|
|
if (version != FPIX_VERSION_NUMBER)
|
|
return (FPIX *)ERROR_PTR("invalid fpix version", procName, NULL);
|
|
if (fscanf(fp, "w = %d, h = %d, nbytes = %d\n", &w, &h, &nbytes) != 3)
|
|
return (FPIX *)ERROR_PTR("read fail for data size", procName, NULL);
|
|
|
|
/* Use fgets() and sscanf(); not fscanf(), for the last
|
|
* bit of header data before the float data. The reason is
|
|
* that fscanf throws away white space, and if the float data
|
|
* happens to begin with ascii character(s) that are white
|
|
* space, it will swallow them and all will be lost! */
|
|
if (fgets(buf, sizeof(buf), fp) == NULL)
|
|
return (FPIX *)ERROR_PTR("fgets read fail", procName, NULL);
|
|
if (sscanf(buf, "xres = %d, yres = %d\n", &xres, &yres) != 2)
|
|
return (FPIX *)ERROR_PTR("read fail for xres, yres", procName, NULL);
|
|
|
|
if ((fpix = fpixCreate(w, h)) == NULL)
|
|
return (FPIX *)ERROR_PTR("fpix not made", procName, NULL);
|
|
fpixSetResolution(fpix, xres, yres);
|
|
data = fpixGetData(fpix);
|
|
if (fread(data, 1, nbytes, fp) != nbytes) {
|
|
fpixDestroy(&fpix);
|
|
return (FPIX *)ERROR_PTR("read error for nbytes", procName, NULL);
|
|
}
|
|
fgetc(fp); /* ending nl */
|
|
|
|
/* Convert to little-endian if necessary */
|
|
fpixEndianByteSwap(fpix, fpix);
|
|
return fpix;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixReadMem()
|
|
*
|
|
* \param[in] data of serialized fpix
|
|
* \param[in] size of data in bytes
|
|
* \return fpix, or NULL on error
|
|
*/
|
|
FPIX *
|
|
fpixReadMem(const l_uint8 *data,
|
|
size_t size)
|
|
{
|
|
FILE *fp;
|
|
FPIX *fpix;
|
|
|
|
PROCNAME("fpixReadMem");
|
|
|
|
if (!data)
|
|
return (FPIX *)ERROR_PTR("data not defined", procName, NULL);
|
|
if ((fp = fopenReadFromMemory(data, size)) == NULL)
|
|
return (FPIX *)ERROR_PTR("stream not opened", procName, NULL);
|
|
|
|
fpix = fpixReadStream(fp);
|
|
fclose(fp);
|
|
if (!fpix) L_ERROR("fpix not read\n", procName);
|
|
return fpix;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixWrite()
|
|
*
|
|
* \param[in] filename
|
|
* \param[in] fpix
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixWrite(const char *filename,
|
|
FPIX *fpix)
|
|
{
|
|
l_int32 ret;
|
|
FILE *fp;
|
|
|
|
PROCNAME("fpixWrite");
|
|
|
|
if (!filename)
|
|
return ERROR_INT("filename not defined", procName, 1);
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
if ((fp = fopenWriteStream(filename, "wb")) == NULL)
|
|
return ERROR_INT("stream not opened", procName, 1);
|
|
ret = fpixWriteStream(fp, fpix);
|
|
fclose(fp);
|
|
if (ret)
|
|
return ERROR_INT("fpix not written to stream", procName, 1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixWriteStream()
|
|
*
|
|
* \param[in] fp file stream opened for "wb"
|
|
* \param[in] fpix
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
fpixWriteStream(FILE *fp,
|
|
FPIX *fpix)
|
|
{
|
|
l_int32 w, h, xres, yres;
|
|
l_uint32 nbytes;
|
|
l_float32 *data;
|
|
FPIX *fpixt;
|
|
|
|
PROCNAME("fpixWriteStream");
|
|
|
|
if (!fp)
|
|
return ERROR_INT("stream not defined", procName, 1);
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
/* Convert to little-endian if necessary */
|
|
fpixt = fpixEndianByteSwap(NULL, fpix);
|
|
|
|
fpixGetDimensions(fpixt, &w, &h);
|
|
data = fpixGetData(fpixt);
|
|
nbytes = sizeof(l_float32) * w * h;
|
|
fpixGetResolution(fpixt, &xres, &yres);
|
|
fprintf(fp, "\nFPix Version %d\n", FPIX_VERSION_NUMBER);
|
|
fprintf(fp, "w = %d, h = %d, nbytes = %u\n", w, h, nbytes);
|
|
fprintf(fp, "xres = %d, yres = %d\n", xres, yres);
|
|
fwrite(data, 1, nbytes, fp);
|
|
fprintf(fp, "\n");
|
|
|
|
fpixDestroy(&fpixt);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixWriteMem()
|
|
*
|
|
* \param[out] pdata data of serialized fpix
|
|
* \param[out] psize size of returned data
|
|
* \param[in] fpix
|
|
* \return 0 if OK, 1 on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Serializes a fpix in memory and puts the result in a buffer.
|
|
* </pre>
|
|
*/
|
|
l_ok
|
|
fpixWriteMem(l_uint8 **pdata,
|
|
size_t *psize,
|
|
FPIX *fpix)
|
|
{
|
|
l_int32 ret;
|
|
FILE *fp;
|
|
|
|
PROCNAME("fpixWriteMem");
|
|
|
|
if (pdata) *pdata = NULL;
|
|
if (psize) *psize = 0;
|
|
if (!pdata)
|
|
return ERROR_INT("&data not defined", procName, 1);
|
|
if (!psize)
|
|
return ERROR_INT("&size not defined", procName, 1);
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
|
|
#if HAVE_FMEMOPEN
|
|
if ((fp = open_memstream((char **)pdata, psize)) == NULL)
|
|
return ERROR_INT("stream not opened", procName, 1);
|
|
ret = fpixWriteStream(fp, fpix);
|
|
#else
|
|
L_INFO("work-around: writing to a temp file\n", procName);
|
|
#ifdef _WIN32
|
|
if ((fp = fopenWriteWinTempfile()) == NULL)
|
|
return ERROR_INT("tmpfile stream not opened", procName, 1);
|
|
#else
|
|
if ((fp = tmpfile()) == NULL)
|
|
return ERROR_INT("tmpfile stream not opened", procName, 1);
|
|
#endif /* _WIN32 */
|
|
ret = fpixWriteStream(fp, fpix);
|
|
rewind(fp);
|
|
*pdata = l_binaryReadStream(fp, psize);
|
|
#endif /* HAVE_FMEMOPEN */
|
|
fclose(fp);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief fpixEndianByteSwap()
|
|
*
|
|
* \param[in] fpixd can be equal to fpixs or NULL
|
|
* \param[in] fpixs
|
|
* \return fpixd always
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) On big-endian hardware, this does byte-swapping on each of
|
|
* the 4-byte floats in the fpix data. On little-endians,
|
|
* the data is unchanged. This is used for serialization
|
|
* of fpix; the data is serialized in little-endian byte
|
|
* order because most hardware is little-endian.
|
|
* (2) The operation can be either in-place or, if fpixd == NULL,
|
|
* a new fpix is made. If not in-place, caller must catch
|
|
* the returned pointer.
|
|
* </pre>
|
|
*/
|
|
FPIX *
|
|
fpixEndianByteSwap(FPIX *fpixd,
|
|
FPIX *fpixs)
|
|
{
|
|
PROCNAME("fpixEndianByteSwap");
|
|
|
|
if (!fpixs)
|
|
return (FPIX *)ERROR_PTR("fpixs not defined", procName, fpixd);
|
|
if (fpixd && (fpixs != fpixd))
|
|
return (FPIX *)ERROR_PTR("fpixd != fpixs", procName, fpixd);
|
|
|
|
#ifdef L_BIG_ENDIAN
|
|
{
|
|
l_uint32 *data;
|
|
l_int32 i, j, w, h;
|
|
l_uint32 word;
|
|
|
|
fpixGetDimensions(fpixs, &w, &h);
|
|
fpixd = fpixCopy(fpixd, fpixs); /* no copy if fpixd == fpixs */
|
|
|
|
data = (l_uint32 *)fpixGetData(fpixd);
|
|
for (i = 0; i < h; i++) {
|
|
for (j = 0; j < w; j++, data++) {
|
|
word = *data;
|
|
*data = (word >> 24) |
|
|
((word >> 8) & 0x0000ff00) |
|
|
((word << 8) & 0x00ff0000) |
|
|
(word << 24);
|
|
}
|
|
}
|
|
return fpixd;
|
|
}
|
|
#else /* L_LITTLE_ENDIAN */
|
|
|
|
if (fpixd)
|
|
return fpixd; /* no-op */
|
|
else
|
|
return fpixClone(fpixs);
|
|
|
|
#endif /* L_BIG_ENDIAN */
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* DPix serialized I/O *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief dpixRead()
|
|
*
|
|
* \param[in] filename
|
|
* \return dpix, or NULL on error
|
|
*/
|
|
DPIX *
|
|
dpixRead(const char *filename)
|
|
{
|
|
FILE *fp;
|
|
DPIX *dpix;
|
|
|
|
PROCNAME("dpixRead");
|
|
|
|
if (!filename)
|
|
return (DPIX *)ERROR_PTR("filename not defined", procName, NULL);
|
|
|
|
if ((fp = fopenReadStream(filename)) == NULL)
|
|
return (DPIX *)ERROR_PTR("stream not opened", procName, NULL);
|
|
dpix = dpixReadStream(fp);
|
|
fclose(fp);
|
|
if (!dpix)
|
|
return (DPIX *)ERROR_PTR("dpix not read", procName, NULL);
|
|
return dpix;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixReadStream()
|
|
*
|
|
* \param[in] fp file stream
|
|
* \return dpix, or NULL on error
|
|
*/
|
|
DPIX *
|
|
dpixReadStream(FILE *fp)
|
|
{
|
|
char buf[256];
|
|
l_int32 w, h, nbytes, version, xres, yres;
|
|
l_float64 *data;
|
|
DPIX *dpix;
|
|
|
|
PROCNAME("dpixReadStream");
|
|
|
|
if (!fp)
|
|
return (DPIX *)ERROR_PTR("stream not defined", procName, NULL);
|
|
|
|
if (fscanf(fp, "\nDPix Version %d\n", &version) != 1)
|
|
return (DPIX *)ERROR_PTR("not a dpix file", procName, NULL);
|
|
if (version != DPIX_VERSION_NUMBER)
|
|
return (DPIX *)ERROR_PTR("invalid dpix version", procName, NULL);
|
|
if (fscanf(fp, "w = %d, h = %d, nbytes = %d\n", &w, &h, &nbytes) != 3)
|
|
return (DPIX *)ERROR_PTR("read fail for data size", procName, NULL);
|
|
|
|
/* Use fgets() and sscanf(); not fscanf(), for the last
|
|
* bit of header data before the float data. The reason is
|
|
* that fscanf throws away white space, and if the float data
|
|
* happens to begin with ascii character(s) that are white
|
|
* space, it will swallow them and all will be lost! */
|
|
if (fgets(buf, sizeof(buf), fp) == NULL)
|
|
return (DPIX *)ERROR_PTR("fgets read fail", procName, NULL);
|
|
if (sscanf(buf, "xres = %d, yres = %d\n", &xres, &yres) != 2)
|
|
return (DPIX *)ERROR_PTR("read fail for xres, yres", procName, NULL);
|
|
|
|
if ((dpix = dpixCreate(w, h)) == NULL)
|
|
return (DPIX *)ERROR_PTR("dpix not made", procName, NULL);
|
|
dpixSetResolution(dpix, xres, yres);
|
|
data = dpixGetData(dpix);
|
|
if (fread(data, 1, nbytes, fp) != nbytes) {
|
|
dpixDestroy(&dpix);
|
|
return (DPIX *)ERROR_PTR("read error for nbytes", procName, NULL);
|
|
}
|
|
fgetc(fp); /* ending nl */
|
|
|
|
/* Convert to little-endian if necessary */
|
|
dpixEndianByteSwap(dpix, dpix);
|
|
return dpix;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixReadMem()
|
|
*
|
|
* \param[in] data of serialized dpix
|
|
* \param[in] size of data in bytes
|
|
* \return dpix, or NULL on error
|
|
*/
|
|
DPIX *
|
|
dpixReadMem(const l_uint8 *data,
|
|
size_t size)
|
|
{
|
|
FILE *fp;
|
|
DPIX *dpix;
|
|
|
|
PROCNAME("dpixReadMem");
|
|
|
|
if (!data)
|
|
return (DPIX *)ERROR_PTR("data not defined", procName, NULL);
|
|
if ((fp = fopenReadFromMemory(data, size)) == NULL)
|
|
return (DPIX *)ERROR_PTR("stream not opened", procName, NULL);
|
|
|
|
dpix = dpixReadStream(fp);
|
|
fclose(fp);
|
|
if (!dpix) L_ERROR("dpix not read\n", procName);
|
|
return dpix;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixWrite()
|
|
*
|
|
* \param[in] filename
|
|
* \param[in] dpix
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixWrite(const char *filename,
|
|
DPIX *dpix)
|
|
{
|
|
l_int32 ret;
|
|
FILE *fp;
|
|
|
|
PROCNAME("dpixWrite");
|
|
|
|
if (!filename)
|
|
return ERROR_INT("filename not defined", procName, 1);
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
|
|
if ((fp = fopenWriteStream(filename, "wb")) == NULL)
|
|
return ERROR_INT("stream not opened", procName, 1);
|
|
ret = dpixWriteStream(fp, dpix);
|
|
fclose(fp);
|
|
if (ret)
|
|
return ERROR_INT("dpix not written to stream", procName, 1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixWriteStream()
|
|
*
|
|
* \param[in] fp file stream opened for "wb"
|
|
* \param[in] dpix
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
dpixWriteStream(FILE *fp,
|
|
DPIX *dpix)
|
|
{
|
|
l_int32 w, h, xres, yres;
|
|
l_uint32 nbytes;
|
|
l_float64 *data;
|
|
DPIX *dpixt;
|
|
|
|
PROCNAME("dpixWriteStream");
|
|
|
|
if (!fp)
|
|
return ERROR_INT("stream not defined", procName, 1);
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
|
|
/* Convert to little-endian if necessary */
|
|
dpixt = dpixEndianByteSwap(NULL, dpix);
|
|
|
|
dpixGetDimensions(dpixt, &w, &h);
|
|
dpixGetResolution(dpixt, &xres, &yres);
|
|
data = dpixGetData(dpixt);
|
|
nbytes = sizeof(l_float64) * w * h;
|
|
fprintf(fp, "\nDPix Version %d\n", DPIX_VERSION_NUMBER);
|
|
fprintf(fp, "w = %d, h = %d, nbytes = %u\n", w, h, nbytes);
|
|
fprintf(fp, "xres = %d, yres = %d\n", xres, yres);
|
|
fwrite(data, 1, nbytes, fp);
|
|
fprintf(fp, "\n");
|
|
|
|
dpixDestroy(&dpixt);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixWriteMem()
|
|
*
|
|
* \param[out] pdata data of serialized dpix
|
|
* \param[out] psize size of returned data
|
|
* \param[in] dpix
|
|
* \return 0 if OK, 1 on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Serializes a dpix in memory and puts the result in a buffer.
|
|
* </pre>
|
|
*/
|
|
l_ok
|
|
dpixWriteMem(l_uint8 **pdata,
|
|
size_t *psize,
|
|
DPIX *dpix)
|
|
{
|
|
l_int32 ret;
|
|
FILE *fp;
|
|
|
|
PROCNAME("dpixWriteMem");
|
|
|
|
if (pdata) *pdata = NULL;
|
|
if (psize) *psize = 0;
|
|
if (!pdata)
|
|
return ERROR_INT("&data not defined", procName, 1);
|
|
if (!psize)
|
|
return ERROR_INT("&size not defined", procName, 1);
|
|
if (!dpix)
|
|
return ERROR_INT("dpix not defined", procName, 1);
|
|
|
|
#if HAVE_FMEMOPEN
|
|
if ((fp = open_memstream((char **)pdata, psize)) == NULL)
|
|
return ERROR_INT("stream not opened", procName, 1);
|
|
ret = dpixWriteStream(fp, dpix);
|
|
#else
|
|
L_INFO("work-around: writing to a temp file\n", procName);
|
|
#ifdef _WIN32
|
|
if ((fp = fopenWriteWinTempfile()) == NULL)
|
|
return ERROR_INT("tmpfile stream not opened", procName, 1);
|
|
#else
|
|
if ((fp = tmpfile()) == NULL)
|
|
return ERROR_INT("tmpfile stream not opened", procName, 1);
|
|
#endif /* _WIN32 */
|
|
ret = dpixWriteStream(fp, dpix);
|
|
rewind(fp);
|
|
*pdata = l_binaryReadStream(fp, psize);
|
|
#endif /* HAVE_FMEMOPEN */
|
|
fclose(fp);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief dpixEndianByteSwap()
|
|
*
|
|
* \param[in] dpixd can be equal to dpixs or NULL
|
|
* \param[in] dpixs
|
|
* \return dpixd always
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) On big-endian hardware, this does byte-swapping on each of
|
|
* the 4-byte words in the dpix data. On little-endians,
|
|
* the data is unchanged. This is used for serialization
|
|
* of dpix; the data is serialized in little-endian byte
|
|
* order because most hardware is little-endian.
|
|
* (2) The operation can be either in-place or, if dpixd == NULL,
|
|
* a new dpix is made. If not in-place, caller must catch
|
|
* the returned pointer.
|
|
* </pre>
|
|
*/
|
|
DPIX *
|
|
dpixEndianByteSwap(DPIX *dpixd,
|
|
DPIX *dpixs)
|
|
{
|
|
PROCNAME("dpixEndianByteSwap");
|
|
|
|
if (!dpixs)
|
|
return (DPIX *)ERROR_PTR("dpixs not defined", procName, dpixd);
|
|
if (dpixd && (dpixs != dpixd))
|
|
return (DPIX *)ERROR_PTR("dpixd != dpixs", procName, dpixd);
|
|
|
|
#ifdef L_BIG_ENDIAN
|
|
{
|
|
l_uint32 *data;
|
|
l_int32 i, j, w, h;
|
|
l_uint32 word;
|
|
|
|
dpixGetDimensions(dpixs, &w, &h);
|
|
dpixd = dpixCopy(dpixd, dpixs); /* no copy if dpixd == dpixs */
|
|
|
|
data = (l_uint32 *)dpixGetData(dpixd);
|
|
for (i = 0; i < h; i++) {
|
|
for (j = 0; j < 2 * w; j++, data++) {
|
|
word = *data;
|
|
*data = (word >> 24) |
|
|
((word >> 8) & 0x0000ff00) |
|
|
((word << 8) & 0x00ff0000) |
|
|
(word << 24);
|
|
}
|
|
}
|
|
return dpixd;
|
|
}
|
|
#else /* L_LITTLE_ENDIAN */
|
|
|
|
if (dpixd)
|
|
return dpixd; /* no-op */
|
|
else
|
|
return dpixClone(dpixs);
|
|
|
|
#endif /* L_BIG_ENDIAN */
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*
|
|
* Print FPix (subsampled, for debugging) *
|
|
*--------------------------------------------------------------------*/
|
|
/*!
|
|
* \brief fpixPrintStream()
|
|
*
|
|
* \param[in] fp file stream
|
|
* \param[in] fpix
|
|
* \param[in] factor for subsampling
|
|
* \return 0 if OK, 1 on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) Subsampled printout of fpix for debugging.
|
|
* </pre>
|
|
*/
|
|
l_ok
|
|
fpixPrintStream(FILE *fp,
|
|
FPIX *fpix,
|
|
l_int32 factor)
|
|
{
|
|
l_int32 i, j, w, h, count;
|
|
l_float32 val;
|
|
|
|
PROCNAME("fpixPrintStream");
|
|
|
|
if (!fp)
|
|
return ERROR_INT("stream not defined", procName, 1);
|
|
if (!fpix)
|
|
return ERROR_INT("fpix not defined", procName, 1);
|
|
if (factor < 1)
|
|
return ERROR_INT("sampling factor < 1f", procName, 1);
|
|
|
|
fpixGetDimensions(fpix, &w, &h);
|
|
fprintf(fp, "\nFPix: w = %d, h = %d\n", w, h);
|
|
for (i = 0; i < h; i += factor) {
|
|
for (count = 0, j = 0; j < w; j += factor, count++) {
|
|
fpixGetPixel(fpix, j, i, &val);
|
|
fprintf(fp, "val[%d, %d] = %f ", i, j, val);
|
|
if ((count + 1) % 3 == 0) fprintf(fp, "\n");
|
|
}
|
|
if (count % 3) fprintf(fp, "\n");
|
|
}
|
|
fprintf(fp, "\n");
|
|
return 0;
|
|
}
|