Skip to content

Commit

Permalink
Small documentation clean up of the opj stream jp2k I/O implementation
Browse files Browse the repository at this point in the history
* In the improved implemtation, compression to and from memory is enabled
  by callbacks in the openjpeg library, and file stream operations
  are wrappers around the memory stream functions.
  • Loading branch information
DanBloomberg committed Feb 6, 2024
1 parent dd31a93 commit ac2d071
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 52 deletions.
2 changes: 1 addition & 1 deletion src/allheaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,7 @@ LEPT_DLL extern l_ok readHeaderJp2k ( const char *filename, l_int32 *pw, l_int32
LEPT_DLL extern l_ok freadHeaderJp2k ( FILE *fp, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pcodec );
LEPT_DLL extern l_ok readHeaderMemJp2k ( const l_uint8 *data, size_t size, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *pcodec );
LEPT_DLL extern l_int32 fgetJp2kResolution ( FILE *fp, l_int32 *pxres, l_int32 *pyres );
LEPT_DLL extern l_ok readResolutionMemJp2k ( const l_uint8 *data, size_t size, l_int32 *pxres, l_int32 *pyres );
LEPT_DLL extern l_ok readResolutionMemJp2k ( const l_uint8 *data, size_t nbytes, l_int32 *pxres, l_int32 *pyres );
LEPT_DLL extern PIX * pixReadJp2k ( const char *filename, l_uint32 reduction, BOX *box, l_int32 hint, l_int32 debug );
LEPT_DLL extern PIX * pixReadStreamJp2k ( FILE *fp, l_uint32 reduction, BOX *box, l_int32 hint, l_int32 debug );
LEPT_DLL extern l_ok pixWriteJp2k ( const char *filename, PIX *pix, l_int32 quality, l_int32 nlevels, l_int32 hint, l_int32 debug );
Expand Down
23 changes: 14 additions & 9 deletions src/jp2kheader.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
* l_int32 freadHeaderJp2k()
* l_int32 readHeaderMemJp2k()
* l_int32 fgetJp2kResolution()
* l_int32 readResolutionMemJp2k()
*
* Note: these function read image metadata from a jp2k file, without
* using any jp2k libraries.
Expand Down Expand Up @@ -249,13 +250,15 @@ l_uint8 ihdr[4] = {0x69, 0x68, 0x64, 0x72}; /* 'ihdr' */


/*
* fgetJp2kResolution()
* \brief fgetJp2kResolution()
*
* Input: fp (file stream opened for read)
* &xres, &yres (<return> resolution in ppi)
* Return: 0 if found; 1 if not found or on error
* \param[in] fp file stream opened for read
* \param[oui] pxres in ppi
* \param[oui] pyres in ppi
* \return 0 if found, 1 if not found or on error
*
* Notes:
* <pre>
* Notes:
* (1) If the capture resolution field is not set, this is not an error;
* the returned resolution values are 0 (designating 'unknown').
* (2) Side-effect: this rewinds the stream.
Expand All @@ -268,15 +271,16 @@ l_uint8 ihdr[4] = {0x69, 0x68, 0x64, 0x72}; /* 'ihdr' */
* xdenom: 2 bytes
* yexp: 1 byte
* xexp: 1 byte
* </pre>
*/
l_int32
fgetJp2kResolution(FILE *fp,
l_int32 *pxres,
l_int32 *pyres)
{
l_uint8 *data;
size_t nbytes;
l_ok ok;
l_uint8 *data;
size_t nbytes;
l_ok ok;

if (!fp)
return ERROR_INT("stream not opened", __func__, 1);
Expand All @@ -291,11 +295,12 @@ l_ok ok;
return ok;
}


/*!
* \brief readResolutionMemJp2k()
*
* \param[in] data const; jp2k-encoded
* \param[in] size of data
* \param[in] nbytes of data
* \param[out] pxres [optional]
* \param[out] pyres [optional]
* \return 0 if OK, 1 on error
Expand Down
2 changes: 1 addition & 1 deletion src/jp2kheaderstub.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ l_int32 fgetJp2kResolution(FILE *fp, l_int32 *pxres, l_int32 *pyres)

/* ----------------------------------------------------------------------*/

l_ok readResolutionMemJp2k(const l_uint8 *data, size_t size,
l_ok readResolutionMemJp2k(const l_uint8 *data, size_t nbytes,
l_int32 *pxres, l_int32 *pyres)
{
return ERROR_INT("function not present", __func__, 1);
Expand Down
98 changes: 58 additions & 40 deletions src/jp2kio.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,26 @@
* <pre>
*
* Read jp2k from file
* PIX *pixReadJp2k() [special top level]
* PIX *pixReadStreamJp2k()
* PIX *pixReadJp2k() [special top level]
* PIX *pixReadStreamJp2k()
* static PIX *pixReadMemJp2kCore()
*
* Write jp2k to file
* l_int32 pixWriteJp2k() [special top level]
* l_int32 pixWriteStreamJp2k()
* static opj_image_t *pixConvertToOpjImage()
* l_int32 pixWriteJp2k() [special top level]
* l_int32 pixWriteStreamJp2k()
* static opj_image_t *pixConvertToOpjImage()
*
* Read/write to memory
* PIX *pixReadMemJp2k()
* l_int32 pixWriteMemJp2k()
* PIX *pixReadMemJp2k()
* l_int32 pixWriteMemJp2k()
*
* Static functions from opj 2.0 to retain file stream interface
* Static generator of opj_stream from a memory buffer
* static opj_stream_t *opjCreateMemoryStream()
* [and other static helpers]
*
* Static generator of opj_stream fom a file stream
* static opj_stream_t *opjCreateStream()
* [other static helpers]
* [and other static helpers]
*
* Based on the OpenJPEG distribution:
* http://www.openjpeg.org/
Expand All @@ -52,10 +57,11 @@
*
* Compressing to memory and decompressing from memory
* ---------------------------------------------------
* On systems like Windows without fmemopen() and open_memstream(),
* we write data to a temp file and read it back for operations
* between pix and compressed-data, such as pixReadMemJp2k() and
* pixWriteMemJp2k().
* In previous versions, for systems like Windows that do not have
* fmemopen() and open_memstream(), we wrote data to a temp file.
* Now we use the opj_stream interface directly for operations to and
* from memory. The file stream interface for these operations
* is a wrapper around the memory interface.
*
* Pdf can accept jp2k compressed strings directly
* -----------------------------------------------
Expand Down Expand Up @@ -120,6 +126,10 @@ typedef struct OpjBuffer
size_t len; /*!< length of valid data in the buffer */
} OpjBuffer;

/* Static converter pix --> opj_image. Used for compressing pix,
* because the codec works on data stored in their raster format. */
static opj_image_t *pixConvertToOpjImage(PIX *pix);

/* Static generator of opj_stream from a memory buffer. */
static opj_stream_t *opjCreateMemoryStream(OpjBuffer *buf, l_int32 is_read);

Expand All @@ -131,9 +141,6 @@ static opj_stream_t *opjCreateMemoryStream(OpjBuffer *buf, l_int32 is_read);
* it is necessary to recreate the stream interface here. */
static opj_stream_t *opjCreateStream(FILE *fp, l_int32 is_read);

/* Static converter pix --> opj_image. Used for compressing pix,
* because the codec works on data stored in their raster format. */
static opj_image_t *pixConvertToOpjImage(PIX *pix);

/*---------------------------------------------------------------------*
* Callback event handlers *
Expand Down Expand Up @@ -178,10 +185,11 @@ static void info_callback(const char *msg, void *client_data) {
* resolution image. Use %reduction > 1 to get a reduced image.
* The actual values of %reduction that can be used on an image
* depend on the number of resolution levels chosen when the
* image was compressed. Typical values might be 1, 2, 4, 8 and 16.
* Using a value representing a reduction level that was not
* image was compressed. We typically encode using six power-of-2
* resolution values: 1, 2, 4, 8, 16 and 32. Attempting to read
* with a value representing a reduction level that was not
* stored when the file was written will fail with the message:
* "failed to read the header".
* "failed to read the header".
* (3) Use %box to decode only a part of the image. The box is defined
* at full resolution. It is reduced internally by %reduction,
* and clipping to the right and bottom of the image is automatic.
Expand Down Expand Up @@ -554,13 +562,13 @@ FILE *fp;
* </pre>
*/
static l_ok
pixWriteOpjStreamJp2k(opj_stream_t *l_stream,
PIX *pix,
l_int32 quality,
l_int32 nlevels,
l_int32 codec,
l_int32 hint,
l_int32 debug)
pixWriteOpjStreamJp2k(opj_stream_t *l_stream,
PIX *pix,
l_int32 quality,
l_int32 nlevels,
l_int32 codec,
l_int32 hint,
l_int32 debug)
{
l_int32 i, w, h, d, depth, channels, success;
l_float64 snr;
Expand Down Expand Up @@ -693,7 +701,7 @@ opj_image_t *image = NULL;

/* Set the resolution (TBD) */

/* Encode the image */
/* Encode the image into the l_stream data interface */
if (!opj_start_compress(l_codec, image, l_stream)) {
opj_destroy_codec(l_codec);
opj_image_destroy(image);
Expand Down Expand Up @@ -730,9 +738,11 @@ opj_image_t *image = NULL;
* \param[in] hint a bitwise OR of L_JP2K_* values; 0 for default
* \param[in] debug output callback messages, etc
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) See pixWriteJp2k() for usage.
* (1) This is a wrapper on the memory stream interface.
* (2) See pixWriteJp2k() for usage.
* </pre>
*/
l_ok
Expand All @@ -744,21 +754,21 @@ pixWriteStreamJp2k(FILE *fp,
l_int32 hint,
l_int32 debug)
{
l_ok ok;
opj_stream_t *l_stream;
l_ok ok;
opj_stream_t *l_stream;

if (!fp)
return ERROR_INT("stream not open", __func__, 1);

/* Open a compression stream for writing. In 2.0 we could use this:
* opj_stream_create_default_file_stream(fp, 0)
* but the file stream interface was removed in 2.1. */
/* Open a compression stream for writing, borrowed from
* the 2.0 implementation because the file stream interface
* was removed in 2.1. */
rewind(fp);
if ((l_stream = opjCreateStream(fp, 0)) == NULL) {
if ((l_stream = opjCreateStream(fp, 0)) == NULL)
return ERROR_INT("failed to open l_stream\n", __func__, 1);
}

ok = pixWriteOpjStreamJp2k(l_stream, pix, quality, nlevels, codec, hint, debug);
ok = pixWriteOpjStreamJp2k(l_stream, pix, quality, nlevels,
codec, hint, debug);

/* Clean up */
opj_stream_destroy(l_stream);
Expand Down Expand Up @@ -956,7 +966,7 @@ OpjBuffer buffer;


/*---------------------------------------------------------------------*
* Static functions for the memory stream interface *
* Static functions for the memory stream interface *
*---------------------------------------------------------------------*/
static OPJ_SIZE_T
opj_read_from_buffer(void *p_buffer, OPJ_SIZE_T p_nb_bytes, OpjBuffer *pbuf) {
Expand All @@ -972,7 +982,8 @@ opj_read_from_buffer(void *p_buffer, OPJ_SIZE_T p_nb_bytes, OpjBuffer *pbuf) {
}

static OPJ_SIZE_T
opj_write_from_buffer(const void *p_buffer, OPJ_SIZE_T p_nb_bytes, OpjBuffer *pbuf) {
opj_write_from_buffer(const void *p_buffer, OPJ_SIZE_T p_nb_bytes,
OpjBuffer *pbuf) {
if (pbuf->pos < 0)
return 0;

Expand Down Expand Up @@ -1018,7 +1029,10 @@ opj_seek_from_buffer(OPJ_OFF_T offset, OpjBuffer *pbuf) {
return 1;
}

/* Static generator of opj_stream from memory buffer */

/*---------------------------------------------------------------------*
* Static generator of opj_stream from memory buffer *
*---------------------------------------------------------------------*/
static opj_stream_t *
opjCreateMemoryStream(OpjBuffer *pbuf,
l_int32 is_read_stream)
Expand Down Expand Up @@ -1050,6 +1064,7 @@ opj_stream_t *l_stream;
return l_stream;
}


/*---------------------------------------------------------------------*
* Static functions from opj 2.0 to retain file stream interface *
*---------------------------------------------------------------------*/
Expand Down Expand Up @@ -1090,7 +1105,10 @@ opj_seek_from_file(OPJ_OFF_T offset, FILE *fp) {
return 1;
}

/* Static generator of opj_stream from file stream */

/*---------------------------------------------------------------------*
* Static generator of opj_stream from a file stream *
*---------------------------------------------------------------------*/
static opj_stream_t *
opjCreateStream(FILE *fp,
l_int32 is_read_stream)
Expand Down
6 changes: 5 additions & 1 deletion version-notes.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ <h2 align=center> <IMG SRC="moller52.jpg" border=1 ALIGN_MIDDLE> </h2>
* Use wrapper callSystemDebug() instead of system() in programs.
* Fixed Issue #730: artifacts and bad compression with pixWriteJp2k.
Results are now identical with ImageMagick convert (to jp2).
* Source files changed: gplot.c, jp2kio.c partify.c, pdfio2.c,
* With PR732, atykhyy made pix(Read,Write)MemJp2k work with
direct memory access using openjpeg opj_stream functions. This
removes need for temp file on Windows when writing to/from memory.
* Source files changed: gplot.c, jp2kheader.c,
jp2kheaderstub.c, jp2kio.c, partify.c, pdfio2.c,
psio2.c, utils2.c, writefile.c, allheaders.h, environ.h
* Prog files changed: libre_makefigs.c, cleanpdf.c croppdf.c,
compresspdf.c, alltests_reg.c, htmlviewer.c, jp2kio_reg.c,
Expand Down

0 comments on commit ac2d071

Please sign in to comment.