diff --git a/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java b/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java index 3bb70e92d..e2d39f817 100755 --- a/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java +++ b/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java @@ -100,6 +100,18 @@ public class ZipWriter implements Closeable { return this; } + /** + * 设置压缩方式 + * + * @param method 压缩方式,支持{@link ZipOutputStream#DEFLATED}和{@link ZipOutputStream#STORED} + * @return this + * @since 6.0.0 + */ + public ZipWriter setMethod(final int method) { + this.out.setMethod(method); + return this; + } + /** * 获取原始的{@link ZipOutputStream} * @@ -233,9 +245,10 @@ public class ZipWriter implements Closeable { * @param filter 文件过滤器,通过实现此接口,自定义要过滤的文件(过滤掉哪些文件或文件夹不加入压缩),{@code null}表示不过滤 * @throws IORuntimeException IO异常 */ - private ZipWriter _add(final File file, final String srcRootDir, final FileFilter filter) throws IORuntimeException { + @SuppressWarnings("resource") + private void _add(final File file, final String srcRootDir, final FileFilter filter) throws IORuntimeException { if (null == file || (null != filter && false == filter.accept(file))) { - return this; + return; } // 获取文件相对于压缩文件夹根目录的子路径 @@ -256,7 +269,6 @@ public class ZipWriter implements Closeable { // 如果是文件或其它符号,则直接压缩该文件 putEntry(subPath, FileUtil.getInputStream(file)); } - return this; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java index adf81e8c2..a9d1f0dce 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java @@ -38,6 +38,7 @@ import java.io.Writer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collection; import java.util.Objects; @@ -527,12 +528,24 @@ public class IoUtil extends NioUtil { /** * 文件转为{@link InputStream} * - * @param file 文件 + * @param file 文件,非空 * @return {@link InputStream} */ public static InputStream toStream(final File file) { + Assert.notNull(file); + return toStream(file.toPath()); + } + + /** + * 文件转为{@link InputStream} + * + * @param path {@link Path},非空 + * @return {@link InputStream} + */ + public static InputStream toStream(final Path path) { + Assert.notNull(path); try { - return Files.newInputStream(file.toPath()); + return Files.newInputStream(path); } catch (final IOException e) { throw new IORuntimeException(e); } diff --git a/hutool-swing/pom.xml b/hutool-swing/pom.xml index c0c25192f..7764fdc24 100755 --- a/hutool-swing/pom.xml +++ b/hutool-swing/pom.xml @@ -27,6 +27,12 @@ ${project.parent.version} + + com.madgag + animated-gif-lib + 1.4 + true + com.drewnoakes metadata-extractor diff --git a/hutool-swing/src/main/java/cn/hutool/swing/captcha/GifCaptcha.java b/hutool-swing/src/main/java/cn/hutool/swing/captcha/GifCaptcha.java index 4781264ad..1a78b45f1 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/captcha/GifCaptcha.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/captcha/GifCaptcha.java @@ -1,9 +1,9 @@ package cn.hutool.swing.captcha; -import cn.hutool.swing.img.gif.AnimatedGifEncoder; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.RandomUtil; +import com.madgag.gif.fmsware.AnimatedGifEncoder; import java.awt.AlphaComposite; import java.awt.Color; diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/AnimatedGifEncoder.java b/hutool-swing/src/main/java/cn/hutool/swing/img/gif/AnimatedGifEncoder.java deleted file mode 100755 index 30f7f3b6b..000000000 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/AnimatedGifEncoder.java +++ /dev/null @@ -1,583 +0,0 @@ -package cn.hutool.swing.img.gif; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferByte; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Paths; - -/** - * 动态GIF动画生成器,可生成一个或多个帧的GIF。 - * - *
- * Example:
- *    AnimatedGifEncoder e = new AnimatedGifEncoder();
- *    e.start(outputFileName);
- *    e.setDelay(1000);   // 1 frame per sec
- *    e.addFrame(image1);
- *    e.addFrame(image2);
- *    e.finish();
- * 
- *

- * 来自:https://github.com/rtyley/animated-gif-lib-for-java - * - * @author Kevin Weiner, FM Software - * @version 1.03 November 2003 - * @since 5.3.8 - */ -public class AnimatedGifEncoder { - - protected int width; // image size - protected int height; - protected Color transparent = null; // transparent color if given - protected boolean transparentExactMatch = false; // transparent color will be found by looking for the closest color - // or for the exact color if transparentExactMatch == true - protected Color background = null; // background color if given - protected int transIndex; // transparent index in color table - protected int repeat = -1; // no repeat - protected int delay = 0; // frame delay (hundredths) - protected boolean started = false; // ready to output frames - protected OutputStream out; - protected BufferedImage image; // current frame - protected byte[] pixels; // BGR byte array from frame - protected byte[] indexedPixels; // converted frame indexed to palette - protected int colorDepth; // number of bit planes - protected byte[] colorTab; // RGB palette - protected boolean[] usedEntry = new boolean[256]; // active palette entries - protected int palSize = 7; // color table size (bits-1) - protected int dispose = -1; // disposal code (-1 = use default) - protected boolean closeStream = false; // close stream when finished - protected boolean firstFrame = true; - protected boolean sizeSet = false; // if false, get size from first frame - protected int sample = 10; // default sample interval for quantizer - - /** - * 设置每一帧的间隔时间 - * Sets the delay time between each frame, or changes it - * for subsequent frames (applies to last frame added). - * - * @param ms 间隔时间,单位毫秒 - */ - public void setDelay(final int ms) { - delay = Math.round(ms / 10.0f); - } - - /** - * Sets the GIF frame disposal code for the last added frame - * and any subsequent frames. Default is 0 if no transparent - * color has been set, otherwise 2. - * - * @param code int disposal code. - */ - public void setDispose(final int code) { - if (code >= 0) { - dispose = code; - } - } - - /** - * Sets the number of times the set of GIF frames - * should be played. Default is 1; 0 means play - * indefinitely. Must be invoked before the first - * image is added. - * - * @param iter int number of iterations. - */ - public void setRepeat(final int iter) { - if (iter >= 0) { - repeat = iter; - } - } - - /** - * Sets the transparent color for the last added frame - * and any subsequent frames. - * Since all colors are subject to modification - * in the quantization process, the color in the final - * palette for each frame closest to the given color - * becomes the transparent color for that frame. - * May be set to null to indicate no transparent color. - * - * @param c Color to be treated as transparent on display. - */ - public void setTransparent(final Color c) { - setTransparent(c, false); - } - - /** - * Sets the transparent color for the last added frame - * and any subsequent frames. - * Since all colors are subject to modification - * in the quantization process, the color in the final - * palette for each frame closest to the given color - * becomes the transparent color for that frame. - * If exactMatch is set to true, transparent color index - * is search with exact match, and not looking for the - * closest one. - * May be set to null to indicate no transparent color. - * - * @param c Color to be treated as transparent on display. - * @param exactMatch If exactMatch is set to true, transparent color index is search with exact match - */ - public void setTransparent(final Color c, final boolean exactMatch) { - transparent = c; - transparentExactMatch = exactMatch; - } - - - /** - * Sets the background color for the last added frame - * and any subsequent frames. - * Since all colors are subject to modification - * in the quantization process, the color in the final - * palette for each frame closest to the given color - * becomes the background color for that frame. - * May be set to null to indicate no background color - * which will default to black. - * - * @param c Color to be treated as background on display. - */ - public void setBackground(final Color c) { - background = c; - } - - /** - * Adds next GIF frame. The frame is not written immediately, but is - * actually deferred until the next frame is received so that timing - * data can be inserted. Invoking {@code finish()} flushes all - * frames. If {@code setSize} was not invoked, the size of the - * first image is used for all subsequent frames. - * - * @param im BufferedImage containing frame to write. - * @return true if successful. - */ - public boolean addFrame(final BufferedImage im) { - if ((im == null) || !started) { - return false; - } - boolean ok = true; - try { - if (!sizeSet) { - // use first frame's size - setSize(im.getWidth(), im.getHeight()); - } - image = im; - getImagePixels(); // convert to correct format if necessary - analyzePixels(); // build color table & map pixels - if (firstFrame) { - writeLSD(); // logical screen descriptior - writePalette(); // global color table - if (repeat >= 0) { - // use NS app extension to indicate reps - writeNetscapeExt(); - } - } - writeGraphicCtrlExt(); // write graphic control extension - writeImageDesc(); // image descriptor - if (!firstFrame) { - writePalette(); // local color table - } - writePixels(); // encode and write pixel data - firstFrame = false; - } catch (final IOException e) { - ok = false; - } - - return ok; - } - - /** - * Flushes any pending data and closes output file. - * If writing to an OutputStream, the stream is not - * closed. - * - * @return is ok - */ - public boolean finish() { - if (!started) return false; - boolean ok = true; - started = false; - try { - out.write(0x3b); // gif trailer - out.flush(); - if (closeStream) { - out.close(); - } - } catch (final IOException e) { - ok = false; - } - - // reset for subsequent use - transIndex = 0; - out = null; - image = null; - pixels = null; - indexedPixels = null; - colorTab = null; - closeStream = false; - firstFrame = true; - - return ok; - } - - /** - * Sets frame rate in frames per second. Equivalent to - * {@code setDelay(1000/fps)}. - * - * @param fps float frame rate (frames per second) - */ - public void setFrameRate(final float fps) { - if (fps != 0f) { - delay = Math.round(100f / fps); - } - } - - /** - * Sets quality of color quantization (conversion of images - * to the maximum 256 colors allowed by the GIF specification). - * Lower values (minimum = 1) produce better colors, but slow - * processing significantly. 10 is the default, and produces - * good color mapping at reasonable speeds. Values greater - * than 20 do not yield significant improvements in speed. - * - * @param quality int greater than 0. - */ - public void setQuality(int quality) { - if (quality < 1) quality = 1; - sample = quality; - } - - /** - * Sets the GIF frame size. The default size is the - * size of the first frame added if this method is - * not invoked. - * - * @param w int frame width. - * @param h int frame width. - */ - public void setSize(final int w, final int h) { - if (started && !firstFrame) return; - width = w; - height = h; - if (width < 1) width = 320; - if (height < 1) height = 240; - sizeSet = true; - } - - /** - * Initiates GIF file creation on the given stream. The stream - * is not closed automatically. - * - * @param os OutputStream on which GIF images are written. - * @return false if initial write failed. - */ - public boolean start(final OutputStream os) { - if (os == null) return false; - boolean ok = true; - closeStream = false; - out = os; - try { - writeString("GIF89a"); // header - } catch (final IOException e) { - ok = false; - } - return started = ok; - } - - /** - * Initiates writing of a GIF file with the specified name. - * - * @param file String containing output file name. - * @return false if open or initial write failed. - */ - public boolean start(final String file) { - boolean ok; - try { - out = new BufferedOutputStream(Files.newOutputStream(Paths.get(file))); - ok = start(out); - closeStream = true; - } catch (final IOException e) { - ok = false; - } - return started = ok; - } - - /** - * @return 是否开始 - */ - public boolean isStarted() { - return started; - } - - /** - * Analyzes image colors and creates color map. - */ - protected void analyzePixels() { - final int len = pixels.length; - final int nPix = len / 3; - indexedPixels = new byte[nPix]; - final NeuQuant nq = new NeuQuant(pixels, len, sample); - // initialize quantizer - colorTab = nq.process(); // create reduced palette - // convert map from BGR to RGB - for (int i = 0; i < colorTab.length; i += 3) { - final byte temp = colorTab[i]; - colorTab[i] = colorTab[i + 2]; - colorTab[i + 2] = temp; - usedEntry[i / 3] = false; - } - // map image pixels to new palette - int k = 0; - for (int i = 0; i < nPix; i++) { - final int index = - nq.map(pixels[k++] & 0xff, - pixels[k++] & 0xff, - pixels[k++] & 0xff); - usedEntry[index] = true; - indexedPixels[i] = (byte) index; - } - pixels = null; - colorDepth = 8; - palSize = 7; - // get the closest match to transparent color if specified - if (transparent != null) { - transIndex = transparentExactMatch ? findExact(transparent) : findClosest(transparent); - } - } - - /** - * Returns index of palette color closest to c - * - * @param c Color - * @return index - */ - protected int findClosest(final Color c) { - if (colorTab == null) return -1; - final int r = c.getRed(); - final int g = c.getGreen(); - final int b = c.getBlue(); - int minpos = 0; - int dmin = 256 * 256 * 256; - final int len = colorTab.length; - for (int i = 0; i < len; ) { - final int dr = r - (colorTab[i++] & 0xff); - final int dg = g - (colorTab[i++] & 0xff); - final int db = b - (colorTab[i] & 0xff); - final int d = dr * dr + dg * dg + db * db; - final int index = i / 3; - if (usedEntry[index] && (d < dmin)) { - dmin = d; - minpos = index; - } - i++; - } - return minpos; - } - - /** - * Returns true if the exact matching color is existing, and used in the color palette, otherwise, return false. - * This method has to be called before finishing the image, - * because after finished the palette is destroyed, and it will always return false. - * - * @param c 颜色 - * @return 颜色是否存在 - */ - boolean isColorUsed(final Color c) { - return findExact(c) != -1; - } - - /** - * Returns index of palette exactly matching to color c or -1 if there is no exact matching. - * - * @param c Color - * @return index - */ - protected int findExact(final Color c) { - if (colorTab == null) { - return -1; - } - - final int r = c.getRed(); - final int g = c.getGreen(); - final int b = c.getBlue(); - final int len = colorTab.length / 3; - for (int index = 0; index < len; ++index) { - final int i = index * 3; - // If the entry is used in colorTab, then check if it is the same exact color we're looking for - if (usedEntry[index] && r == (colorTab[i] & 0xff) && g == (colorTab[i + 1] & 0xff) && b == (colorTab[i + 2] & 0xff)) { - return index; - } - } - return -1; - } - - /** - * Extracts image pixels into byte array "pixels" - */ - protected void getImagePixels() { - final int w = image.getWidth(); - final int h = image.getHeight(); - final int type = image.getType(); - if ((w != width) - || (h != height) - || (type != BufferedImage.TYPE_3BYTE_BGR)) { - // create new image with right size/format - final BufferedImage temp = - new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); - final Graphics2D g = temp.createGraphics(); - g.setColor(background); - g.fillRect(0, 0, width, height); - g.drawImage(image, 0, 0, null); - image = temp; - } - pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); - } - - /** - * Writes Graphic Control Extension - * - * @throws IOException IO异常 - */ - protected void writeGraphicCtrlExt() throws IOException { - out.write(0x21); // extension introducer - out.write(0xf9); // GCE label - out.write(4); // data block size - final int transp; - int disp; - if (transparent == null) { - transp = 0; - disp = 0; // dispose = no action - } else { - transp = 1; - disp = 2; // force clear if using transparent color - } - if (dispose >= 0) { - disp = dispose & 7; // user override - } - disp <<= 2; - - // packed fields - //noinspection PointlessBitwiseExpression - out.write(0 | // 1:3 reserved - disp | // 4:6 disposal - 0 | // 7 user input - 0 = none - transp); // 8 transparency flag - - writeShort(delay); // delay x 1/100 sec - out.write(transIndex); // transparent color index - out.write(0); // block terminator - } - - /** - * Writes Image Descriptor - * - * @throws IOException IO异常 - */ - protected void writeImageDesc() throws IOException { - out.write(0x2c); // image separator - writeShort(0); // image position x,y = 0,0 - writeShort(0); - writeShort(width); // image size - writeShort(height); - // packed fields - if (firstFrame) { - // no LCT - GCT is used for first (or only) frame - out.write(0); - } else { - // specify normal LCT - //noinspection PointlessBitwiseExpression - out.write(0x80 | // 1 local color table 1=yes - 0 | // 2 interlace - 0=no - 0 | // 3 sorted - 0=no - 0 | // 4-5 reserved - palSize); // 6-8 size of color table - } - } - - /** - * Writes Logical Screen Descriptor - * - * @throws IOException IO异常 - */ - protected void writeLSD() throws IOException { - // logical screen size - writeShort(width); - writeShort(height); - // packed fields - //noinspection PointlessBitwiseExpression - out.write((0x80 | // 1 : global color table flag = 1 (gct used) - 0x70 | // 2-4 : color resolution = 7 - 0x00 | // 5 : gct sort flag = 0 - palSize)); // 6-8 : gct size - - out.write(0); // background color index - out.write(0); // pixel aspect ratio - assume 1:1 - } - - /** - * Writes Netscape application extension to define - * repeat count. - * - * @throws IOException IO异常 - */ - protected void writeNetscapeExt() throws IOException { - out.write(0x21); // extension introducer - out.write(0xff); // app extension label - out.write(11); // block size - writeString("NETSCAPE" + "2.0"); // app id + auth code - out.write(3); // sub-block size - out.write(1); // loop sub-block id - writeShort(repeat); // loop count (extra iterations, 0=repeat forever) - out.write(0); // block terminator - } - - /** - * Writes color table - * - * @throws IOException IO异常 - */ - protected void writePalette() throws IOException { - out.write(colorTab, 0, colorTab.length); - final int n = (3 * 256) - colorTab.length; - for (int i = 0; i < n; i++) { - out.write(0); - } - } - - /** - * Encodes and writes pixel data - * - * @throws IOException IO异常 - */ - protected void writePixels() throws IOException { - final LZWEncoder encoder = new LZWEncoder(width, height, indexedPixels, colorDepth); - encoder.encode(out); - } - - /** - * Write 16-bit value to output stream, LSB first - * - * @param value 16-bit value - * @throws IOException IO异常 - */ - protected void writeShort(final int value) throws IOException { - out.write(value & 0xff); - out.write((value >> 8) & 0xff); - } - - /** - * Writes string to output stream - * - * @param s String - * @throws IOException IO异常 - */ - protected void writeString(final String s) throws IOException { - for (int i = 0; i < s.length(); i++) { - out.write((byte) s.charAt(i)); - } - } -} diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/GifDecoder.java b/hutool-swing/src/main/java/cn/hutool/swing/img/gif/GifDecoder.java deleted file mode 100755 index 676008a5a..000000000 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/GifDecoder.java +++ /dev/null @@ -1,793 +0,0 @@ -package cn.hutool.swing.img.gif; - -import cn.hutool.core.io.IoUtil; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; - -/** - * GIF文件解析 - * Class GifDecoder - Decodes a GIF file into one or more frames. - *

- * Example: - * - *

- * {@code
- *    GifDecoder d = new GifDecoder();
- *    d.read("sample.gif");
- *    int n = d.getFrameCount();
- *    for (int i = 0; i < n; i++) {
- *       BufferedImage frame = d.getFrame(i);  // frame i
- *       int t = d.getDelay(i);  // display duration of frame in milliseconds
- *       // do something with frame
- *    }
- * }
- * 
- *

- * 来自:https://github.com/rtyley/animated-gif-lib-for-java - * - * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick. - */ -public class GifDecoder { - - /** - * File read status: No errors. - */ - public static final int STATUS_OK = 0; - - /** - * File read status: Error decoding file (may be partially decoded) - */ - public static final int STATUS_FORMAT_ERROR = 1; - - /** - * File read status: Unable to open source. - */ - public static final int STATUS_OPEN_ERROR = 2; - - protected BufferedInputStream in; - protected int status; - - protected int width; // full image width - protected int height; // full image height - protected boolean gctFlag; // global color table used - protected int gctSize; // size of global color table - protected int loopCount = 1; // iterations; 0 = repeat forever - - protected int[] gct; // global color table - protected int[] lct; // local color table - protected int[] act; // active color table - - protected int bgIndex; // background color index - protected int bgColor; // background color - protected int lastBgColor; // previous bg color - protected int pixelAspect; // pixel aspect ratio - - protected boolean lctFlag; // local color table flag - protected boolean interlace; // interlace flag - protected int lctSize; // local color table size - - protected int ix, iy, iw, ih; // current image rectangle - protected Rectangle lastRect; // last image rect - protected BufferedImage image; // current frame - protected BufferedImage lastImage; // previous frame - - protected byte[] block = new byte[256]; // current data block - protected int blockSize = 0; // block size - - // last graphic control extension info - protected int dispose = 0; - // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev - protected int lastDispose = 0; - protected boolean transparency = false; // use transparent color - protected int delay = 0; // delay in milliseconds - protected int transIndex; // transparent color index - - protected static final int MAX_STACK_SIZE = 4096; - // max decoder pixel stack size - - // LZW decoder working arrays - protected short[] prefix; - protected byte[] suffix; - protected byte[] pixelStack; - protected byte[] pixels; - - protected ArrayList frames; // frames read from current file - protected int frameCount; - - static class GifFrame { - public GifFrame(final BufferedImage im, final int del) { - image = im; - delay = del; - } - - public BufferedImage image; - public int delay; - } - - /** - * Gets display duration for specified frame. - * - * @param n int index of frame - * @return delay in milliseconds - */ - public int getDelay(final int n) { - // - delay = -1; - if ((n >= 0) && (n < frameCount)) { - delay = frames.get(n).delay; - } - return delay; - } - - /** - * Gets the number of frames read from file. - * - * @return frame count - */ - public int getFrameCount() { - return frameCount; - } - - /** - * Gets the first (or only) image read. - * - * @return BufferedImage containing first frame, or null if none. - */ - public BufferedImage getImage() { - return getFrame(0); - } - - /** - * Gets the "Netscape" iteration count, if any. - * A count of 0 means repeat indefinitiely. - * - * @return iteration count if one was specified, else 1. - */ - public int getLoopCount() { - return loopCount; - } - - /** - * Creates new frame image from current data (and previous - * frames as specified by their disposition codes). - */ - protected void setPixels() { - // expose destination image's pixels as int array - final int[] dest = - ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); - - // fill in starting image contents based on last image's dispose code - if (lastDispose > 0) { - if (lastDispose == 3) { - // use image before last - final int n = frameCount - 2; - if (n > 0) { - lastImage = getFrame(n - 1); - } else { - lastImage = null; - } - } - - if (lastImage != null) { - final int[] prev = - ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData(); - System.arraycopy(prev, 0, dest, 0, width * height); - // copy pixels - - if (lastDispose == 2) { - // fill last image rect area with background color - final Graphics2D g = image.createGraphics(); - final Color c; - if (transparency) { - c = new Color(0, 0, 0, 0); // assume background is transparent - } else { - c = new Color(lastBgColor); // use given background color - } - g.setColor(c); - g.setComposite(AlphaComposite.Src); // replace area - g.fill(lastRect); - g.dispose(); - } - } - } - - // copy each source line to the appropriate place in the destination - int pass = 1; - int inc = 8; - int iline = 0; - for (int i = 0; i < ih; i++) { - int line = i; - if (interlace) { - if (iline >= ih) { - pass++; - switch (pass) { - case 2: - iline = 4; - break; - case 3: - iline = 2; - inc = 4; - break; - case 4: - iline = 1; - inc = 2; - } - } - line = iline; - iline += inc; - } - line += iy; - if (line < height) { - final int k = line * width; - int dx = k + ix; // start of line in dest - int dlim = dx + iw; // end of dest line - if ((k + width) < dlim) { - dlim = k + width; // past dest edge - } - int sx = i * iw; // start of line in source - while (dx < dlim) { - // map color and insert in destination - final int index = ((int) pixels[sx++]) & 0xff; - final int c = act[index]; - if (c != 0) { - dest[dx] = c; - } - dx++; - } - } - } - } - - /** - * Gets the image contents of frame n. - * - * @param n frame - * @return BufferedImage - */ - public BufferedImage getFrame(final int n) { - BufferedImage im = null; - if ((n >= 0) && (n < frameCount)) { - im = frames.get(n).image; - } - return im; - } - - /** - * Gets image size. - * - * @return GIF image dimensions - */ - public Dimension getFrameSize() { - return new Dimension(width, height); - } - - /** - * Reads GIF image from stream - * - * @param is BufferedInputStream containing GIF file. - * @return read status code (0 = no errors) - */ - public int read(final BufferedInputStream is) { - init(); - if (is != null) { - in = is; - readHeader(); - if (false == err()) { - readContents(); - if (frameCount < 0) { - status = STATUS_FORMAT_ERROR; - } - } - } else { - status = STATUS_OPEN_ERROR; - } - IoUtil.close(is); - return status; - } - - /** - * Reads GIF image from stream - * - * @param is InputStream containing GIF file. - * @return read status code (0 = no errors) - */ - public int read(InputStream is) { - init(); - if (is != null) { - if (!(is instanceof BufferedInputStream)) - is = new BufferedInputStream(is); - in = (BufferedInputStream) is; - readHeader(); - if (!err()) { - readContents(); - if (frameCount < 0) { - status = STATUS_FORMAT_ERROR; - } - } - } else { - status = STATUS_OPEN_ERROR; - } - IoUtil.close(is); - return status; - } - - /** - * Reads GIF file from specified file/URL source - * (URL assumed if name contains ":/" or "file:") - * - * @param name String containing source - * @return read status code (0 = no errors) - */ - public int read(String name) { - status = STATUS_OK; - try { - name = name.trim().toLowerCase(); - if ((name.contains("file:")) || - (name.indexOf(":/") > 0)) { - final URL url = new URL(name); - in = new BufferedInputStream(url.openStream()); - } else { - in = new BufferedInputStream(Files.newInputStream(Paths.get(name))); - } - status = read(in); - } catch (final IOException e) { - status = STATUS_OPEN_ERROR; - } - - return status; - } - - /** - * Decodes LZW image data into pixel array. - * Adapted from John Cristy's ImageMagick. - */ - protected void decodeImageData() { - final int NullCode = -1; - final int npix = iw * ih; - int available; - final int clear; - int code_mask; - int code_size; - final int end_of_information; - int in_code; - int old_code; - int bits; - int code; - int count; - int i; - int datum; - final int data_size; - int first; - int top; - int bi; - int pi; - - if ((pixels == null) || (pixels.length < npix)) { - pixels = new byte[npix]; // allocate new pixel array - } - if (prefix == null) prefix = new short[MAX_STACK_SIZE]; - if (suffix == null) suffix = new byte[MAX_STACK_SIZE]; - if (pixelStack == null) pixelStack = new byte[MAX_STACK_SIZE + 1]; - - // Initialize GIF data stream decoder. - - data_size = read(); - clear = 1 << data_size; - end_of_information = clear + 1; - available = clear + 2; - old_code = NullCode; - code_size = data_size + 1; - code_mask = (1 << code_size) - 1; - for (code = 0; code < clear; code++) { - prefix[code] = 0; - suffix[code] = (byte) code; - } - - // Decode GIF pixel stream. - - datum = bits = count = first = top = pi = bi = 0; - - for (i = 0; i < npix; ) { - if (top == 0) { - if (bits < code_size) { - // Load bytes until there are enough bits for a code. - if (count == 0) { - // Read a new data block. - count = readBlock(); - if (count <= 0) - break; - bi = 0; - } - datum += (((int) block[bi]) & 0xff) << bits; - bits += 8; - bi++; - count--; - continue; - } - - // Get the next code. - - code = datum & code_mask; - datum >>= code_size; - bits -= code_size; - - // Interpret the code - - if ((code > available) || (code == end_of_information)) - break; - if (code == clear) { - // Reset decoder. - code_size = data_size + 1; - code_mask = (1 << code_size) - 1; - available = clear + 2; - old_code = NullCode; - continue; - } - if (old_code == NullCode) { - pixelStack[top++] = suffix[code]; - old_code = code; - first = code; - continue; - } - in_code = code; - if (code == available) { - pixelStack[top++] = (byte) first; - code = old_code; - } - while (code > clear) { - pixelStack[top++] = suffix[code]; - code = prefix[code]; - } - first = ((int) suffix[code]) & 0xff; - - // Add a new string to the string table, - - if (available >= MAX_STACK_SIZE) { - pixelStack[top++] = (byte) first; - continue; - } - pixelStack[top++] = (byte) first; - prefix[available] = (short) old_code; - suffix[available] = (byte) first; - available++; - if (((available & code_mask) == 0) - && (available < MAX_STACK_SIZE)) { - code_size++; - code_mask += available; - } - old_code = in_code; - } - - // Pop a pixel off the pixel stack. - - top--; - pixels[pi++] = pixelStack[top]; - i++; - } - - for (i = pi; i < npix; i++) { - pixels[i] = 0; // clear missing pixels - } - - } - - /** - * Returns true if an error was encountered during reading/decoding - * - * @return true if an error was encountered during reading/decoding - */ - protected boolean err() { - return status != STATUS_OK; - } - - /** - * Initializes or re-initializes reader - */ - protected void init() { - status = STATUS_OK; - frameCount = 0; - frames = new ArrayList<>(); - gct = null; - lct = null; - } - - /** - * Reads a single byte from the input stream. - * - * @return single byte - */ - protected int read() { - int curByte = 0; - try { - curByte = in.read(); - } catch (final IOException e) { - status = STATUS_FORMAT_ERROR; - } - return curByte; - } - - /** - * Reads next variable length block from input. - * - * @return number of bytes stored in "buffer" - */ - protected int readBlock() { - blockSize = read(); - int n = 0; - if (blockSize > 0) { - try { - int count; - while (n < blockSize) { - count = in.read(block, n, blockSize - n); - if (count == -1) - break; - n += count; - } - } catch (final IOException e) { - //ignore - } - - if (n < blockSize) { - status = STATUS_FORMAT_ERROR; - } - } - return n; - } - - /** - * Reads color table as 256 RGB integer values - * - * @param ncolors int number of colors to read - * @return int array containing 256 colors (packed ARGB with full alpha) - */ - protected int[] readColorTable(final int ncolors) { - final int nbytes = 3 * ncolors; - int[] tab = null; - final byte[] c = new byte[nbytes]; - int n = 0; - try { - n = in.read(c); - } catch (final IOException e) { - //ignore - } - if (n < nbytes) { - status = STATUS_FORMAT_ERROR; - } else { - tab = new int[256]; // max size to avoid bounds checks - int i = 0; - int j = 0; - while (i < ncolors) { - final int r = ((int) c[j++]) & 0xff; - final int g = ((int) c[j++]) & 0xff; - final int b = ((int) c[j++]) & 0xff; - tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; - } - } - return tab; - } - - /** - * Main file parser. Reads GIF content blocks. - */ - protected void readContents() { - // read GIF file content blocks - boolean done = false; - while (!(done || err())) { - int code = read(); - switch (code) { - - case 0x2C: // image separator - readImage(); - break; - - case 0x21: // extension - code = read(); - switch (code) { - case 0xf9: // graphics control extension - readGraphicControlExt(); - break; - - case 0xff: // application extension - readBlock(); - final StringBuilder app = new StringBuilder(); - for (int i = 0; i < 11; i++) { - app.append((char) block[i]); - } - if ("NETSCAPE2.0".equals(app.toString())) { - readNetscapeExt(); - } else { - skip(); // don't care - } - break; - - default: // uninteresting extension - skip(); - } - break; - - case 0x3b: // terminator - done = true; - break; - - case 0x00: // bad byte, but keep going and see what happens - break; - - default: - status = STATUS_FORMAT_ERROR; - } - } - } - - /** - * Reads Graphics Control Extension values - */ - protected void readGraphicControlExt() { - read(); // block size - final int packed = read(); // packed fields - dispose = (packed & 0x1c) >> 2; // disposal method - if (dispose == 0) { - dispose = 1; // elect to keep old image if discretionary - } - transparency = (packed & 1) != 0; - delay = readShort() * 10; // delay in milliseconds - transIndex = read(); // transparent color index - read(); // block terminator - } - - /** - * Reads GIF file header information. - */ - protected void readHeader() { - final StringBuilder id = new StringBuilder(); - for (int i = 0; i < 6; i++) { - id.append((char) read()); - } - if (false == id.toString().startsWith("GIF")) { - status = STATUS_FORMAT_ERROR; - return; - } - - readLSD(); - if (gctFlag && !err()) { - gct = readColorTable(gctSize); - bgColor = gct[bgIndex]; - } - } - - /** - * Reads next frame image - */ - protected void readImage() { - ix = readShort(); // (sub)image position & size - iy = readShort(); - iw = readShort(); - ih = readShort(); - - final int packed = read(); - lctFlag = (packed & 0x80) != 0; // 1 - local color table flag - interlace = (packed & 0x40) != 0; // 2 - interlace flag - // 3 - sort flag - // 4-5 - reserved - lctSize = 2 << (packed & 7); // 6-8 - local color table size - - if (lctFlag) { - lct = readColorTable(lctSize); // read table - act = lct; // make local table active - } else { - act = gct; // make global table active - if (bgIndex == transIndex) - bgColor = 0; - } - int save = 0; - if (transparency) { - save = act[transIndex]; - act[transIndex] = 0; // set transparent color if specified - } - - if (act == null) { - status = STATUS_FORMAT_ERROR; // no color table defined - } - - if (err()) return; - - decodeImageData(); // decode pixel data - skip(); - - if (err()) return; - - frameCount++; - - // create new image to receive frame data - image = - new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); - - setPixels(); // transfer pixel data to image - - frames.add(new GifFrame(image, delay)); // add image to frame list - - if (transparency) { - act[transIndex] = save; - } - resetFrame(); - - } - - /** - * Reads Logical Screen Descriptor - */ - protected void readLSD() { - - // logical screen size - width = readShort(); - height = readShort(); - - // packed fields - final int packed = read(); - gctFlag = (packed & 0x80) != 0; // 1 : global color table flag - // 2-4 : color resolution - // 5 : gct sort flag - gctSize = 2 << (packed & 7); // 6-8 : gct size - - bgIndex = read(); // background color index - pixelAspect = read(); // pixel aspect ratio - } - - /** - * Reads Netscape extenstion to obtain iteration count - */ - protected void readNetscapeExt() { - do { - readBlock(); - if (block[0] == 1) { - // loop count sub-block - final int b1 = ((int) block[1]) & 0xff; - final int b2 = ((int) block[2]) & 0xff; - loopCount = (b2 << 8) | b1; - } - } while ((blockSize > 0) && !err()); - } - - /** - * Reads next 16-bit value, LSB first - * - * @return next 16-bit value - */ - protected int readShort() { - // read 16-bit value, LSB first - return read() | (read() << 8); - } - - /** - * Resets frame state for reading next image. - */ - protected void resetFrame() { - lastDispose = dispose; - lastRect = new Rectangle(ix, iy, iw, ih); - lastImage = image; - lastBgColor = bgColor; - lct = null; - } - - /** - * Skips variable length blocks up to and including - * next zero length block. - */ - protected void skip() { - do { - readBlock(); - } while ((blockSize > 0) && !err()); - } -} diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/LZWEncoder.java b/hutool-swing/src/main/java/cn/hutool/swing/img/gif/LZWEncoder.java deleted file mode 100755 index 0dc2e1ed8..000000000 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/LZWEncoder.java +++ /dev/null @@ -1,306 +0,0 @@ -package cn.hutool.swing.img.gif; - -import java.io.IOException; -import java.io.OutputStream; - -//============================================================================== -// Adapted from Jef Poskanzer's Java port by way of J. M. G. Elliott. -// K Weiner 12/00 - -class LZWEncoder { - - private static final int EOF = -1; - - private final int imgW; - private final int imgH; - private final byte[] pixAry; - private final int initCodeSize; - - private int remaining; - private int curPixel; - - // GIFCOMPR.C - GIF Image compression routines - // - // Lempel-Ziv compression based on 'compress'. GIF modifications by - // David Rowley (mgardi@watdcsu.waterloo.edu) - - // General DEFINEs - - static final int BITS = 12; - - static final int HSIZE = 5003; // 80% occupancy - - // GIF Image compression - modified 'compress' - // - // Based on: compress.c - File compression ala IEEE Computer, June 1984. - // - // By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) - // Jim McKie (decvax!mcvax!jim) - // Steve Davies (decvax!vax135!petsd!peora!srd) - // Ken Turkowski (decvax!decwrl!turtlevax!ken) - // James A. Woods (decvax!ihnp4!ames!jaw) - // Joe Orost (decvax!vax135!petsd!joe) - - int n_bits; // number of bits/code - int maxbits = BITS; // user settable max # bits/code - int maxcode; // maximum code, given n_bits - int maxmaxcode = 1 << BITS; // should NEVER generate this code - - int[] htab = new int[HSIZE]; - int[] codetab = new int[HSIZE]; - - int hsize = HSIZE; // for dynamic table sizing - - int free_ent = 0; // first unused entry - - // block compression parameters -- after all codes are used up, - // and compression rate changes, start over. - boolean clear_flg = false; - - // Algorithm: use open addressing double hashing (no chaining) on the - // prefix code / next character combination. We do a variant of Knuth's - // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime - // secondary probe. Here, the modular division first probe is gives way - // to a faster exclusive-or manipulation. Also do block compression with - // an adaptive reset, whereby the code table is cleared when the compression - // ratio decreases, but after the table fills. The variable-length output - // codes are re-sized at this point, and a special CLEAR code is generated - // for the decompressor. Late addition: construct the table according to - // file size for noticeable speed improvement on small files. Please direct - // questions about this implementation to ames!jaw. - - int g_init_bits; - - int ClearCode; - int EOFCode; - - // output - // - // Output the given code. - // Inputs: - // code: A n_bits-bit integer. If == -1, then EOF. This assumes - // that n_bits =< wordsize - 1. - // Outputs: - // Outputs code to the file. - // Assumptions: - // Chars are 8 bits long. - // Algorithm: - // Maintain a BITS character long buffer (so that 8 codes will - // fit in it exactly). Use the VAX insv instruction to insert each - // code in turn. When the buffer fills up empty it and start over. - - int cur_accum = 0; - int cur_bits = 0; - - final int[] masks = - { - 0x0000, - 0x0001, - 0x0003, - 0x0007, - 0x000F, - 0x001F, - 0x003F, - 0x007F, - 0x00FF, - 0x01FF, - 0x03FF, - 0x07FF, - 0x0FFF, - 0x1FFF, - 0x3FFF, - 0x7FFF, - 0xFFFF }; - - // Number of characters so far in this 'packet' - int a_count; - - // Define the storage for the packet accumulator - byte[] accum = new byte[256]; - - //---------------------------------------------------------------------------- - LZWEncoder(final int width, final int height, final byte[] pixels, final int color_depth) { - imgW = width; - imgH = height; - pixAry = pixels; - initCodeSize = Math.max(2, color_depth); - } - - // Add a character to the end of the current packet, and if it is 254 - // characters, flush the packet to disk. - void char_out(final byte c, final OutputStream outs) throws IOException { - accum[a_count++] = c; - if (a_count >= 254) - flush_char(outs); - } - - // Clear out the hash table - - // table clear for block compress - void cl_block(final OutputStream outs) throws IOException { - cl_hash(hsize); - free_ent = ClearCode + 2; - clear_flg = true; - - output(ClearCode, outs); - } - - // reset code table - void cl_hash(final int hsize) { - for (int i = 0; i < hsize; ++i) - htab[i] = -1; - } - - void compress(final int init_bits, final OutputStream outs) throws IOException { - int fcode; - int i /* = 0 */; - int c; - int ent; - int disp; - final int hsize_reg; - int hshift; - - // Set up the globals: g_init_bits - initial number of bits - g_init_bits = init_bits; - - // Set up the necessary values - clear_flg = false; - n_bits = g_init_bits; - maxcode = MAXCODE(n_bits); - - ClearCode = 1 << (init_bits - 1); - EOFCode = ClearCode + 1; - free_ent = ClearCode + 2; - - a_count = 0; // clear packet - - ent = nextPixel(); - - hshift = 0; - for (fcode = hsize; fcode < 65536; fcode *= 2) - ++hshift; - hshift = 8 - hshift; // set hash code range bound - - hsize_reg = hsize; - cl_hash(hsize_reg); // clear hash table - - output(ClearCode, outs); - - outer_loop : while ((c = nextPixel()) != EOF) { - fcode = (c << maxbits) + ent; - i = (c << hshift) ^ ent; // xor hashing - - if (htab[i] == fcode) { - ent = codetab[i]; - continue; - } else if (htab[i] >= 0) // non-empty slot - { - disp = hsize_reg - i; // secondary hash (after G. Knott) - if (i == 0) - disp = 1; - do { - if ((i -= disp) < 0) - i += hsize_reg; - - if (htab[i] == fcode) { - ent = codetab[i]; - continue outer_loop; - } - } while (htab[i] >= 0); - } - output(ent, outs); - ent = c; - if (free_ent < maxmaxcode) { - codetab[i] = free_ent++; // code -> hashtable - htab[i] = fcode; - } else { - cl_block(outs); - } - } - // Put out the final code. - output(ent, outs); - output(EOFCode, outs); - } - - //---------------------------------------------------------------------------- - void encode(final OutputStream os) throws IOException { - os.write(initCodeSize); // write "initial code size" byte - - remaining = imgW * imgH; // reset navigation variables - curPixel = 0; - - compress(initCodeSize + 1, os); // compress and write the pixel data - - os.write(0); // write block terminator - } - - // Flush the packet to disk, and reset the accumulator - void flush_char(final OutputStream outs) throws IOException { - if (a_count > 0) { - outs.write(a_count); - outs.write(accum, 0, a_count); - a_count = 0; - } - } - - final int MAXCODE(final int n_bits) { - return (1 << n_bits) - 1; - } - - //---------------------------------------------------------------------------- - // Return the next pixel from the image - //---------------------------------------------------------------------------- - private int nextPixel() { - if (remaining == 0) - return EOF; - - --remaining; - - final byte pix = pixAry[curPixel++]; - - return pix & 0xff; - } - - void output(final int code, final OutputStream outs) throws IOException { - cur_accum &= masks[cur_bits]; - - if (cur_bits > 0) - cur_accum |= (code << cur_bits); - else - cur_accum = code; - - cur_bits += n_bits; - - while (cur_bits >= 8) { - char_out((byte) (cur_accum & 0xff), outs); - cur_accum >>= 8; - cur_bits -= 8; - } - - // If the next entry is going to be too big for the code size, - // then increase it, if possible. - if (free_ent > maxcode || clear_flg) { - if (clear_flg) { - maxcode = MAXCODE(n_bits = g_init_bits); - clear_flg = false; - } else { - ++n_bits; - if (n_bits == maxbits) - maxcode = maxmaxcode; - else - maxcode = MAXCODE(n_bits); - } - } - - if (code == EOFCode) { - // At EOF, write the rest of the buffer. - while (cur_bits > 0) { - char_out((byte) (cur_accum & 0xff), outs); - cur_accum >>= 8; - cur_bits -= 8; - } - - flush_char(outs); - } - } -} diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/NeuQuant.java b/hutool-swing/src/main/java/cn/hutool/swing/img/gif/NeuQuant.java deleted file mode 100755 index ff128f59e..000000000 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/NeuQuant.java +++ /dev/null @@ -1,444 +0,0 @@ -package cn.hutool.swing.img.gif; - -/** - * NeuQuant Neural-Net Quantization Algorithm - * - * @author Dekker - */ -public class NeuQuant { - - protected static final int NETSIZE = 256; /* number of colours used */ - - /* four primes near 500 - assume no image has a length so large */ - /* that it is divisible by all four primes */ - protected static final int PRIME1 = 499; - protected static final int PRIME2 = 491; - protected static final int PRIME3 = 487; - protected static final int PRIME4 = 503; - - protected static final int MINPICTUREBYTES = (3 * PRIME4); - /* minimum size for input image */ - - /* Program Skeleton - ---------------- - [select samplefac in range 1..30] - [read image from input file] - pic = (unsigned char*) malloc(3*width*height); - initnet(pic,3*width*height,samplefac); - learn(); - unbiasnet(); - [write output image header, using writecolourmap(f)] - inxbuild(); - write output image using inxsearch(b,g,r) */ - - /* Network Definitions - ------------------- */ - - protected static final int MAXNETPOS = (NETSIZE - 1); - protected static final int NETBIASSHIFT = 4; /* bias for colour values */ - protected static final int NCYCLES = 100; /* no. of learning cycles */ - - /* defs for freq and bias */ - protected static final int INTBIASSHIFT = 16; /* bias for fractions */ - protected static final int INTBIAS = (1 << INTBIASSHIFT); - protected static final int GAMMASHIFT = 10; /* gamma = 1024 */ - protected static final int GAMMA = (1 << GAMMASHIFT); - protected static final int BETASHIFT = 10; - protected static final int BETA = (INTBIAS >> BETASHIFT); /* beta = 1/1024 */ - protected static final int BETAGAMMA = - (INTBIAS << (GAMMASHIFT - BETASHIFT)); - - /* defs for decreasing radius factor */ - protected static final int INITRAD = (NETSIZE >> 3); /* for 256 cols, radius starts */ - protected static final int RADIUSBIASSHIFT = 6; /* at 32.0 biased by 6 bits */ - protected static final int RADIUSBIAS = (1 << RADIUSBIASSHIFT); - protected static final int INITRADIUS = (INITRAD * RADIUSBIAS); /* and decreases by a */ - protected static final int RADIUSDEC = 30; /* factor of 1/30 each cycle */ - - /* defs for decreasing alpha factor */ - protected static final int ALPHABIASSHIFT = 10; /* alpha starts at 1.0 */ - protected static final int INITALPHA = (1 << ALPHABIASSHIFT); - - protected int alphadec; /* biased by 10 bits */ - - /* radbias and alpharadbias used for radpower calculation */ - protected static final int RADBIASSHIFT = 8; - protected static final int RADBIAS = (1 << RADBIASSHIFT); - protected static final int ALPHARADBSHIFT = (ALPHABIASSHIFT + RADBIASSHIFT); - protected static final int ALPHARADBIAS = (1 << ALPHARADBSHIFT); - - /* Types and Global Variables - -------------------------- */ - - protected byte[] thepicture; /* the input image itself */ - protected int lengthcount; /* lengthcount = H*W*3 */ - - protected int samplefac; /* sampling factor 1..30 */ - - // typedef int pixel[4]; /* BGRc */ - protected int[][] network; /* the network itself - [netsize][4] */ - - protected int[] netindex = new int[256]; - /* for network lookup - really 256 */ - - protected int[] bias = new int[NETSIZE]; - /* bias and freq arrays for learning */ - protected int[] freq = new int[NETSIZE]; - protected int[] radpower = new int[INITRAD]; - /* radpower for precomputation */ - - /* Initialise network in range (0,0,0) to (255,255,255) and set parameters - ----------------------------------------------------------------------- */ - public NeuQuant(final byte[] thepic, final int len, final int sample) { - - int i; - int[] p; - - thepicture = thepic; - lengthcount = len; - samplefac = sample; - - network = new int[NETSIZE][]; - for (i = 0; i < NETSIZE; i++) { - network[i] = new int[4]; - p = network[i]; - p[0] = p[1] = p[2] = (i << (NETBIASSHIFT + 8)) / NETSIZE; - freq[i] = INTBIAS / NETSIZE; /* 1/netsize */ - bias[i] = 0; - } - } - - public byte[] colorMap() { - final byte[] map = new byte[3 * NETSIZE]; - final int[] index = new int[NETSIZE]; - for (int i = 0; i < NETSIZE; i++) - index[network[i][3]] = i; - int k = 0; - for (int i = 0; i < NETSIZE; i++) { - final int j = index[i]; - map[k++] = (byte) (network[j][0]); - map[k++] = (byte) (network[j][1]); - map[k++] = (byte) (network[j][2]); - } - return map; - } - - /* Insertion sort of network and building of netindex[0..255] (to do after unbias) - ------------------------------------------------------------------------------- */ - public void inxbuild() { - - int i, j, smallpos, smallval; - int[] p; - int[] q; - int previouscol, startpos; - - previouscol = 0; - startpos = 0; - for (i = 0; i < NETSIZE; i++) { - p = network[i]; - smallpos = i; - smallval = p[1]; /* index on g */ - /* find smallest in i..netsize-1 */ - for (j = i + 1; j < NETSIZE; j++) { - q = network[j]; - if (q[1] < smallval) { /* index on g */ - smallpos = j; - smallval = q[1]; /* index on g */ - } - } - q = network[smallpos]; - /* swap p (i) and q (smallpos) entries */ - if (i != smallpos) { - j = q[0]; - q[0] = p[0]; - p[0] = j; - j = q[1]; - q[1] = p[1]; - p[1] = j; - j = q[2]; - q[2] = p[2]; - p[2] = j; - j = q[3]; - q[3] = p[3]; - p[3] = j; - } - /* smallval entry is now in position i */ - if (smallval != previouscol) { - netindex[previouscol] = (startpos + i) >> 1; - for (j = previouscol + 1; j < smallval; j++) - netindex[j] = i; - previouscol = smallval; - startpos = i; - } - } - netindex[previouscol] = (startpos + MAXNETPOS) >> 1; - for (j = previouscol + 1; j < 256; j++) - netindex[j] = MAXNETPOS; /* really 256 */ - } - - /* Main Learning Loop - ------------------ */ - public void learn() { - - int i, j, b, g, r; - int radius; - int rad; - int alpha; - final int step; - int delta; - final int samplepixels; - final byte[] p; - int pix; - final int lim; - - if (lengthcount < MINPICTUREBYTES) - samplefac = 1; - alphadec = 30 + ((samplefac - 1) / 3); - p = thepicture; - pix = 0; - lim = lengthcount; - samplepixels = lengthcount / (3 * samplefac); - delta = samplepixels / NCYCLES; - alpha = INITALPHA; - radius = INITRADIUS; - - rad = radius >> RADIUSBIASSHIFT; - for (i = 0; i < rad; i++) - radpower[i] = - alpha * (((rad * rad - i * i) * RADBIAS) / (rad * rad)); - - //fprintf(stderr,"beginning 1D learning: initial radius=%d\n", rad); - - if (lengthcount < MINPICTUREBYTES) - step = 3; - else if ((lengthcount % PRIME1) != 0) - step = 3 * PRIME1; - else { - if ((lengthcount % PRIME2) != 0) - step = 3 * PRIME2; - else { - if ((lengthcount % PRIME3) != 0) - step = 3 * PRIME3; - else - step = 3 * PRIME4; - } - } - - i = 0; - while (i < samplepixels) { - b = (p[pix] & 0xff) << NETBIASSHIFT; - g = (p[pix + 1] & 0xff) << NETBIASSHIFT; - r = (p[pix + 2] & 0xff) << NETBIASSHIFT; - j = contest(b, g, r); - - altersingle(alpha, j, b, g, r); - if (rad != 0) - alterneigh(rad, j, b, g, r); /* alter neighbours */ - - pix += step; - if (pix >= lim) - pix -= lengthcount; - - i++; - if (delta == 0) - delta = 1; - if (i % delta == 0) { - alpha -= alpha / alphadec; - radius -= radius / RADIUSDEC; - rad = radius >> RADIUSBIASSHIFT; - if (rad <= 1) - rad = 0; - for (j = 0; j < rad; j++) - radpower[j] = - alpha * (((rad * rad - j * j) * RADBIAS) / (rad * rad)); - } - } - //fprintf(stderr,"finished 1D learning: final alpha=%f !\n",((float)alpha)/initalpha); - } - - /* Search for BGR values 0..255 (after net is unbiased) and return colour index - ---------------------------------------------------------------------------- */ - public int map(final int b, final int g, final int r) { - - int i, j, dist, a, bestd; - int[] p; - int best; - - bestd = 1000; /* biggest possible dist is 256*3 */ - best = -1; - i = netindex[g]; /* index on g */ - j = i - 1; /* start at netindex[g] and work outwards */ - - while ((i < NETSIZE) || (j >= 0)) { - if (i < NETSIZE) { - p = network[i]; - dist = p[1] - g; /* inx key */ - if (dist >= bestd) - i = NETSIZE; /* stop iter */ - else { - i++; - if (dist < 0) - dist = -dist; - a = p[0] - b; - if (a < 0) - a = -a; - dist += a; - if (dist < bestd) { - a = p[2] - r; - if (a < 0) - a = -a; - dist += a; - if (dist < bestd) { - bestd = dist; - best = p[3]; - } - } - } - } - if (j >= 0) { - p = network[j]; - dist = g - p[1]; /* inx key - reverse dif */ - if (dist >= bestd) - j = -1; /* stop iter */ - else { - j--; - if (dist < 0) - dist = -dist; - a = p[0] - b; - if (a < 0) - a = -a; - dist += a; - if (dist < bestd) { - a = p[2] - r; - if (a < 0) - a = -a; - dist += a; - if (dist < bestd) { - bestd = dist; - best = p[3]; - } - } - } - } - } - return (best); - } - - public byte[] process() { - learn(); - unbiasnet(); - inxbuild(); - return colorMap(); - } - - /* Unbias network to give byte values 0..255 and record position i to prepare for sort - ----------------------------------------------------------------------------------- */ - public void unbiasnet() { - for (int i = 0; i < NETSIZE; i++) { - network[i][0] >>= NETBIASSHIFT; - network[i][1] >>= NETBIASSHIFT; - network[i][2] >>= NETBIASSHIFT; - network[i][3] = i; /* record colour no */ - } - } - - /* Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|] - --------------------------------------------------------------------------------- */ - protected void alterneigh(final int rad, final int i, final int b, final int g, final int r) { - - int j, k, lo, hi, a, m; - int[] p; - - lo = i - rad; - if (lo < -1) - lo = -1; - hi = i + rad; - if (hi > NETSIZE) - hi = NETSIZE; - - j = i + 1; - k = i - 1; - m = 1; - while ((j < hi) || (k > lo)) { - a = radpower[m++]; - if (j < hi) { - p = network[j++]; - try { - p[0] -= (a * (p[0] - b)) / ALPHARADBIAS; - p[1] -= (a * (p[1] - g)) / ALPHARADBIAS; - p[2] -= (a * (p[2] - r)) / ALPHARADBIAS; - } catch (final Exception ignored) { - } // prevents 1.3 miscompilation - } - if (k > lo) { - p = network[k--]; - try { - p[0] -= (a * (p[0] - b)) / ALPHARADBIAS; - p[1] -= (a * (p[1] - g)) / ALPHARADBIAS; - p[2] -= (a * (p[2] - r)) / ALPHARADBIAS; - } catch (final Exception ignored) { - } - } - } - } - - /* Move neuron i towards biased (b,g,r) by factor alpha - ---------------------------------------------------- */ - protected void altersingle(final int alpha, final int i, final int b, final int g, final int r) { - - /* alter hit neuron */ - final int[] n = network[i]; - n[0] -= (alpha * (n[0] - b)) / INITALPHA; - n[1] -= (alpha * (n[1] - g)) / INITALPHA; - n[2] -= (alpha * (n[2] - r)) / INITALPHA; - } - - /* Search for biased BGR values - ---------------------------- */ - protected int contest(final int b, final int g, final int r) { - - /* finds closest neuron (min dist) and updates freq */ - /* finds best neuron (min dist-bias) and returns position */ - /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */ - /* bias[i] = gamma*((1/netsize)-freq[i]) */ - - int i, dist, a, biasdist, betafreq; - int bestpos, bestbiaspos, bestd, bestbiasd; - int[] n; - - bestd = ~(1 << 31); - bestbiasd = bestd; - bestpos = -1; - bestbiaspos = bestpos; - - for (i = 0; i < NETSIZE; i++) { - n = network[i]; - dist = n[0] - b; - if (dist < 0) - dist = -dist; - a = n[1] - g; - if (a < 0) - a = -a; - dist += a; - a = n[2] - r; - if (a < 0) - a = -a; - dist += a; - if (dist < bestd) { - bestd = dist; - bestpos = i; - } - biasdist = dist - ((bias[i]) >> (INTBIASSHIFT - NETBIASSHIFT)); - if (biasdist < bestbiasd) { - bestbiasd = biasdist; - bestbiaspos = i; - } - betafreq = (freq[i] >> BETASHIFT); - freq[i] -= betafreq; - bias[i] += (betafreq << GAMMASHIFT); - } - freq[bestpos] += BETA; - bias[bestpos] -= BETAGAMMA; - return (bestbiaspos); - } -} diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/package-info.java b/hutool-swing/src/main/java/cn/hutool/swing/img/gif/package-info.java deleted file mode 100755 index e0280645d..000000000 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * GIF处理,来自:https://github.com/rtyley/animated-gif-lib-for-java - * - * @author looly - * - */ -package cn.hutool.swing.img.gif;