/** * Set one pixel value at the correct index in this field. Basically a single pixel set, but it * could also be width, height, number of components. This must be used with great care as it * could well corrupt the user data. * * @param index The position in the array to set * @param value The value to use at that position */ public void set1Value(int index, int value) throws ArrayIndexOutOfBoundsException { checkReadAccess(); checkWriteAccess(); if (value < 0) throw new IllegalArgumentException("Pixels may not be negative."); if (index < 0) throw new ArrayIndexOutOfBoundsException(); synchronized (theEventQueue.eventLock) { MFImageWrapper queuedElement = (MFImageWrapper) theEventQueue.getLast(this); boolean newEvent = false; if (queuedElement == null || !queuedElement.isSetOneValue) { // Input and output buffers do not mix if (!storedInput && !storedOutput) { queuedElement = this; loadInputValue(); isSetOneValue = true; } else { queuedElement = new MFImageWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true); queuedElement.isSetOneValue = true; } newEvent = true; } queuedElement.storedInputValue[index] = value; queuedElement.rogueInputData = true; if (newEvent) theEventQueue.processEvent(queuedElement); } }
/** * Inserts a value into an existing index of the field. Current field values from the index to the * end of the field are shifted down and the field length is increased by one to accomodate the * new element. * * <p>This method modifies the integer array rather than the conceptual image array. * * <p>If the index is out of the bounds of the current field an ArrayIndexOutofBoundsException * will be generated. * * @param index The position at which to insert * @param value The new element to insert * @exception ArrayIndexOutOfBoundsException The index was outside the current field size. */ public void insertValue(int index, int value) throws ArrayIndexOutOfBoundsException { checkReadAccess(); checkWriteAccess(); synchronized (theEventQueue.eventLock) { MFImageWrapper queuedElement = (MFImageWrapper) theEventQueue.getLast(this); boolean newEvent = false; if (queuedElement == null || !queuedElement.isSetOneValue) { // Input and output buffers do not mix if (!storedInput && !storedOutput) { queuedElement = this; loadInputValue(); isSetOneValue = true; } else { queuedElement = new MFImageWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true); queuedElement.isSetOneValue = true; } newEvent = true; } queuedElement.ensureArraySize(queuedElement.storedInputLength + 1); System.arraycopy( queuedElement.storedInputValue, index, queuedElement.storedInputValue, index + 1, queuedElement.storedInputLength - index); queuedElement.storedInputValue[index] = value; queuedElement.storedInputLength++; queuedElement.rogueInputData = true; if (newEvent) theEventQueue.processEvent(queuedElement); } }
/** * Copy a region of the argument RenderedImage to replace a portion of the current SFimage. * * <p>The sub image set shall not resize the base image representation and therefore performs an * intersection clip of the provided image. The user provided image shall be of the same format * (pixel depth, pixel representation) as the original image obtained through the getImage() * method. * * <p>RenderedImages are row order from top to bottom. A 4x8 RenderImage is indexed as follows: * * <PRE> * * X >01234567 * ---------- * 0 |********| * 1 |********| * 2 |********| * 3 |********| * ^ ---------- * Y * * </PRE> * * SFImages are row order from bottom to top. A 4x8 RenderImage is indexed as follows: * * <PRE> * * X >01234567 * ---------- * 3 |********| * 2 |********| * 1 |********| * 0 |********| * ^ ---------- * Y * * </PRE> * * <p>Note: The parameter srcYOffset is referenced to the RenderedImage object (indexed top to * bottom). <br> * The parameter destYOffset is referenced to the SFImage object (indexed bottom to top). * * @param imgIndex The index of the image in the array * @param img The new image to use as the source * @param srcWidth The width of the argument sub-image region to copy * @param srcHeight The height of the argument sub-image region to copy * @param srcXOffset The initial x dimension (width) offset into the argument sub-image that * begins the region to copy * @param srcYOffset The initial y dimension (height) offset into the argument sub-image that * begins the region to copy * @param destXOffset The initial x dimension (width) offset in the SFimage object that begins the * region to receive the copy * @param destYOffset The initial y dimension (height) offset in the SFimage object that begins * the region to receive the copy */ public void setSubImage( int imgIndex, RenderedImage img, int srcWidth, int srcHeight, int srcXOffset, int srcYOffset, int destXOffset, int destYOffset) throws InvalidOperationTimingException, InvalidFieldValueException, InvalidWritableFieldException, InvalidFieldException { checkWriteAccess(); if (imgIndex < 0) throw new ArrayIndexOutOfBoundsException(); synchronized (theEventQueue.eventLock) { MFImageWrapper queuedElement = (MFImageWrapper) theEventQueue.getLast(this); if (queuedElement == null || !queuedElement.isSetOneValue) { // Input and output buffers do not mix if (!storedInput && !storedOutput) { // Avoid clogging this buffer if // index out of bounds if (imgIndex >= storedInputValue.length) throw new ArrayIndexOutOfBoundsException(); queuedElement = this; loadInputValue(); isSetOneValue = true; // TODO: Insert image values } else { // If this generates an ArrayIndexOutOfBounds its okay, // the element will be garbage. queuedElement = new MFImageWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true); queuedElement.isSetOneValue = true; // TODO: Insert image values } theEventQueue.processEvent(queuedElement); } else { checkDataSanity(); // TODO: Insert image values } } }
/** @see org.web3d.x3d.sai.MFImage#removeValue(int) */ public void removeValue(int index) throws ArrayIndexOutOfBoundsException { checkReadAccess(); checkWriteAccess(); synchronized (theEventQueue.eventLock) { MFImageWrapper queuedElement = (MFImageWrapper) theEventQueue.getLast(this); boolean newEvent = false; if (queuedElement == null || !queuedElement.isSetOneValue) { // Input and output buffers do not mix if (!storedInput && !storedOutput) { queuedElement = this; loadInputValue(); isSetOneValue = true; } else { queuedElement = new MFImageWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true); queuedElement.isSetOneValue = true; } newEvent = true; } // Removing a raw byte, rather than an image value. if (queuedElement.storedInputLength > 0) { if (index + 1 < queuedElement.storedInputLength) System.arraycopy( queuedElement.storedInputValue, index + 1, queuedElement.storedInputValue, index, queuedElement.storedInputLength - index - 1); queuedElement.storedInputLength--; queuedElement.rogueInputData = true; if (newEvent) theEventQueue.processEvent(queuedElement); } else { // Free up the buffer before throwing the exception if (newEvent) queuedElement.isSetOneValue = false; throw new ArrayIndexOutOfBoundsException(); } } }
/** * Set the image value in the given writable field to the new image defined by a set of pixels. * * <p> * * @param imgIndex The index of the image in the array * @param img The new image to use as the source */ public void setImage(int imgIndex, RenderedImage img) throws InvalidOperationTimingException, InvalidFieldValueException, InvalidWritableFieldException, InvalidFieldException { if (imgIndex < 0) throw new ArrayIndexOutOfBoundsException(); checkWriteAccess(); synchronized (theEventQueue.eventLock) { MFImageWrapper queuedElement = (MFImageWrapper) theEventQueue.getLast(this); if (queuedElement == null || !queuedElement.isSetOneValue) { // Input and output buffers do not mix if (!storedInput && !storedOutput) { // Avoid clogging this buffer if // index out of bounds if (imgIndex < 0) throw new ArrayIndexOutOfBoundsException(); loadInputValue(); if (imgIndex >= storedInputValue.length) throw new ArrayIndexOutOfBoundsException(); queuedElement = this; loadInputValue(); isSetOneValue = true; } else { // If this generates an ArrayIndexOutOfBounds its okay, // the element will be garbage. queuedElement = new MFImageWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true); queuedElement.isSetOneValue = true; } queuedElement.rewriteImageToSize(imgIndex, img.getWidth(), img.getHeight()); SFImageUtils.convertRenderedImageToData( img, queuedElement.storedInputValue, queuedElement.findStartOfInputImage(imgIndex)); theEventQueue.processEvent(queuedElement); } else { checkDataSanity(); queuedElement.rewriteImageToSize(imgIndex, img.getWidth(), img.getHeight()); SFImageUtils.convertRenderedImageToData( img, queuedElement.storedInputValue, queuedElement.findStartOfInputImage(imgIndex)); queuedElement.getSize(); } } }
/** * Set the image value in the given writable field. * <P> * Image values are specified using a width, height and the number of * components. The number of items in the pixels array must be at least * <CODE>width * height<CODE>. If there are less items than this an * ArrayIndexOutOfBoundsException will be generated. The integer values * are represented according to the number of components. If the integer * contains values in bytes that are not used by the number of components * for that image, the values are ignored. * <P> * <B>1 Component Images</B><BR> * The integer has the intensity value stored in the lowest byte and can be * obtained: * <PRE> * intensity = (pixel[i] ) & 0xFF; * </PRE> * <P> * <B>2 Component Images</B><BR> * The integer has the transparency value stored in the lowest byte and the * intensity in the next byte: * <PRE> * intensity = (pixel[i] >> 8) & 0xFF; * alpha = (pixel[i] ) & 0xFF; * </PRE> * <P> * <B>3 Component Images</B><BR> * The three color components are stored in the integer array as follows: * <PRE> * red = (pixel[i] >> 16) & 0xFF; * green = (pixel[i] >> 8) & 0xFF; * blue = (pixel[i] ) & 0xFF; * </PRE> * <P> * <B>4 Component Images</B><BR> * The integer has the value stored in the array as follows: * <PRE> * red = (pixel[i] >> 24) & 0xFF; * green = (pixel[i] >> 16) & 0xFF; * blue = (pixel[i] >> 8) & 0xFF; * alpha = (pixel[i] ) & 0xFF; * </PRE> * <P> * The width and height values must be greater than or equal to zero. The * number of components is between 1 and 4. Any value outside of these * bounds will generate an IllegalArgumentException. * * @param imgIndex The index of the image in the array * @param width The width of the image in pixels * @param height The height of the image in pixels * @param components The number of colour components [1-4] * @param pixels The array of pixel values as specified above. * * @exception IllegalArgumentException The number of components or width/ * height are illegal values. * @exception ArrayIndexOutOfBoundsException The number of pixels provided by the * caller is not enough for the width * height. */ public void set1Value(int imgIndex, int width, int height, int components, int[] pixels) { if (imgIndex < 0) throw new ArrayIndexOutOfBoundsException(); if (width < 0 || height < 0 || components < 0 || components > 4) throw new IllegalArgumentException(); checkWriteAccess(); synchronized (theEventQueue.eventLock) { MFImageWrapper queuedElement = (MFImageWrapper) theEventQueue.getLast(this); if (queuedElement == null || !queuedElement.isSetOneValue) { // Input and output buffers do not mix if (!storedInput && !storedOutput) { // Avoid clogging this buffer if // index out of bounds if (imgIndex >= storedInputValue.length) throw new ArrayIndexOutOfBoundsException(); queuedElement = this; loadInputValue(); isSetOneValue = true; } else { // If this generates an ArrayIndexOutOfBounds its okay, // the element will be garbage. queuedElement = new MFImageWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true); queuedElement.isSetOneValue = true; } queuedElement.rewriteImageToSize(imgIndex, width, height); int startingIndex = queuedElement.findStartOfInputImage(imgIndex); queuedElement.storedInputValue[startingIndex + 2] = components; if (pixels.length != 0) System.arraycopy( pixels, 0, queuedElement.storedInputValue, startingIndex + 3, pixels.length); theEventQueue.processEvent(queuedElement); } else { checkDataSanity(); queuedElement.rewriteImageToSize(imgIndex, width, height); int startingIndex = queuedElement.findStartOfInputImage(imgIndex); queuedElement.storedInputValue[startingIndex + 2] = components; if (pixels.length != 0) System.arraycopy( pixels, 0, queuedElement.storedInputValue, startingIndex + 3, pixels.length); } } }
int findStartOfInputImage(int index) { return MFImageWrapper.findStartOfImage(index, storedInputValue); }