J2KAPI(j2k_Component*) j2k_Component_construct(nrt_Uint32 width, nrt_Uint32 height, nrt_Uint32 precision, NRT_BOOL isSigned, nrt_Uint32 offsetX, nrt_Uint32 offsetY, nrt_Uint32 separationX, nrt_Uint32 separationY, nrt_Error *error) { j2k_Component *component = NULL; ComponentImpl *impl = NULL; component = (j2k_Component*) J2K_MALLOC(sizeof(j2k_Component)); if (!component) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } memset(component, 0, sizeof(j2k_Component)); /* create the Component interface */ impl = (ComponentImpl *) J2K_MALLOC(sizeof(ComponentImpl)); if (!impl) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } memset(impl, 0, sizeof(ComponentImpl)); component->data = impl; component->iface = &ComponentInterface; impl->width = width; impl->height = height; impl->precision = precision; impl->isSigned = isSigned; impl->x0 = offsetX; impl->y0 = offsetY; impl->xSeparation = separationX; impl->ySeparation = separationY; return component; CATCH_ERROR: { if (component) { j2k_Component_destruct(&component); } return NULL; } }
J2KAPI(j2k_Container*) j2k_Container_construct(nrt_Uint32 gridWidth, nrt_Uint32 gridHeight, nrt_Uint32 numComponents, j2k_Component** components, nrt_Uint32 tileWidth, nrt_Uint32 tileHeight, int imageType, nrt_Error *error) { j2k_Container *container = NULL; ContainerImpl *impl = NULL; container = (j2k_Container*) J2K_MALLOC(sizeof(j2k_Container)); if (!container) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } memset(container, 0, sizeof(j2k_Container)); /* create the Container interface */ impl = (ContainerImpl *) J2K_MALLOC(sizeof(ContainerImpl)); if (!impl) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } memset(impl, 0, sizeof(ContainerImpl)); container->data = impl; container->iface = &ContainerInterface; impl->gridWidth = gridWidth; impl->gridHeight = gridHeight; impl->nComponents = numComponents; impl->components = components; impl->tileWidth = tileWidth; impl->tileHeight = tileHeight; impl->xTiles = gridWidth / tileWidth + (gridWidth % tileWidth == 0 ? 0 : 1); impl->yTiles = gridHeight / tileHeight + (gridHeight % tileHeight == 0 ? 0 : 1); impl->imageType = imageType; return container; CATCH_ERROR: { if (container) { j2k_Container_destruct(&container); } return NULL; } }
J2KAPI(j2k_Reader*) j2k_Reader_openIO(nrt_IOInterface *io, nrt_Error *error) { OpenJPEGReaderImpl *impl = NULL; j2k_Reader *reader = NULL; /* create the Reader interface */ impl = (OpenJPEGReaderImpl *) J2K_MALLOC(sizeof(OpenJPEGReaderImpl)); if (!impl) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } memset(impl, 0, sizeof(OpenJPEGReaderImpl)); reader = (j2k_Reader *) J2K_MALLOC(sizeof(j2k_Reader)); if (!reader) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } memset(reader, 0, sizeof(j2k_Reader)); reader->data = impl; reader->iface = &ReaderInterface; /* initialize the interfaces */ impl->io = io; impl->ioOffset = nrt_IOInterface_tell(io, error); if (!OpenJPEG_readHeader(impl, error)) { goto CATCH_ERROR; } return reader; CATCH_ERROR: { if (reader) { j2k_Reader_destruct(&reader); } else if (impl) { OpenJPEGReader_destruct((J2K_USER_DATA*) impl); } return NULL; } }
J2KAPI(j2k_Writer*) j2k_Writer_construct(j2k_Container *container, j2k_WriterOptions *writerOps, nrt_Error *error) { j2k_Writer *writer = NULL; OpenJPEGWriterImpl *impl = NULL; writer = (j2k_Writer*) J2K_MALLOC(sizeof(j2k_Container)); if (!writer) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } memset(writer, 0, sizeof(j2k_Writer)); /* create the Writer interface */ impl = (OpenJPEGWriterImpl *) J2K_MALLOC(sizeof(OpenJPEGWriterImpl)); if (!impl) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } memset(impl, 0, sizeof(OpenJPEGWriterImpl)); impl->container = container; if (!(OpenJPEG_initImage(impl, writerOps, error))) { goto CATCH_ERROR; } writer->data = impl; writer->iface = &WriterInterface; return writer; CATCH_ERROR: { if (writer) { j2k_Writer_destruct(&writer); } return NULL; } }
J2K_BOOL readFile(const char* filename, char **buf, nrt_Uint64 *bufSize, nrt_Error *error) { J2K_BOOL rc = J2K_TRUE; nrt_IOInterface *io = NULL; if (!(io = nrt_IOHandleAdapter_open(filename, NRT_ACCESS_READONLY, NRT_OPEN_EXISTING, error))) goto CATCH_ERROR; *bufSize = nrt_IOInterface_getSize(io, error); if (!(*buf = (char*)J2K_MALLOC(*bufSize))) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } if (!nrt_IOInterface_read(io, *buf, *bufSize, error)) { goto CATCH_ERROR; } goto CLEANUP; CATCH_ERROR: { rc = J2K_FALSE; if (*buf) J2K_FREE(*buf); *buf = NULL; } CLEANUP: { if (io) nrt_IOInterface_destruct(&io); } return rc; }
OpenJPEGWriter_setTile(J2K_USER_DATA *data, nrt_Uint32 tileX, nrt_Uint32 tileY, const nrt_Uint8 *buf, nrt_Uint32 tileSize, nrt_Error *error) { OpenJPEGWriterImpl *impl = (OpenJPEGWriterImpl*) data; NRT_BOOL rc = NRT_SUCCESS; nrt_Uint32 xTiles, yTiles, tileIndex, width, height, tileWidth, tileHeight; nrt_Uint32 thisTileWidth, thisTileHeight, thisTileSize, nComponents, nBytes; nrt_Uint8* newTileBuf = NULL; xTiles = j2k_Container_getTilesX(impl->container, error); yTiles = j2k_Container_getTilesY(impl->container, error); width = j2k_Container_getWidth(impl->container, error); height = j2k_Container_getHeight(impl->container, error); tileWidth = j2k_Container_getTileWidth(impl->container, error); tileHeight = j2k_Container_getTileHeight(impl->container, error); nComponents = j2k_Container_getNumComponents(impl->container, error); nBytes = (j2k_Container_getPrecision(impl->container, error) - 1) / 8 + 1; tileIndex = tileY * xTiles + tileX; memset(error->message, 0, NRT_MAX_EMESSAGE); if(!opj_set_error_handler(impl->codec, OpenJPEG_errorHandler, error)) { nrt_Error_init(error, "Unable to set OpenJPEG error handler", NRT_CTXT, NRT_ERR_UNK); goto CATCH_ERROR; } /* Check for edge case where we may have partial tile */ thisTileWidth = tileWidth; thisTileHeight = tileHeight; if (tileX == xTiles - 1 && width % tileWidth != 0) thisTileWidth = width % tileWidth; if (tileY == yTiles - 1 && height % tileHeight != 0) thisTileHeight = height % tileHeight; thisTileSize = thisTileWidth * thisTileHeight * nComponents * nBytes; if(thisTileSize != tileSize) tileSize = thisTileSize; if(thisTileWidth < tileWidth) { /* TODO: The current approach below only works for single band * imagery. For RGB data, I believe it is stored as all * red, then all green, then all blue, so we would need * a temp buffer rather than reusing the current buffer. */ if (nComponents != 1) { nrt_Error_init( error, "Partial tile width not implemented for multi-band", NRT_CTXT, NRT_ERR_UNK); goto CATCH_ERROR; } /* We have a tile that is wider than it "should" be * Need to create smaller buffer to pass to write function */ { OPJ_UINT32 ii; size_t srcOffset = 0; size_t destOffset = 0; const size_t srcStride = tileWidth * nBytes; const size_t destStride = thisTileWidth * nBytes; newTileBuf = (nrt_Uint8*) J2K_MALLOC(thisTileSize); if(!newTileBuf) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } for(ii = 0; ii < thisTileHeight; ++ii, srcOffset += srcStride, destOffset += destStride) memcpy(newTileBuf + destOffset, buf + srcOffset, destStride); buf = newTileBuf; } } if (!opj_write_tile(impl->codec, tileIndex, (OPJ_BYTE* )buf, tileSize, impl->stream)) { nrt_Error ioError; const nrt_Off currentPos = nrt_IOInterface_tell(impl->compressed, &ioError); const nrt_Off ioSize = nrt_IOInterface_getSize(impl->compressed, &ioError); if (NRT_IO_SUCCESS(currentPos) && NRT_IO_SUCCESS(ioSize) && currentPos + OPENJPEG_STREAM_SIZE >= ioSize) { /* The write failed because implStreamWrite() failed because * nrt_IOInterface_write() failed because we didn't have enough * room left in the buffer that we copy to prior to flushing out * to disk in OpenJPEGWriter_write(). The buffer is sized to the * uncompressed image size, so this only occurs if the compressed * image is actually larger than the uncompressed size. * TODO: Handle resizing the buffer on the fly when this occurs * inside implStreamWrite(). Long-term if we're able to thread * per tile, we won't have to reallocate nearly as much. */ nrt_Error_init(error, "Error writing tile: Compressed image is larger " "than uncompressed image", NRT_CTXT, NRT_ERR_INVALID_OBJECT); } /*nrt_Error_init(error, "Error writing tile", NRT_CTXT, NRT_ERR_INVALID_OBJECT);*/ goto CATCH_ERROR; } goto CLEANUP; CATCH_ERROR: { rc = NRT_FAILURE; } CLEANUP: { if(newTileBuf) J2K_FREE(newTileBuf); } return rc; }
OpenJPEGReader_readRegion(J2K_USER_DATA *data, nrt_Uint32 x0, nrt_Uint32 y0, nrt_Uint32 x1, nrt_Uint32 y1, nrt_Uint8 **buf, nrt_Error *error) { OpenJPEGReaderImpl *impl = (OpenJPEGReaderImpl*) data; opj_stream_t *stream = NULL; opj_image_t *image = NULL; opj_codec_t *codec = NULL; nrt_Uint64 bufSize; nrt_Uint64 offset = 0; nrt_Uint32 componentBytes, nComponents; if (!OpenJPEG_setup(impl, &stream, &codec, error)) { goto CATCH_ERROR; } /* unfortunately, we need to read the header every time ... */ if (!opj_read_header(stream, codec, &image)) { /*nrt_Error_init(error, "Error reading header", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } if (x1 == 0) x1 = j2k_Container_getWidth(impl->container, error); if (y1 == 0) y1 = j2k_Container_getHeight(impl->container, error); /* only decode what we want */ if (!opj_set_decode_area(codec, image, x0, y0, x1, y1)) { /*nrt_Error_init(error, "Error decoding area", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } nComponents = j2k_Container_getNumComponents(impl->container, error); componentBytes = (j2k_Container_getPrecision(impl->container, error) - 1) / 8 + 1; bufSize = (nrt_Uint64)(x1 - x0) * (y1 - y0) * componentBytes * nComponents; if (buf && !*buf) { *buf = (nrt_Uint8*)J2K_MALLOC(bufSize); if (!*buf) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } } { int keepGoing; OPJ_UINT32 tileIndex, reqSize; OPJ_INT32 tileX0, tileY0, tileX1, tileY1; do { if (!opj_read_tile_header(codec, stream, &tileIndex, &reqSize, &tileX0, &tileY0, &tileX1, &tileY1, &nComponents, &keepGoing)) { /*nrt_Error_init(error, "Error reading tile header", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } if (keepGoing) { if (!opj_decode_tile_data(codec, tileIndex, (*buf + offset), reqSize, stream)) { /*nrt_Error_init(error, "Error decoding tile", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } offset += reqSize; } } while (keepGoing); } goto CLEANUP; CATCH_ERROR: { bufSize = 0; } CLEANUP: { OpenJPEG_cleanup(&stream, &codec, &image); } return bufSize; }
OpenJPEGReader_readTile(J2K_USER_DATA *data, nrt_Uint32 tileX, nrt_Uint32 tileY, nrt_Uint8 **buf, nrt_Error *error) { OpenJPEGReaderImpl *impl = (OpenJPEGReaderImpl*) data; opj_stream_t *stream = NULL; opj_image_t *image = NULL; opj_codec_t *codec = NULL; nrt_Uint32 bufSize; const OPJ_UINT32 tileWidth = j2k_Container_getTileWidth(impl->container, error); const OPJ_UINT32 tileHeight = j2k_Container_getTileHeight(impl->container, error); size_t numBitsPerPixel = 0; size_t numBytesPerPixel = 0; nrt_Uint64 fullBufSize = 0; if (!OpenJPEG_setup(impl, &stream, &codec, error)) { goto CATCH_ERROR; } /* unfortunately, we need to read the header every time ... */ if (!opj_read_header(stream, codec, &image)) { /*nrt_Error_init(error, "Error reading header", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } /* only decode what we want */ if (!opj_set_decode_area(codec, image, tileWidth * tileX, tileHeight * tileY, tileWidth * (tileX + 1), tileHeight * (tileY + 1))) { /*nrt_Error_init(error, "Error decoding area", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } { int keepGoing; OPJ_UINT32 tileIndex, nComponents; OPJ_INT32 tileX0, tileY0, tileX1, tileY1; if (!opj_read_tile_header(codec, stream, &tileIndex, &bufSize, &tileX0, &tileY0, &tileX1, &tileY1, &nComponents, &keepGoing)) { /*nrt_Error_init(error, "Error reading tile header", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } if (keepGoing) { /* TODO: The way blockIO->cntl->blockOffsetInc is currently * implemented in ImageIO.c corresponds with how a * non-compressed partial block would be laid out in a * NITF - the actual extra columns would have been read. * Not sure how the J2K data is laid out on disk but * OpenJPEG is hiding this from us if the extra columns are * present there. So whenever we get a partial tile that * isn't at the full width, we need to add in these extra * columns of 0's ourselves. Potentially we could update * ImageIO.c to not require this instead. Note that we * don't need to pad out the extra rows for a partial block * that isn't the full height because ImageIO will never try * to memcpy these in - we only need to get the stride to * work out correctly. */ const OPJ_UINT32 thisTileWidth = tileX1 - tileX0; const OPJ_UINT32 thisTileHeight = tileY1 - tileY0; if (thisTileWidth < tileWidth) { /* TODO: The current approach below only works for single band * imagery. For RGB data, I believe it is stored as all * red, then all green, then all blue, so we would need * a temp buffer rather than reusing the current buffer. */ if (nComponents != 1) { nrt_Error_init( error, "Partial tile width not implemented for multi-band", NRT_CTXT, NRT_ERR_UNK); goto CATCH_ERROR; } numBitsPerPixel = j2k_Container_getPrecision(impl->container, error); numBytesPerPixel = (numBitsPerPixel / 8) + (numBitsPerPixel % 8 != 0); fullBufSize = tileWidth * thisTileHeight * numBytesPerPixel; } else { fullBufSize = bufSize; } if (buf && !*buf) { *buf = (nrt_Uint8*)J2K_MALLOC(fullBufSize); if (!*buf) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } } if (!opj_decode_tile_data(codec, tileIndex, *buf, bufSize, stream)) { /*nrt_Error_init(error, "Error decoding tile", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } if (thisTileWidth < tileWidth) { /* We have a tile that isn't as wide as it "should" be * Need to add in the extra columns ourselves. By marching * through the rows backwards, we can do this in place. */ const size_t srcStride = thisTileWidth * numBytesPerPixel; const size_t destStride = tileWidth * numBytesPerPixel; const size_t numLeftoverBytes = destStride - srcStride; OPJ_UINT32 lastRow = thisTileHeight - 1; size_t srcOffset = lastRow * srcStride; size_t destOffset = lastRow * destStride; OPJ_UINT32 ii; nrt_Uint8* bufPtr = *buf; for (ii = 0; ii < thisTileHeight; ++ii, srcOffset -= srcStride, destOffset -= destStride) { nrt_Uint8* const dest = bufPtr + destOffset; memmove(dest, bufPtr + srcOffset, srcStride); memset(dest + srcStride, 0, numLeftoverBytes); } } } } goto CLEANUP; CATCH_ERROR: { fullBufSize = 0; } CLEANUP: { OpenJPEG_cleanup(&stream, &codec, &image); } return fullBufSize; }
J2KPRIV( NRT_BOOL) OpenJPEG_initImage(OpenJPEGWriterImpl *impl, j2k_WriterOptions *writerOps, nrt_Error *error) { NRT_BOOL rc = NRT_SUCCESS; nrt_Uint32 i, nComponents, height, width, tileHeight, tileWidth; nrt_Uint32 nBytes; j2k_Component *component = NULL; size_t uncompressedSize; int imageType; opj_cparameters_t encoderParams; opj_image_cmptparm_t *cmptParams; OPJ_COLOR_SPACE colorSpace; nComponents = j2k_Container_getNumComponents(impl->container, error); width = j2k_Container_getWidth(impl->container, error); height = j2k_Container_getHeight(impl->container, error); tileWidth = j2k_Container_getTileWidth(impl->container, error); tileHeight = j2k_Container_getTileHeight(impl->container, error); imageType = j2k_Container_getImageType(impl->container, error); /* Set up the encoder parameters. This defaults to lossless. */ /* TODO allow overrides somehow? */ opj_set_default_encoder_parameters(&encoderParams); /* For now we are enforcing lossless compression. If we have a better * way to allow overrides in the future, uncomment out the tcp_rates logic * below (tcp_rates[0] == 0 via opj_set_default_encoder_parameters()). * Also consider setting encoderParams.irreversible = 1; to use the * lossy DWT 9-7 instead of the reversible 5-3. */ /*if (writerOps && writerOps->compressionRatio > 0.0001) encoderParams.tcp_rates[0] = 1.0 / writerOps->compressionRatio; else encoderParams.tcp_rates[0] = 4.0; */ /* TODO: These two lines should not be necessary when using lossless * encoding but appear to be needed (at least in OpenJPEG 2.0) - * otherwise we get a seg fault. * The sample opj_compress.c is doing the same thing with a comment * indicating that it's a bug. */ ++encoderParams.tcp_numlayers; encoderParams.cp_disto_alloc = 1; if (writerOps && writerOps->numResolutions > 0) { encoderParams.numresolution = writerOps->numResolutions; /* Note, if this isn't set right (see below) it will error out */ } else { /* OpenJPEG defaults this to 6, but that causes the compressor to fail if the tile sizes are less than 2^6. So we adjust this down if necessary. */ const double logTwo = log(2); const OPJ_UINT32 minX = (OPJ_UINT32)floor(log(tileWidth) / logTwo); const OPJ_UINT32 minY = (OPJ_UINT32)floor(log(tileHeight) / logTwo); const OPJ_UINT32 minXY = (minX < minY) ? minX : minY; if (minXY < encoderParams.numresolution) { encoderParams.numresolution = minXY; } } /* Turn on tiling */ encoderParams.tile_size_on = 1; encoderParams.cp_tx0 = 0; encoderParams.cp_ty0 = 0; encoderParams.cp_tdx = tileWidth; encoderParams.cp_tdy = tileHeight; if (!(cmptParams = (opj_image_cmptparm_t*)J2K_MALLOC(sizeof( opj_image_cmptparm_t) * nComponents))) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } memset(cmptParams, 0, sizeof(opj_image_cmptparm_t) * nComponents); for(i = 0; i < nComponents; ++i) { component = j2k_Container_getComponent(impl->container, i, error); cmptParams[i].w = j2k_Component_getWidth(component, error); cmptParams[i].h = j2k_Component_getHeight(component, error); cmptParams[i].prec = j2k_Component_getPrecision(component, error); cmptParams[i].x0 = j2k_Component_getOffsetX(component, error); cmptParams[i].y0 = j2k_Component_getOffsetY(component, error); cmptParams[i].dx = j2k_Component_getSeparationX(component, error); cmptParams[i].dy = j2k_Component_getSeparationY(component, error); cmptParams[i].sgnd = j2k_Component_isSigned(component, error); } nBytes = (j2k_Container_getPrecision(impl->container, error) - 1) / 8 + 1; uncompressedSize = width * height * nComponents * nBytes; /* this is not ideal, but there is really no other way */ if (!(impl->compressedBuf = (char*)J2K_MALLOC(uncompressedSize))) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } if (!(impl->compressed = nrt_BufferAdapter_construct(impl->compressedBuf, uncompressedSize, 1, error))) { goto CATCH_ERROR; } if (!(impl->stream = OpenJPEG_createIO(impl->compressed, &impl->userData, 0, 0, error))) { goto CATCH_ERROR; } switch(imageType) { case J2K_TYPE_RGB: colorSpace = OPJ_CLRSPC_SRGB; break; default: colorSpace = OPJ_CLRSPC_GRAY; } if (!(impl->codec = opj_create_compress(OPJ_CODEC_J2K))) { nrt_Error_init(error, "Error creating OpenJPEG codec", NRT_CTXT, NRT_ERR_INVALID_OBJECT); goto CATCH_ERROR; } if (!(impl->image = opj_image_tile_create(nComponents, cmptParams, colorSpace))) { nrt_Error_init(error, "Error creating OpenJPEG image", NRT_CTXT, NRT_ERR_INVALID_OBJECT); goto CATCH_ERROR; } /* for some reason we must also explicitly specify these in the image... */ impl->image->numcomps = nComponents; impl->image->x0 = 0; impl->image->y0 = 0; impl->image->x1 = width; impl->image->y1 = height; impl->image->color_space = colorSpace; memset(error->message, 0, NRT_MAX_EMESSAGE); if(!opj_set_error_handler(impl->codec, OpenJPEG_errorHandler, error)) { nrt_Error_init(error, "Unable to set OpenJPEG error handler", NRT_CTXT, NRT_ERR_UNK); goto CATCH_ERROR; } if (!opj_setup_encoder(impl->codec, &encoderParams, impl->image)) { /*nrt_Error_init(error, "Error setting up OpenJPEG decoder", NRT_CTXT, NRT_ERR_INVALID_OBJECT);*/ goto CATCH_ERROR; } if (!opj_start_compress(impl->codec, impl->image, impl->stream)) { /*nrt_Error_init(error, "Error starting OpenJPEG compression", NRT_CTXT, NRT_ERR_INVALID_OBJECT);*/ goto CATCH_ERROR; } goto CLEANUP; CATCH_ERROR: { rc = NRT_FAILURE; } CLEANUP: { if (cmptParams) J2K_FREE(cmptParams); } return rc; }
OpenJPEG_readHeader(OpenJPEGReaderImpl *impl, nrt_Error *error) { opj_stream_t *stream = NULL; opj_image_t *image = NULL; opj_codec_t *codec = NULL; opj_codestream_info_v2_t* codeStreamInfo = NULL; NRT_BOOL rc = NRT_SUCCESS; OPJ_UINT32 tileWidth, tileHeight; OPJ_UINT32 imageWidth, imageHeight; if (!OpenJPEG_setup(impl, &stream, &codec, error)) { goto CATCH_ERROR; } if (!opj_read_header(stream, codec, &image)) { /*nrt_Error_init(error, "Error reading header", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } codeStreamInfo = opj_get_cstr_info(codec); if (!codeStreamInfo) { /*nrt_Error_init(error, "Error reading code stream", NRT_CTXT, NRT_ERR_UNK);*/ goto CATCH_ERROR; } tileWidth = codeStreamInfo->tdx; tileHeight = codeStreamInfo->tdy; /* sanity checking */ if (!image) { nrt_Error_init(error, "NULL image after reading header", NRT_CTXT, NRT_ERR_UNK); goto CATCH_ERROR; } if (image->x0 >= image->x1 || image->y0 >= image->y1) { nrt_Error_init(error, "Invalid image offsets", NRT_CTXT, NRT_ERR_UNK); goto CATCH_ERROR; } if (image->numcomps == 0) { nrt_Error_init(error, "No image components found", NRT_CTXT, NRT_ERR_UNK); goto CATCH_ERROR; } /* TODO: We need special handling that's not implemented in readTile() to * accommodate partial tiles with more than one band. */ imageWidth = image->x1 - image->x0; imageHeight = image->y1 - image->y0; if (image->numcomps > 1 && (imageWidth % tileWidth != 0 || imageHeight % tileHeight != 0)) { nrt_Error_init(error, "No image components found", NRT_CTXT, NRT_ERR_UNK); goto CATCH_ERROR; } if (!impl->container) { /* initialize the container */ nrt_Uint32 idx; j2k_Component **components = NULL; int imageType; if (!(components = (j2k_Component**)J2K_MALLOC( sizeof(j2k_Component*) * image->numcomps))) { nrt_Error_init(error, NRT_STRERROR(NRT_ERRNO), NRT_CTXT, NRT_ERR_MEMORY); goto CATCH_ERROR; } for(idx = 0; idx < image->numcomps; ++idx) { opj_image_comp_t cmp = image->comps[idx]; if (!(components[idx] = j2k_Component_construct(cmp.w, cmp.h, cmp.prec, cmp.sgnd, cmp.x0, cmp.y0, cmp.dx, cmp.dy, error))) { goto CATCH_ERROR; } } switch(image->color_space) { case OPJ_CLRSPC_SRGB: imageType = J2K_TYPE_RGB; break; case OPJ_CLRSPC_GRAY: imageType = J2K_TYPE_MONO; break; default: imageType = J2K_TYPE_UNKNOWN; } if (!(impl->container = j2k_Container_construct(image->x1 - image->x0, image->y1 - image->y0, image->numcomps, components, tileWidth, tileHeight, imageType, error))) { goto CATCH_ERROR; } } goto CLEANUP; CATCH_ERROR: { rc = NRT_FAILURE; } CLEANUP: { opj_destroy_cstr_info(&codeStreamInfo); OpenJPEG_cleanup(&stream, &codec, &image); } return rc; }