/** * {@collect.stats} Filters an IndexColorModel object by running each entry in its color tables * through the filterRGB function that RGBImageFilter subclasses must provide. Uses coordinates of * -1 to indicate that a color table entry is being filtered rather than an actual pixel value. * * @param icm the IndexColorModel object to be filtered * @exception NullPointerException if <code>icm</code> is null * @return a new IndexColorModel representing the filtered colors */ public IndexColorModel filterIndexColorModel(IndexColorModel icm) { int mapsize = icm.getMapSize(); byte r[] = new byte[mapsize]; byte g[] = new byte[mapsize]; byte b[] = new byte[mapsize]; byte a[] = new byte[mapsize]; icm.getReds(r); icm.getGreens(g); icm.getBlues(b); icm.getAlphas(a); int trans = icm.getTransparentPixel(); boolean needalpha = false; for (int i = 0; i < mapsize; i++) { int rgb = filterRGB(-1, -1, icm.getRGB(i)); a[i] = (byte) (rgb >> 24); if (a[i] != ((byte) 0xff) && i != trans) { needalpha = true; } r[i] = (byte) (rgb >> 16); g[i] = (byte) (rgb >> 8); b[i] = (byte) (rgb >> 0); } if (needalpha) { return new IndexColorModel(icm.getPixelSize(), mapsize, r, g, b, a); } else { return new IndexColorModel(icm.getPixelSize(), mapsize, r, g, b, trans); } }
void setHistogram(ImagePlus imp, int j) { ImageProcessor ip = imp.getProcessor(); ImageStatistics stats = ImageStatistics.getStatistics(ip, AREA + MODE, null); int maxCount2 = 0; histogram = stats.histogram; for (int i = 0; i < stats.nBins; i++) if ((histogram[i] > maxCount2) && (i != stats.mode)) maxCount2 = histogram[i]; hmax = stats.maxCount; if ((hmax > (maxCount2 * 1.5)) && (maxCount2 != 0)) { // GL 1.5 was 2 hmax = (int) (maxCount2 * 1.1); // GL 1.1 was 1.5 histogram[stats.mode] = hmax; } os = null; ColorModel cm = ip.getColorModel(); if (!(cm instanceof IndexColorModel)) return; IndexColorModel icm = (IndexColorModel) cm; int mapSize = icm.getMapSize(); if (mapSize != 256) return; byte[] r = new byte[256]; byte[] g = new byte[256]; byte[] b = new byte[256]; icm.getReds(r); icm.getGreens(g); icm.getBlues(b); hColors = new Color[256]; if (isRGB) { if (j == 0) { for (int i = 0; i < 256; i++) hColors[i] = new Color(i & 255, 0 & 255, 0 & 255); } else if (j == 1) { for (int i = 0; i < 256; i++) hColors[i] = new Color(0 & 255, i & 255, 0 & 255); } else if (j == 2) { for (int i = 0; i < 256; i++) hColors[i] = new Color(0 & 255, 0 & 255, i & 255); } } else { if (j == 0) { for (int i = 0; i < 256; i++) hColors[i] = new Color(r[i] & 255, g[i] & 255, b[i] & 255); } else if (j == 1) { for (int i = 0; i < 256; i++) // hColors[i] = new Color(127-i/2&255, 127+i/2&255, 127-i/2&255); hColors[i] = new Color(192 - i / 4 & 255, 192 + i / 4 & 255, 192 - i / 4 & 255); } else if (j == 2) { for (int i = 0; i < 256; i++) hColors[i] = new Color(i & 255, i & 255, 0 & 255); } } }
public boolean dispose() { if (decoder.imageComplete(ImageConsumer.SINGLEFRAMEDONE, false) == 0) { return false; } else { if (delay > 0) { try { if (verbose) { System.out.println("sleeping: " + delay); } Thread.sleep(delay); } catch (InterruptedException e) { return false; } } else { Thread.yield(); } if (verbose && disposal_method != 0) { System.out.println("disposal method: " + disposal_method); } int global_width = decoder.global_width; int global_height = decoder.global_height; if (x < 0) { width += x; x = 0; } if (x + width > global_width) { width = global_width - x; } if (width <= 0) { disposal_method = DISPOSAL_NONE; } else { if (y < 0) { height += y; y = 0; } if (y + height > global_height) { height = global_height - y; } if (height <= 0) { disposal_method = DISPOSAL_NONE; } } switch (disposal_method) { case DISPOSAL_PREVIOUS: byte[] saved_image = decoder.saved_image; IndexColorModel saved_model = decoder.saved_model; if (saved_image != null) { setPixels( x, y, width, height, saved_model, saved_image, y * global_width + x, global_width); } break; case DISPOSAL_BGCOLOR: byte tpix; if (model.getTransparentPixel() < 0) { model = trans_model; if (model == null) { model = new IndexColorModel(8, 1, new byte[4], 0, true); trans_model = model; } tpix = 0; } else { tpix = (byte) model.getTransparentPixel(); } int rassize = width * height; byte[] rasfill = new byte[rassize]; if (tpix != 0) { for (int i = 0; i < rassize; i++) { rasfill[i] = tpix; } } // setPixels(x, y, width, height, model, rasfill, 0, 0); setPixels(x, y, width, height, model, rasfill, 0, width); break; case DISPOSAL_SAVE: decoder.saved_model = model; break; } } return true; }
/** Read Image data */ private boolean readImage(boolean first, int disposal_method, int delay) throws IOException { if (curframe != null && !curframe.dispose()) { abort(); return false; } long tm = 0; if (verbose) { tm = System.currentTimeMillis(); } // Allocate the buffer byte block[] = new byte[256 + 3]; // Read the image descriptor if (readBytes(block, 0, 10) != 0) { throw new IOException(); } int x = ExtractWord(block, 0); int y = ExtractWord(block, 2); int width = ExtractWord(block, 4); int height = ExtractWord(block, 6); boolean interlace = (block[8] & INTERLACEMASK) != 0; IndexColorModel model = global_model; if ((block[8] & COLORMAPMASK) != 0) { // We read one extra byte above so now when we must // transfer that byte as the first colormap byte // and manually read the code size when we are done int num_local_colors = 1 << ((block[8] & 0x7) + 1); // Read local colors byte[] local_colormap = new byte[num_local_colors * 3]; local_colormap[0] = block[9]; if (readBytes(local_colormap, 1, num_local_colors * 3 - 1) != 0) { throw new IOException(); } // Now read the "real" code size byte which follows // the local color table if (readBytes(block, 9, 1) != 0) { throw new IOException(); } model = new IndexColorModel(8, num_local_colors, local_colormap, 0, false, trans_pixel); } else if (model == null || trans_pixel != model.getTransparentPixel()) { model = new IndexColorModel(8, num_global_colors, global_colormap, 0, false, trans_pixel); global_model = model; } // Notify the consumers if (first) { if (global_width == 0) global_width = width; if (global_height == 0) global_height = height; setDimensions(global_width, global_height); setProperties(props); setColorModel(model); headerComplete(); } if (disposal_method == GifFrame.DISPOSAL_SAVE && saved_image == null) { saved_image = new byte[global_width * global_height]; } int hints = (interlace ? interlaceflags : normalflags); setHints(hints); curframe = new GifFrame(this, disposal_method, delay, (curframe == null), model, x, y, width, height); // allocate the raster data byte rasline[] = new byte[width]; if (verbose) { System.out.print( "Reading a " + width + " by " + height + " " + (interlace ? "" : "non-") + "interlaced image..."); } boolean ret = parseImage(x, y, width, height, interlace, ExtractByte(block, 9), block, rasline, model); if (!ret) { abort(); } if (verbose) { System.out.println("done in " + (System.currentTimeMillis() - tm) + "ms"); } return ret; }
/* * This is converted from the native version. The java version is * much faster when we have JIT. */ private boolean parseImage( int relx, int rely, int width, int height, boolean interlace, int initCodeSize, byte block[], byte rasline[], IndexColorModel model) { int OUTCODELENGTH = 4097; int clearCode = (1 << initCodeSize); int eofCode = clearCode + 1; int bitMask; int curCode; int outCount = OUTCODELENGTH; /* Variables used to form reading data */ boolean blockEnd = false; int remain = 0; int byteoff = 0; int accumbits = 0; int accumdata = 0; /* Variables used to decompress the data */ int codeSize = initCodeSize + 1; int maxCode = 1 << codeSize; int codeMask = maxCode - 1; int freeCode = clearCode + 2; int code = 0; int oldCode = 0; char prevChar = 0; // int blockLength = 0; int blockLength = 0; /* Variables used for writing pixels */ int x = width; int y = 0; int off = 0; int passinc = interlace ? 8 : 1; int passht = passinc; int len; bitMask = model.getMapSize() - 1; /* Read codes until the eofCode is encountered */ for (; ; ) { if (accumbits < codeSize) { boolean lastByte = false; /* fill the buffer if needed */ while (remain < 2) { if (blockEnd) { /* Sometimes we have one last byte to process... */ if (remain == 1 && accumbits + 8 >= codeSize) { break; } if (off > 0) { // sendPixels(relx, rely+y, width, passht, rasline, // model); sendPixels(relx, rely + y, width, 1, rasline, model); } /* quietly accept truncated GIF images */ return false; } /* move remaining bytes to the beginning of the buffer */ block[0] = block[byteoff]; byteoff = 0; /* fill the block */ len = readBytes(block, remain, blockLength + 1); remain += blockLength; if (len > 0) { remain -= (len - 1); blockLength = 0; } else { blockLength = (block[remain] & 0xff); } if (blockLength == 0) { blockEnd = true; } } /* 2 bytes at a time saves checking for accumbits < codeSize. * We know we'll get enough and also that we can't overflow * since codeSize <= 12. */ if (!lastByte) { remain -= 2; accumdata += (block[byteoff++] & 0xff) << accumbits; accumbits += 8; accumdata += (block[byteoff++] & 0xff) << accumbits; accumbits += 8; } else { remain--; accumdata += (block[byteoff++] & 0xff) << accumbits; accumbits += 8; } } /* Compute the code */ code = accumdata & codeMask; accumdata >>= codeSize; accumbits -= codeSize; /* * Interpret the code */ if (code == clearCode) { /* Clear code sets everything back to its initial value, then * reads the immediately subsequent code as uncompressed data. */ /* Note that freeCode is one less than it is supposed to be, * this is because it will be incremented next time round the * loop */ freeCode = clearCode + 1; codeSize = initCodeSize + 1; maxCode = 1 << codeSize; codeMask = maxCode - 1; /* Continue if we've NOT reached the end, some Gif images * contain bogus codes after the last clear code. */ if (y < height) { continue; } /* pretend we've reached the end of the data */ code = eofCode; } if (code == eofCode) { /* make sure we read the whole block of pixels. */ while (!blockEnd) { if (readBytes(block, 0, blockLength + 1) != 0) { /* quietly accept truncated GIF images */ return false; } blockLength = block[blockLength]; blockEnd = (blockLength == 0); } return true; } /* It must be data: save code in CurCode */ curCode = code; /* Whenever it gets here outCount is always equal to OUTCODELENGTH, so no need to reset outCount. */ // outCount = OUTCODELENGTH; /* If greater or equal to freeCode, not in the hash table * yet; repeat the last character decoded */ if (curCode >= freeCode) { if (curCode > freeCode) { /* * if we get a code too far outside our range, it * could case the parser to start traversing parts * of our data structure that are out of range... */ /*In native version: goto flushit;*/ while (!blockEnd) { if (readBytes(block, 0, blockLength + 1) != 0) { /* quietly accept truncated GIF images */ return false; } blockLength = block[blockLength]; blockEnd = (blockLength == 0); } return true; } curCode = oldCode; outCode[--outCount] = (byte) prevChar; } /* Unless this code is raw data, pursue the chain pointed * to by curCode through the hash table to its end; each * code in the chain puts its associated output code on * the output queue. */ while (curCode > bitMask) { outCode[--outCount] = suffix[curCode]; if (outCount == 0) { /* * In theory this should never happen since our * prefix and suffix arrays are monotonically * decreasing and so outCode will only be filled * as much as those arrays, but I don't want to * take that chance and the test is probably * cheap compared to the read and write operations. * If we ever do overflow the array, we will just * flush the rest of the data and quietly accept * the GIF as truncated here. */ // In native version: goto flushit; while (!blockEnd) { if (readBytes(block, 0, blockLength + 1) != 0) { /* quietly accept truncated GIF images */ return false; } blockLength = block[blockLength]; blockEnd = (blockLength == 0); } return true; } curCode = prefix[curCode]; } /* The last code in the chain is treated as raw data. */ prevChar = (char) curCode; outCode[--outCount] = (byte) prevChar; /* Now we put the data out to the Output routine. It's * been stacked LIFO, so deal with it that way... */ len = OUTCODELENGTH - outCount; /* This is why I commented out the code that resets outCount. */ while (--len >= 0) { rasline[off++] = outCode[outCount++]; /* Update the X-coordinate, and if it overflows, update the * Y-coordinate */ if (--x == 0) { int count; /* If a non-interlaced picture, just increment y to the next * scan line. If it's interlaced, deal with the interlace as * described in the GIF spec. Put the decoded scan line out * to the screen if we haven't gone past the bottom of it */ // count = sendPixels(relx, rely+y, width, passht, rasline, model); count = sendPixels(relx, rely + y, width, 1, rasline, model); if (count <= 0) { /* Nobody is listening any more. */ return false; } x = width; off = 0; /* pass inc ht ystart */ /* 0 8 8 0 */ /* 1 8 4 4 */ /* 2 4 2 2 */ /* 3 2 1 1 */ y += passinc; while (y >= height) { passinc = passht; passht >>= 1; y = passht; if (passht == 0) { // In native version: goto flushit; while (!blockEnd) { if (readBytes(block, 0, blockLength + 1) != 0) { /* quietly accept truncated GIF images */ return false; } blockLength = block[blockLength] & 0xff; blockEnd = (blockLength == 0); } return true; } } } } /* Build the hash table on-the-fly. No table is stored in the file. */ prefix[freeCode] = (short) oldCode; suffix[freeCode] = (byte) prevChar; oldCode = code; /* Point to the next slot in the table. If we exceed the * maxCode, increment the code size unless * it's already 12. If it is, do nothing: the next code * decompressed better be CLEAR */ if (++freeCode >= maxCode) { if (codeSize < 12) { codeSize++; maxCode <<= 1; codeMask = maxCode - 1; } else { /* Just in case */ freeCode = maxCode - 1; } } } }
Color getColor(int index) { IndexColorModel cm = (IndexColorModel) imp.getProcessor().getColorModel(); // IJ.write(""+index+" "+(new Color(cm.getRGB(index)))); return new Color(cm.getRGB(index)); }