/** * Create possibly volatile scratch image for fast painting. A scratch image can become * invalidated, when this happens any actions involving it are ignored, and it needs to be * recreated. Use isScratchImageValid() to check this. */ public static Image createScratchImage(int width, int height) { try { Image img = (Image) tryMethod( output_comp, "createVolatileImage", new Object[] {new Integer(width), new Integer(height)}); if (img == null) { // no such method -> create regular image return output_comp.createImage(width, height); } // if (img.validate(output_comp.getGraphicsConfiguration()) // == VolatileImage.IMAGE_INCOMPATIBLE) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gs = ge.getDefaultScreenDevice(); GraphicsConfiguration gc = gs.getDefaultConfiguration(); Integer valid = (Integer) tryMethod(img, "validate", new Object[] {gc}); // output_comp.getGraphicsConfiguration() }); if (valid.intValue() == 2) { // I checked, IMAGE_INCOMPATIBLE=2 // Hmm, somehow it didn't work. Create regular image. return output_comp.createImage(width, height); } return img; } catch (java.security.AccessControlException e) { // we're not allowed to do this (we're probably an applet) return output_comp.createImage(width, height); } }
/** * Load image from resource path (using getResource). Note that GIFs are loaded as _translucent_ * indexed images. Images are cached: loading an image with the same name twice will get the * cached image the second time. If you want to remove an image from the cache, use purgeImage. * Throws JGError when there was an error. */ @SuppressWarnings({"deprecation", "unchecked"}) public JGImage loadImage(String imgfile) { Image img = (Image) loadedimages.get(imgfile); if (img == null) { URL imgurl = getClass().getResource(imgfile); if (imgurl == null) { try { File imgf = new File(imgfile); if (imgf.canRead()) { imgurl = imgf.toURL(); } else { imgurl = new URL(imgfile); // throw new JGameError( // "File "+imgfile+" not found.",true); } } catch (MalformedURLException e) { // e.printStackTrace(); throw new JGameError("File not found or malformed path or URL '" + imgfile + "'.", true); } } img = output_comp.getToolkit().createImage(imgurl); loadedimages.put(imgfile, img); } try { ensureLoaded(img); } catch (Exception e) { // e.printStackTrace(); throw new JGameError("Error loading image " + imgfile); } return new JREImage(img); }
public JGImage crop(int x, int y, int width, int height) { @SuppressWarnings("unused") JGPoint size = getSize(); int[] buffer = getPixels(x, y, width, height); return new JREImage( output_comp.createImage(new MemoryImageSource(width, height, buffer, 0, width))); }
public JGImage flip(boolean horiz, boolean vert) { @SuppressWarnings("unused") Image flipped = null; JGPoint size = getSize(); int[] buffer = getPixels(); int[] flipbuf = new int[size.x * size.y]; if (vert && !horiz) { for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { flipbuf[(size.y - y - 1) * size.x + x] = buffer[(y * size.x) + x]; } } } else if (horiz && !vert) { for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { flipbuf[y * size.x + (size.x - x - 1)] = buffer[(y * size.x) + x]; } } } else if (horiz && vert) { for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { flipbuf[(size.y - y - 1) * size.x + (size.x - x - 1)] = buffer[(y * size.x) + x]; } } } return new JREImage( output_comp.createImage(new MemoryImageSource(size.x, size.y, flipbuf, 0, size.x))); }
/** for angle, only increments of 90 are allowed */ public JGImage rotate(int angle) { @SuppressWarnings("unused") Image rot = null; JGPoint size = getSize(); int[] buffer = getPixels(); int[] rotate = new int[size.x * size.y]; int angletype = (angle / 90) & 3; if (angletype == 0) return this; if (angletype == 1) { /* 1 2 3 4 9 5 1 * 5 6 7 8 => a 6 2 * 9 a b c b 7 3 * c 8 4 */ for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { rotate[x * size.y + (size.y - 1 - y)] = buffer[(y * size.x) + x]; } } return new JREImage( output_comp.createImage(new MemoryImageSource(size.y, size.x, rotate, 0, size.y))); } if (angletype == 3) { /* 1 2 3 4 4 8 c * 5 6 7 8 => 3 7 b * 9 a b c 2 6 a * 1 5 9 */ for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { rotate[(size.x - x - 1) * size.y + y] = buffer[(y * size.x) + x]; } } return new JREImage( output_comp.createImage(new MemoryImageSource(size.y, size.x, rotate, 0, size.y))); } if (angletype == 2) { /* 1 2 3 4 c b a 9 * 5 6 7 8 => 8 7 6 5 * 9 a b c 4 3 2 1 */ for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { rotate[((size.y - y - 1) * size.x) + (size.x - x - 1)] = buffer[(y * size.x) + x]; } } } return new JREImage( output_comp.createImage(new MemoryImageSource(size.x, size.y, rotate, 0, size.x))); }
/** * Turn a (possibly) translucent or indexed image into a display-compatible bitmask image using * the given alpha threshold and render-to-background colour, or display-compatible translucent * image. The alpha values in the image are set to either 0 (below threshold) or 255 (above * threshold). The render-to-background colour bg_col is used to determine how the pixels * overlapping transparent pixels should be rendered. The fast algorithm just sets the colour * behind the transparent pixels in the image (for bitmask source images); the slow algorithm * actually renders the image to a background of bg_col (for translucent sources). * * @param thresh alpha threshold between 0 and 255 * @param fast use fast algorithm (only set bg_col behind transp. pixels) * @param bitmask true=use bitmask, false=use translucent */ public JGImage toDisplayCompatible(int thresh, JGColor bg_col, boolean fast, boolean bitmask) { Color bgcol = new Color(bg_col.r, bg_col.g, bg_col.b); int bgcol_rgb = (bgcol.getRed() << 16) | (bgcol.getGreen() << 8) | bgcol.getBlue(); JGPoint size = getSize(); int[] buffer = getPixels(); // render image to bg depending on bgcol BufferedImage img_bg; if (bitmask) { img_bg = createCompatibleImage(size.x, size.y, Transparency.BITMASK); } else { img_bg = createCompatibleImage(size.x, size.y, Transparency.TRANSLUCENT); } int[] bg_buf; if (!fast) { Graphics g = img_bg.getGraphics(); g.setColor(bgcol); // the docs say I could use bgcol in the drawImage as an // equivalent to the following two lines, but this // doesn't handle translucency properly and is _slower_ g.fillRect(0, 0, size.x, size.y); g.drawImage(img, 0, 0, null); bg_buf = new JREImage(img_bg).getPixels(); } else { bg_buf = buffer; } // g.dispose(); // ColorModel rgb_bitmask = ColorModel.getRGBdefault(); // rgb_bitmask = new PackedColorModel( // rgb_bitmask.getColorSpace(),25,0xff0000,0x00ff00,0x0000ff, // 0x1000000, false, Transparency.BITMASK, DataBuffer.TYPE_INT); // ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask, boolean // isAlphaPremultiplied, int trans, int transferType) int[] thrsbuf = new int[size.x * size.y]; for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { if (((buffer[y * size.x + x] >> 24) & 0xff) >= thresh) { thrsbuf[y * size.x + x] = bg_buf[y * size.x + x] | (0xff << 24); } else { // explicitly set the colour of the transparent pixel. // This makes a difference when scaling! // thrsbuf[y*size.x+x]=bg_buf[y*size.x+x]&~(0xff<<24); thrsbuf[y * size.x + x] = bgcol_rgb; } } } return new JREImage( output_comp.createImage( new MemoryImageSource( size.x, size.y, // rgb_bitmask, img_bg.getColorModel(), // display compatible bitmask bitmask ? thrsbuf : bg_buf, 0, size.x))); }
/** Behaves like loadImage(String). Returns null if there was an error. */ @SuppressWarnings("unchecked") public static JGImage loadImage(URL imgurl) { Image img = (Image) loadedimages.get(imgurl); if (img == null) { img = output_comp.getToolkit().createImage(imgurl); loadedimages.put(imgurl, img); } try { ensureLoaded(img); } catch (Exception e) { System.err.println("Error loading image " + imgurl); return null; } return new JREImage(img); }