Operations > OP_J2KP, OP_J2KP3D, OP_J2KPRGB |
OP_J2KP, OP_J2KP3D, OP_J2KPRGB : Compress to JPEG2000
See the J2K_UNION, TILECOMP, TILE, PARTITION, REGION, and REGION2 sections for additional information.
JPEG2000 compression may be used to compress images with varying grayscale and color bit depths, including planar and interlaced image formats, grayscale, color-mapped and continuous-tone color images and grayscale images with bit-depths from 1 to 16 bits per sample, signed and/or unsigned pixel values, in big-endian or little-endian order.
JPEG 2000 provides many different compression parameters. These can be independently adjusted to create a large number of useful compression modes. Most users will choose a destination file size by setting one of PF2_ForceLossless, CompFileSize or Rate, and will then sit back and let the OP_J2KP autopilot carry them safely to their desired result. The curious and feckless will attempt to fly manually by independently adjusting the various parameters available in J2K_UNION, TILE, and TILE_COMP.
The output JPEG2000 compressed image can be in the JPEG2000 raw codestream format or in the JPEG2000 JP2 file format controlled by the use of the PF2_SkipJP2Header flag. The former is an excerpt of the latter.
The JPEG2000 compressor supports multiple tiles for images according to the dimensions specified by TileWidth and TileHeight. In most cases a single tile is recommended and both TileWidth and TileHeight are set to 0. Too many tiles increase compression time when TargetPSNR, Rate or CompFileSize is used as the controlling parameter. Too many tiles also reduce image quality for a given TargetPSNR, Rate or CompFileSize because of JPEG 2000 overhead associated with tiles.
JPEG2000 supports both lossy and lossless encoding. The lossless mode uses the reversible wavelet filter (Tilecomp.WaveletTransform = WT_5_3) and uses either the reversible color-space transform or no color-space transform. The lossless mode is most easily selected by setting the PF2_ForceLossless flag which forces use of both the reversible wavelet and the reversible color-space transform.
Both lossy and lossless encoding will be faster, and decompression of the resulting compressed image will be faster, if TCF_Bypass is set in u.J2K.DftTile.DftTileComp.Flags, but at a cost of a few percent larger size of the compressed image.
For fastest encoding and subsequent decompression, set PF2_FavorSpeed. Note that when this flag is set, lossless encoded files may become slightly larger and lossy rate-controlled encoded files may decode to slightly lower quality. Can be combined with PF2_EarlyOutRateControl for best performance.
For lossy mode, the degree of compression is controlled by:
The application can set size or PSNR targets for the individual layers of the output image by setting u.J2K.DftTile.LayerRates to point to an array containing one value per layer plus one additional entry containing the value 0 to terminate the array. Layer size targets are cumulative values; each value indicates the count of bytes to use to encode the corresponding layer plus all previous layers, and the first value indicates the count of bytes to use to encode the first layer plus the main headers. If TF_LayerRatesTargetPSNR is set in u.J2K.DftTile.Flags, then set this field to an array of target PSNR values instead of byte counts, where each value indicates the target quality that the encoded bits for that layer and all previous layers will meet.
The application may set fewer values in the array than one per layer, in which case OP_J2KP will determine the sizes of the unspecified layers subject to the values in u.J2K.Rate or u.J2K.CompFileSize or u.J2K.TargetPSNR, as appropriate. If the application either does not specify a size for the final layer or the size that it does specify for the final layer is sufficiently large, and the application sets values in u.J2K.Rate or u.J2K.CompFileSize or u.J2K.TargetPSNR that are either zero or sufficiently large, then OP_J2KP determines the output image overall file size. If the application sets more values in u.J2K.DftTile.LayerRates than there are layers, the extraneous values will be ignored.
If u.J2K.TargetPSNR is nonzero, it is used to control compression irrespective of the values in u.J2K.Rate and u.J2K.CompFileSize. If the application sets u.J2K.TargetPSNR to zero and both u.J2K.Rate and u.J2K.CompFileSize to nonzero values, OP_J2KP uses the value in u.J2K.CompFileSize and ignores the value in u.J2K.Rate. If all three fields are set to zero and there is a nonzero value in u.J2K.DftTile.LayerRates for the final layer, then that final layer size is the target for the output image overall file size. If one of the fields is nonzero and there are fewer values in u.J2K.DftTile.LayerRates than the number of layers to be created, then the nonzero value in u.J2K.Rate or u.J2K.CompFileSize or u.J2K.TargetPSNR is used only if it is larger than the size of the last specified layer; otherwise, it is increased to the size of that last specified layer, that size becomes the target for the output image overall file size, and the number of layers to be created is reduced to match the number of layers in the u.J2K.DftTile.LayerRates array.
Compression is performed using the familiar REQ_INIT - REQ_EXEC - REQ_TERM process. Before REQ_INIT, the application specifies the input image dimensions and compression parameters. This is done either by filling in PicParm.Head and setting F_Bmpin PicParm.Flags or by filling in the J2K_Union.Region structure and setting F_Raw in PicParm.Flags. If F_Bmp is set then 9-16 bit images cannot be input and the image is assumed to be bottom-up with unsigned samples in BGR (for RGB images) sample order and with each pixel row padded to a 32-bit (DWORD) boundary. Setting TileHeight, TileWidth, TileXOff, and TileYOff to 0 is ordinarily recommended. REQ_INIT returns the minimum allowed Get buffer size in StripSize. The application then allocates and fills a Get buffer of at least StripSize bytes with image data.
In order to support larger images, this opcode supports the optional use of REGION2. If ParmVerMinor is set to 4, then the opcode treats u.J2K.Region as a REGION2 structure instead of a REGION structure. Otherwise, ParmVerMinor should be set to 3. See the REGION2 section for more information
For even larger images or other situations where memory is a concern, this opcode offers a reduced-memory mode of operation. More details of this mode can be found in the Reduced-Memory Mode section below.
If PF_YieldGet is set in u.J2K.PicFlags then OP_J2KP will return a RES_GET_DATA_YIELD response periodically during compression. This would allow an application to update compression progress reporting for example.
After REQ_INIT returns RES_DONE, the application performs the REQ_EXEC phase. If desired, the Put buffer can be allocated during the REQ_EXEC phase instead of prior to REQ_EXEC by allocating it within the RES_PUT_NEED_SPACE response handler. The Put buffer will be filled with JPEG2000 compressed data during the compression process.
The application can use PIC2List P2P_Comment packets to supply OP_ J2KP with one or more comments to be embedded in the output compressed file. JPEG 2000 errors or warnings returned from the underlying JPEG 2000 library optionally return additional descriptive text in PIC2List if there is enough space or if the application reacts to RES_EXTEND_PIC2LIST responses. In that case, ERR_PIC2LIST_HAS_DESCRIPTION is returned in Status and the information about the error appears in P2PktErrorText packets with Type P2P_ErrorText. Certain types of metadata are also input on the PIC2List and are discussed in the following Metadata section. See include\pic2file.h and the PIC2List section of Accessing Comments and Other Auxiliary Data in the PICTools Programmer's Guide for more information about PIC2List packets.
Only partition 0 can be an RGB partition.
For RGB images, either set F_Bmp in PicParm.Flags and fill in the PicParm.Head fields or set F_Raw in PicParm.Flags and fill in the u.J2K.Region fields. 24 bit-per-pixel RGB images are supported. 32 bit-per-pixel RGBA images are allowed as input but the fourth component sample is not compressed. The information is discarded. The default interleaved pixel component sample ordering is Blue/Green/Red. If the component sample ordering is Red/Green/Blue, then set F_Raw in PicParm.Flags and set RF_SwapRB in u.J2K.Region.Flags.
By default, the RGB samples are converted to the YCbCr color-space. The reversible color transform is used if PF2_ForceLossess is set or if the reversible wavelet transform is used. Otherwise, the irreversible color transform is used. Set u.J2K.DftTile.TileCompTransform to TCT_None to compress the actual RGB samples without first converting to YCbCr.
Only partition 0 can be a color-mapped partition.
Set F_Bmp in PicParm.Flags and fill in the PicParm.Head fields or set F_Raw in PicParm.Flags and fill in the u.J2K.Region fields. Packed pixels, i.e. more than one pixel per byte, are not supported. Set PicParm.Head.biClrUsed to the number of colors in the color map. Set PicParm.ColorTable according to the colors in the color map.
The pixel color indices can be compressed as the corresponding RGB values instead of compressing the color index values themselves by specifying RF_CM2RGB in Region.Flags. If all color map colors are gray, then specifying RF_CM2RGB will compress as the corresponding gray image.
If the number of colors is 2BitsPerPixel, and all the colors in the color map are gray, and the red, green and blue intensity values for each color index are equal to the color index, then the image is compressed as a gray image and not as a color-mapped image.
Compression of pixel color indices requires that lossless compression be specified, that PicParm.Head.biClrUsed is not 0, and that PF2_SkipJP2Header is not set, otherwise the image is compressed as though RF_CM2RGB were set. When pixel color indices are compressed, the PF2_KeepColorTable is ignored and the color table is always retained in the JP2 file format.
For partition 0, set F_Bmp in PicParm.Flags and fill in the PicParm.Head fields or set F_Raw in PicParm.Flags and fill in the u.J2K.Region fields. Packed pixels, i.e., more than one pixel per byte, are not supported. For partitions N other than 0, fill in the u.J2K.OtherPartition[N].Region fields (see Images with Planar Components below).
Set RF_2Byte in Region.Flags if the 1 to 8 bit-per-sample values are contained in two bytes. Set Region.PixType to PT_GRAYM if the second byte contains the intensity value and the first byte will be ignored. Otherwise set Region.PixType to PT_GRAY and the first byte contains the intensity value and the second byte will be ignored.
Set RF_Signed if the sample values are signed.
For partition 0, set F_Raw in PicParm.Flags and fill in the u.J2K.Region fields. For partitions N other than 0, fill in the u.J2K.OtherPartition[N].Region fields (see Images with Planar Components below).
Set Region.PixType to PT_GRAYM if the sample bytes are ordered in Motorola/big-endian format where the first byte (lesser memory address) has the most significant bits of the sample value and the second byte has bits 0-7 of the sample value. Otherwise set Region.PixType to PT_GRAY and the sample bytes are ordered in Intel/little-endian format and the first byte has bits 0-7 of the sample value and the second byte has the most significant bytes of the sample value.
Set RF_Signed if the sample values are signed.
The u.J2K.Region fields allow an image with 3 interleaved RGB components, a single grayscale, or a single color-mapped component to be described. To describe more complicated images, allocate an array of PARTITION data structures. Each element of the array describes a single component to be compressed. The first PARTITION, partition number 0, is specified by u.J2K.Region, u.J2K.StripSize and PicParm.Get. Partition 0 may specify three components (RGB) or one color-mapped component consisting of pixel color indices or one other component that is ordinarily grayscale data of 1-16 bits per sample. Partitions number 1 through u.J2K.NumOtherPartitions - 1, each specify a single other component. Partition number 1 is described by u.J2K.OtherPartitions[0], etc.
When input data for partition 0 is needed, a RES_GET_NEED_DATA response is returned, u.J2K.PartitionNum will be 0, and the data will be returned in the PicParm.Get queue. When input data for partition N is needed, a RES_GET_NEED_DATA response is returned, u.J2K.PartitionNum will be N, and the data will be returned in the u.J2K.OtherPartitions[N].Queue queue. Each u.J2K.OtherPartitions[N].Queue must be at least u.J2K.OtherPartitions[N].StripSize bytes in size.
Partition 0 subsampled components are not supported. Other partitions may be subsampled horizontally and/or vertically up to 16384:1 with respect to the partition 0 samples. OP_J2KP does not itself subsample the component, but rather allows an input component that has already been subsampled.
An application ordinarily specifies that the partition N component is subsampled by setting u.J2K.OtherPartitions[N].Region.Width and u.J2K.OtherPartitions[N].Region.Height values to the subsampled component width and height.
If Region.Width and Region.Height are 0, subsampling factors of 2:1 through 8:1 can be specified in u.J2K.OtherPartitions[N].Region.Interlace (see the REGION description).
A canvas is defined as a rectangle:
By JPEG 2000 specification, all subsampled image components would have a sample coinciding with the canvas point (0, 0) if the image were made exactly as large as the canvas. Therefore if some subsampled image component sample does not coincide with the top-left corner point of an unsubsampled component, then the top-left-corner of the image rectangle cannot coincide with canvas point (0, 0), but must instead coincide with some other canvas point (u.J2K.ImageXOff, u.J2K.ImageYOff).
In the physical world, a subsampled component's samples may not exactly coincide with canvas points, but may more accurately be regarded as being offset between points by some fraction of a unit horizontally and/or vertically. JPEG 2000 allows this component registration to be specified in the compressed file, but OP_J2KP does not presently allow this to be specified.
In order to control the location of tile boundary artifacts in the decompressed image or for some other reason, it may be desirable for the top-left-corner pixel in the (0, 0) tile to be at a different canvas location from the top-left-corner pixel in the image. For this reason, (u.J2K.ImageXOff, u.J2K.ImageYOff) may be different from (0, 0) even in an image with no subsampled components. For an unsubsampled component, at least the top-left-corner pixel in the image must be contained in the (0, 0) tile. The position on the canvas of the top-left-corner pixel of the (0, 0) tile is (u.J2K.TileXOff, u.J2K.TileYOff).
A subrectangle of the input image can be compressed by setting F_Crop in PicParm.Flags and setting PicParm.CropXoff, PicParm.CropYoff, PicParm.CropWidth, and PicParm.CropHeight to describe the subrectangle. PicParm.CropXoff and PicParm.CropYoff are offsets within the image and not within the canvas. OP_J2KP will still read sequentially through the first PicParm.CropYOff lines in each component input buffer in order to be positioned at the first line to be compressed.
The image's X and Y offset in the canvas as stored in the compressed file are u.J2K.ImageXOff + PicParm.CropXoff and u.J2K.ImageYOff + PicParm.CropYoff.
The compression options for images to be transmitted to a client for best OP_JPIPSERVER performance in stateless mode are:
u.J2K.DftTile.ProgressionOrder = PO_LRCP; or
u.J2K.DftTile.ProgressionOrder = PO_RLCP;
u.J2K.DftTile.DftTileComp.PrecinctWidth = 128;
u.J2K.DftTile.DftTileComp.PrecinctHeight = 128;
u.J2K.PicFlags2 |= PF2_InsertPPMMarker;
The compression options for images to be transmitted to a client for best OP_TIDP2 performance in sessionless mode are:
u.J2K.DftTile.ProgressionOrder = PO_RPCL;
u.J2K.DftTile.DftTileComp.PrecinctWidth = 128;
u.J2K.DftTile.DftTileComp.PrecinctHeight = 128;
u.J2K.DftTile.Flags |= TF_TilePartResolution;
u.J2K.DftTile.Flags |= TF_InsertPLTMarker;
u.J2K.PicFlags2 |= PF2_InsertTLMMarker;
In addition, the number of layers u.J2K.DftTile.NumLayers, is a tradeoff between the amount of input image data OP_TIDP2 has to read to satisfy successive, sessionless-mode, requests - best for NumLayers = 1 - and the smoothness of client updates for smaller bandwidths - best for NumLayers some larger number of layers.
The opcode provides a means to drastically reduce the amount of memory required for encoding, thereby making it possible to encode extremely large images and/or operate where memory is otherwise limited. To use this mode, set the PF2_ReducedMemoryMode flag in u.J2K.PicFlags2 before REQ_INIT; for best performance, request only one layer, the PCRL progression order, and small precincts (128x128 recommended).
In reduced-memory mode, rate control is less sophisticated and the opcode may not hit a target as closely as in normal mode. To set a target size value greater than what fits in the u.J2K.CompFileSize,field, either set a value in u.J2K.Rate or set u.J2K.CompFileSize to the lower 32 bits of the target size and u.J2K.CompFileSizeHigh to the upper 32 bits. The rate control in reduced-memory mode precludes encoding to a quality measure and therefore requesting a PSNR target is not allowed.
It is possible to request more than one tile be created but to do so the opcode must be able to seek in the output stream. The application must signal its ability to seek by setting the PF2_UseResSeek flag in u.J2K.PicFlags2. This is the only situation where this opcode needs to be able to seek. If seeking is enabled, be sure to use the values in the PicParm.SeekOffsetLow and PicParm.SeekOffsetHigh fields when responding to a RES_SEEK request from the opcode in order to get the correct seek offset for extremely large images.
In reduced-memory mode, it is not possible for the opcode to create tile parts and the opcode therefore simply ignores the flags TF_TilePartResolution, TF_TilePartLayer, and TF_TilePartComponent flags. Inserting markers is not possible and the opcode disallows the TF_InsertPLTMarker, the PF2_InsertPPMMarker, and the PF2_InsertTLMMarker flags.
Multithreading Considerations:
In general, multithreaded compression will frequently lead to a different compressed output file for successive compressions of the same image with the same compression options. If lossless compression is used, the decompressed result will match the original input image.
For lossy compression, it should be noted that reduced memory mode is primarily intended to be used for very large images where memory utilization is a concern. Using this mode is not recommended for encoding smaller images using multithreading, particularly in conjunction with rate control that targets an output file size or an output bit-rate. This is because a substantial reduction in image quality could result when compared to encoding with a single core. In addition, the output file size can vary excessively between runs and can vary excessively from the targeted size. Single core encoding, lossless encoding, and lossy encoding without specifying a target output size or bit rate do not experience this issue, and the decompressed results will have closely similar quality output within the tolerance of the compressed rate.
The opcode provides a means to use features of Part-2 of the JPEG2000 standard to encode volumetric data more efficiently than encoding each slice of data independently. Set PF2_3D_Slices in u.J2K.PicFlags2 before REQ_INIT and the opcode will consider partitions to be slices of volumetric data. They will be encoded together as a JPEG2000 Part-2 3D image. The output JPEG2000 compressed image can be in the JPEG2000 raw codestream format or in the JPEG2000 JPX file format controlled by the use of the PF2_SkipJP2Header flag.
The number of slices to encode is determined by the number of partitions provided to the opcode at REQ_INIT. Each partition carries data for one slice and can contain interleaved RGB samples (8 bits per sample; 24 bpp) or grayscale samples (up to 16 bits). Color-mapped images are not allowed. Subsampling is not allowed. The opcode performs a one-dimensional wavelet transform across the slices and then a two-dimensional wavelet transform within each slice. For RGB data, a color transform is performed prior to the one-dimensional wavelet. The Tile.TileCompTransformfield is ignored.
Set F_Raw in PicParm.Flags and fill in the u.J2K.Region fields for the first partition. Fill in the u.J2K.OtherPartition array for the other partitions. All partitions must have identical characteristics and therefore the same values in the Region structures. In order to meet limitations set by the JPEG2000 standard, there is a maximum of 16384 grayscale partitions or 5461 RGB partitions allowed.
The degree of compression is controlled by:
The opcode accepts P2PktUUIDBox, P2PktUUIDDataEntryURL, P2PktXMLBox, and P2PktIPTCDataSet packets on the PIC2List.
The P2PktIPTCDataSet packets will be combined into a UUID Box with UUID 33c7a4d2-b81d-4723-a0ba-f1a3e097ad38.
The P2PktXMLBox must contain a NULL terminated char* string. If the XML data is UTF-16 it must start with a Byte Order Marker (BOM) and end with two NULLs.
The P2PktUUIDDataEntryURL packets will be combined into UUID Info Boxes based on the URL field. To be combined correctly the URL fields must match case-sensitively and exactly.
The user can provide an ICC profile of restricted type to be put into the Color Specification box by setting u.J2K.ColorSpecMethod to J2K_COLOR_SPEC_METHOD_ICP, pointing u.J2K.ColorSpecICCProfileData to a valid ICC Profile, and setting u.J2K.ColorSpecICCProfileLen to the length of the data pointed to by u.J2K.ColorSpecICCProfileData. The opcode expects the user to provide a valid restricted ICC profile and no other type. It is the user's responsibility to allocate and free the memory pointed to by u.J2K.ColorSpecICCProfileData.
The user can create Resolution Boxes, Capture or Display, by setting PIC_PARM.opcodeExtraPtr to point to a J2K_EXTRA structure and setting opcodeExtraPtr->CaptureResVert, opcodeExtraPtr->CaptureResHorz, or opcodeExtraPtr->DisplayResVert, opcodeExtraPtr->DisplayResHorz. If a Vert value is set to a non-zero value then the corresponding Horz value must also be set to a non-zero value.