API review - Image Ops (RT-17409)

Jim Graham james.graham at oracle.com
Mon May 14 23:39:09 PDT 2012


Here is my issue with that, and it's a sort of odd one.

I've sometimes used a hack where I specify a scan stride of 0 as really 
meaning "0", not "this is a useless value, please pick it for me".  In 
particular, 0 is not useless.  You can replicate image data across rows 
by specifying a scan of 0.  I used this in an interlaced GIF converter 
to easily replicate the decoded rows - which are typically duplicated 
across 8 rows on the first pass, 4 rows on the second, etc.  It's not 
something I find useful in very many contexts, but it could be useful 
for someone.  Negative strides can also be useful for reversing image 
layouts (some Windows formats have "bottom up" layout which requires a 
negative scan stride to fix).  Unfortunately, we cannot directly take 
advantage of that with the following API because the only data storage 
that is used in these methods is a Buffer that is positioned at the 
beginning of the first row and negative indices don't work.  In a future 
version of the API we could add overrides that allow a Buffer plus a 
start offset and/or take raw primitive arrays with an offset - then a 
negative scan stride could be useful.

Perhaps I could provide overrides that simply omit the parameter and 
then we'll figure it out for you?

			...jim

On 5/14/2012 7:29 PM, Kevin Rushforth wrote:
> Looks good to me.
>
> One question: often a value of 0 for stride is used to mean "pack
> adjacent rows as tightly as possible" (possibly subject to alignment
> rules for pixel data with less than 4 components per pixel). Do you plan
> to support that?
>
> -- Kevin
>
>
> Jim Graham wrote:
>> http://javafx-jira.kenai.com/browse/RT-17409
>>
>> I've added a couple of new classes and a small number of new methods
>> to provide pixel access to images. I am not yet done with the
>> implementation so I can't really share a webrev yet, but I need to get
>> the API approved before our API freeze, so here are the new classes
>> and methods:
>>
>> javafx.scene.image.Image (new methods):
>>
>> /**
>> * Construct a new empty {@code Image} with the specified dimensions
>> * filled with transparent pixels to be used with the
>> * {@link #setArgb(int, int, int) setArgb()}
>> * and
>> * {@link #setColor(int, int, javafx.scene.paint.Color) setColor()}
>> * methods to create a completely custom image.
>> *
>> * @param width the width of the empty image
>> * @param height the height of the empty image
>> */
>> public Image(int width, int height);
>>
>> /**
>> * This method returns the {@code PixelFormat} in which the image stores
>> * its pixels, or a roughly equivalent pixel format into which it can
>> * easily convert its pixels for purposes of reading and writing them.
>> * If this method returns null then this image does not support reading
>> * and writing of pixels in any format and all of the methods to
>> * get and set pixels will throw an {@link UnsupportedOperationException}.
>> * This method will return null if the image is being loaded from a
>> * source and is still incomplete {the progress is still < 1.0) or if
>> * there was an error.
>> * This method may also return null for some images in a format that
>> * is not supported for reading and writing pixels to.
>> *
>> * @return the {@code PixelFormat} that best describes the underlying
>> * pixels
>> */
>> public PixelFormat getPixelFormat() {
>>
>> /**
>> * Reads a 32-bit integer representation of the color of a pixel
>> * from the specified coordinates in the image.
>> * The 32-bit integer will contain the 4 color components in separate
>> * 8-bit fields in ARGB order from the most significant byte to the least
>> * significant byte.
>> *
>> * @param x the X coordinate of the pixel color to read
>> * @param y the Y coordinate of the pixel color to read
>> * @return a 32-bit representation of the color in a format described
>> * by the {@link PixelFormat.Type.BYTE_ARGB} PixelFormat type.
>> * @throws UnsupportedOperationException if the image pixels are not
>> * accessible
>> * @see #getPixelFormat()
>> */
>> public int getArgb(int x, int y) {
>> return checkPixelAccess(true, false).getArgb(x, y);
>> }
>>
>> /**
>> * Reads the color of a pixel from the specified coordinates in the
>> * image and returns the value as a {@link Color} object.
>> *
>> * @param x the X coordinate of the pixel color to read
>> * @param y the Y coordinate of the pixel color to read
>> * @return the Color object representing the color of the indicated
>> * pixel
>> * @throws UnsupportedOperationException if the image pixels are not
>> * accessible
>> * @see #getPixelFormat()
>> */
>> public Color getColor(int x, int y);
>>
>> * Stores pixel data for a color into the specified coordinates of the
>> * image.
>> * The 32-bit integer {@code argb} parameter will contain the 4 color
>> * components in separate 8-bit fields in ARGB order from the most
>> * significant byte to the least significant byte.
>> *
>> * @param x the X coordinate of the pixel color to write
>> * @param y the Y coordinate of the pixel color to write
>> * @param argb the color information to write, specified in a format
>> * described by the {@link PixelFormat.Type.BYTE_ARGB}
>> * PixelFormat type.
>> * @throws UnsupportedOperationException if the image pixels are not
>> * accessible
>> * @see #getPixelFormat()
>> */
>> public void setArgb(int x, int y, int argb);
>>
>> /**
>> * Stores pixel data for a {@link Color} into the specified coordinates
>> * of the image.
>> *
>> * @param x the X coordinate of the pixel color to write
>> * @param y the Y coordinate of the pixel color to write
>> * @param c the Color to write
>> * @throws UnsupportedOperationException if the image pixels are not
>> * accessible
>> * @see #getPixelFormat()
>> */
>> public void setColor(int x, int y, Color c);
>>
>> /**
>> * Reads pixel data from a rectangular region of the image into the
>> * specified buffer.
>> * The format of the pixels in the buffer are defined by the
>> * {@link PixelFormat} object and pixel format conversions will be
>> * performed as needed.
>> * The buffer is assumed to be positioned to the location where the
>> * first pixel data from the image pixel at location {@code (x, y)}
>> * will be stored.
>> * Pixel data for a row will be stored in adjacent locations within
>> * the buffer packed as tightly as possible for increasing X
>> * coordinates.
>> * Pixel data for adjacent rows will be stored offset from each other
>> * by the number of buffer data elements defined by
>> * {@code scanlineStride}.
>> *
>> * @param x the X coordinate of the rectangular region to read
>> * @param y the Y coordinate of the rectangular region to read
>> * @param w the width of the rectangular region to read
>> * @param h the height of the rectangular region to read
>> * @param buffer a buffer of a type appropriate for the indicated
>> * {@code PixelFormat} object
>> * @param pixelformat the {@code PixelFormat} object defining the format
>> * to store the pixels into buffer
>> * @param scanlineStride the distance between the pixel data for the
>> * start of one row of data in the buffer to the start of the
>> * next row of data.
>> * @throws UnsupportedOperationException if the image pixels are not
>> * accessible
>> * @see #getPixelFormat()
>> */
>> public <T extends Buffer>
>> void getPixels(int x, int y, int w, int h,
>> T buffer, WritablePixelFormat<T> pixelformat,
>> int scanlineStride);
>>
>> /**
>> * Stores pixel data from a buffer into a rectangular region of the
>> * image.
>> * The format of the pixels in the buffer are defined by the
>> * {@link PixelFormat} object and pixel format conversions will be
>> * performed as needed.
>> * The buffer is assumed to be positioned to the location where the
>> * first pixel data to be stored in the image pixel at location
>> * {@code (x, y)} is located.
>> * Pixel data for a row will be stored in adjacent locations within
>> * the buffer packed as tightly as possible for increasing X
>> * coordinates.
>> * Pixel data for adjacent rows will be stored offset from each other
>> * by the number of buffer data elements defined by
>> * {@code scanlineStride}.
>> *
>> * @param x the X coordinate of the rectangular region to write
>> * @param y the Y coordinate of the rectangular region to write
>> * @param w the width of the rectangular region to write
>> * @param h the height of the rectangular region to write
>> * @param buffer a buffer of a type appropriate for the indicated
>> * {@code PixelFormat} object
>> * @param pixelformat the {@code PixelFormat} object defining the format
>> * of the pixels in the buffer
>> * @param scanlineStride the distance between the pixel data for the
>> * start of one row of data in the buffer to the start of the
>> * next row of data.
>> * @throws UnsupportedOperationException if the image pixels are not
>> * accessible
>> * @see #getPixelFormat()
>> */
>> public <T extends Buffer>
>> void setPixels(int x, int y, int w, int h,
>> T buffer, PixelFormat<T> pixelformat,
>> int scanlineStride);
>>
>> =========================================================
>>
>> javafx.scene.image.PixelFormat:
>>
>> /**
>> * A {@code PixelFormat} object defines the layout of data for a pixel of
>> * a given format.
>> */
>> public abstract class PixelFormat<T extends Buffer> {
>> public enum Type {
>> /**
>> * The pixels are stored in 32-bit integers with the premultiplied
>> * components stored in order, from MSb to LSb:
>> * alpha, red, green, blue.
>> */
>> INT_ARGB_PRE,
>> /**
>> * The pixels are stored in 32-bit integers with the non-premultiplied
>> * components stored in order, from MSb to LSb:
>> * alpha, red, green, blue.
>> */
>> INT_ARGB,
>> /**
>> * The pixels are stored in adjacent bytes with the premultiplied
>> * components stored in order of increasing index:
>> * blue, green, red, alpha.
>> */
>> BYTE_BGRA_PRE,
>> /**
>> * The pixels are stored in adjacent bytes with the non-premultiplied
>> * components stored in order of increasing index:
>> * blue, green, red, alpha.
>> */
>> BYTE_BGRA,
>> /**
>> * The opaque pixels are stored in adjacent bytes with the color
>> * components stored in order of increasing index:
>> * red, gree, blue.
>> */
>> BYTE_RGB,
>> /**
>> * The pixel colors are referenced by byte indices stored in the
>> * pixel array, with the byte interpreted as an unsigned index into
>> * a list of colors provided by the {@code PixelFormat} object.
>> */
>> BYTE_INDEXED,
>> }
>>
>> // Static factory methods
>> public static WritablePixelFormat<IntBuffer> getArgbInstance();
>>
>> public static WritablePixelFormat<IntBuffer> getArgbPreInstance();
>>
>> public static WritablePixelFormat<ByteBuffer> getByteBgraInstance();
>>
>> public static WritablePixelFormat<ByteBuffer> getByteBgraPreInstance();
>>
>> public static PixelFormat<ByteBuffer> getByteRgbInstance();
>>
>> public static PixelFormat<ByteBuffer>
>> createByteIndexedPremultipliedInstance(int colors[]);
>>
>> public static PixelFormat<ByteBuffer>
>> createByteIndexedInstance(int colors[]);
>>
>> // Informational getters
>> public Type getType();
>>
>> public boolean isWritable();
>>
>> public boolean isPremultiplied();
>>
>> // Pixel access methods
>>
>> /**
>> * Reads a 32-bit integer representation of the color from the buffer
>> * at the specified coordinates.
>> * The 32-bit integer will contain the 4 color components in separate
>> * 8-bit fields in ARGB order from the most significant byte to the least
>> * significant byte.
>> * The buffer should be positioned to the start of the pixel data such
>> * that {@code buf.get(0)} would return the pixel information for the
>> * pixel at coordinates {@code (0, 0)}.
>> * The {@scanlineStride} parameter defines the distance from the pixel
>> * data at the start of one row to the pixel data at the start of the
>> * immediately following row at the next higher Y coordinate. Usually,
>> * {@scanlineStride} is the same as the width of the image multiplied
>> * by the number of data elements per pixel (1 for the case of the
>> * integer and indexed formats, or 3 or 4 in the case of the byte
>> * formats), but some images may have further padding between rows for
>> * alignment or other purposes.
>> *
>> * @param buf the buffer of pixel data
>> * @param x the X coordinate of the pixel to be read
>> * @param y the Y coordinate of the pixel to be read
>> * @param scanlineStride the number of buffer elements between the
>> * start of adjacent pixel rows in the buffer
>> * @return a 32-bit value with the color of the pixel in a format
>> * similar to the {@code Type.INT_ARGB} pixel format
>> */
>> public abstract int getArgb(T buf, int x, int y, int scanlineStride);
>> }
>>
>> =========================================================
>>
>> javafx.scene.image.WritablePixelFormat:
>>
>> /**
>> * A {@link PixelFormat} object representing a pixel format that can store
>> * full colors and so can be used as a destination format to write pixel
>> * data from an arbitrary image.
>> */
>> public abstract class WritablePixelFormat<T extends Buffer>
>> extends PixelFormat<T>
>> {
>> /**
>> * Stores a 32-bit integer representation of the color in the buffer
>> * at the specified coordinates.
>> ... Similar wording to the getArgb method above...
>> * @param argb a 32-bit value with the color to be stored in the pixel
>> * in a format similar to the {@code Type.INT_ARGB} pixel format
>> */
>> public abstract void setArgb(T buf, int x, int y, int scanlineStride,
>> int argb);
>> }
>>
>> =========================================================
>>
>> ...jim


More information about the openjfx-dev mailing list