Java、JFrame製作錄製GIF小工具
和截圖工具類似,選取一塊區域截圖儲存成圖片,gif錄製就是選取一塊區域持續錄製,最後儲存成gif動畫圖片。
執行效果
1、選取需要錄製的區域(滑鼠拖拽選擇錄製的區域)
2、點選開始按鈕開始錄製GIF圖片(開始錄製時,區域邊框會閃爍)
3、點選結束按鈕儲存GIF圖片(沒錯提示就是這麼裸露,自己懶得優化)
4、最後生成GIF圖片
設計思路
1、如何繪製矩形區域
如何繪製使用者可見的矩形區域,這是一個小的難點,你可以在JFrame繪製任意的形狀,如何不遮擋螢幕的情況下,再螢幕任何地方選取一塊區域呢
a、首先畫一個和螢幕一樣大的透明JFrame。
來看下上面的一段程式碼,是顯示一個和電腦螢幕一樣大的透明視窗。
// 設定視窗無標題部分
this.setUndecorated(true);
// 設定透明背景色,0x01000000 ,01表示透明度
// 這裡要注意,不能將視窗設定為00(完全透明),如果設定為完全透明,滑鼠將無法聚焦當前視窗,也就無法繪製圖形了,這裡你可以改成00試試看你就明白了。
this.setBackground(new Color(0x01000000, true));
b、 再監聽滑鼠拖拽事件,畫矩形
上面程式碼就是畫一個矩形,是通過設定label的邊框、大小和起點位置來畫矩形的
if (sx == -1) // sx=-1說明是滑鼠第一次按下,設定label的位置,也就是矩形的位置
else // 否則是滑鼠按下拖拽的過程,只需要設定label的大小即可形成一個繪製矩形的效果
選取矩形區域這裡有個BUG,用了你就知道了,懶得改 :)
2、截圖
這個錄gif不是說選取區域之後就開始錄製了,而是先不停的擷取區域的圖片儲存到臨時路徑下。
上圖程式碼就是每隔interval毫秒擷取螢幕並儲存為圖片的,截圖儲存圖片的程式碼很簡單,自己稍微看下就明白了。
這裡有個需要注意的地方就是,擷取的螢幕是不含滑鼠的。但是截圖沒有滑鼠就算了,gif圖片肯定記錄操作的,沒有滑鼠怎麼行。這裡的處理是:每次截圖的時候獲取滑鼠位置資訊,在滑鼠所在的位置繪製一個小圓圈即可,如下圖程式碼。
3、儲存GIF
儲存GIF就比較簡單了,網上找的一個GIF工具類AnimatedGifEncoder,不知道哪位大神寫的。
程式碼
主介面:GIFCapture.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.border.LineBorder;
import javax.swing.filechooser.FileSystemView;
/**
* 螢幕GIF動畫錄製,有兩個較大的問題可以優化(1、儲存GIF圖片的時間太長。2、儲存GIF圖片太大),如果你有好的建議可以加QQ294618814,一起探討
*
* @author ding.yi 2017年3月10日 上午10:20:36
*
*/
@SuppressWarnings("serial")
public class GIFCapture extends JFrame {
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screenSize = toolkit.getScreenSize();
JLabel label = new JLabel();
JButton startBtn = new JButton("開始");
JButton existBtn = new JButton("取消");
Boolean isRecording = false;
Rectangle rectangle = null;
// 臨時檔案存放的路徑
String tempFilePath = "C:/Windows/temp/java_capture/";
// 沒幀間隔時間(ms),100MS就是說1秒鐘10張圖片
int interval = 100;
public GIFCapture() {
setLayout(null);
label.setName("black");
label.setVisible(false);
label.setBorder(new LineBorder(Color.black, 4));
label.setBackground(new Color(0x00000000, true));
this.add(label);
// 開始和取消按鈕
startBtn.setMargin(new Insets(0, 0, 0, 0));
existBtn.setMargin(new Insets(0, 0, 0, 0));
startBtn.setSize(50, 24);
existBtn.setSize(50, 24);
startBtn.setVisible(false);
existBtn.setVisible(false);
existBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
System.exit(0);
}
});
startBtn.addActionListener(recordListener);
this.add(startBtn);
this.add(existBtn);
// 視窗屬性設定
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(screenSize);
this.setUndecorated(true);
this.setBackground(new Color(0x01000000, true));
this.setVisible(true);
this.setAlwaysOnTop(true);
// 鍵盤事件,按Esc鍵可以推出程式
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 27) {
dispose();
System.exit(0);
}
}
});
this.addMouseMotionListener(ml);
}
int sx = -1, sy = -1, cx = -1, cy = -1;
boolean isDrag = false;
MouseMotionListener ml = new MouseMotionListener() {
@Override
public void mouseMoved(MouseEvent e) {
if (Math.abs(sx - cx) > 0 && Math.abs(sy - cy) > 0) {
startBtn.setLocation(cx - startBtn.getWidth(), cy);
existBtn.setLocation(cx - startBtn.getWidth() - existBtn.getWidth(), cy);
startBtn.setVisible(true);
existBtn.setVisible(true);
rectangle = new Rectangle(sx + 4, sy + 4, Math.abs(sx - cx) - 8, Math.abs(sy - cy) - 8);
sx = -1;
sy = -1;
cx = -1;
cy = -1;
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (isRecording) {
return;
}
if (sx == -1) {
sx = e.getX();
sy = e.getY();
startBtn.setVisible(false);
label.setSize(0, 0 );
label.setLocation(sx, sy);
} else {
cx = e.getX();
cy = e.getY();
label.setSize(Math.abs(sx - cx), Math.abs(sy - cy));
label.setVisible(true);
}
repaint();
}
};
ActionListener recordListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
isRecording = "開始".contentEquals(startBtn.getText());
if (isRecording) {
setBackground(new Color(0x00000000, true));
startBtn.setText("結束");
existBtn.setVisible(false);
startRecording();
} else {
existBtn.setVisible(false);
startBtn.setVisible(false);
}
}
};
protected void startRecording() {
File f = new File(tempFilePath);
if (!f.exists()) {
f.mkdirs();
}
// 先將臨時資料夾中的截圖全部刪除
for (File img : f.listFiles()) {
img.delete();
}
// 開始錄製,閃爍邊框
new Thread(new BlinkRunnable()).start();
// 開始錄製,先將截圖一張一張儲存到臨時資料夾下
new Thread(new Runnable() {
@Override
public void run() {
try {
while (isRecording) {
creater(); // 開啟執行緒單獨截圖
Thread.sleep(interval);
}
ScreenCapture.saveScreen(rectangle, tempFilePath + System.nanoTime() + ".xy");
saveGIF();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Q: 這裡為何要單獨開啟執行緒截圖?
* A: 只為了保證沒幀的間隔時間一樣,因為截圖需要一點時間,不開啟執行緒截圖會導致gif動畫變快
*/
private void creater() {
new Thread(new Runnable() {
@Override
public void run() {
ScreenCapture.saveScreen(rectangle, tempFilePath + System.nanoTime() + ".xy");
}
}).start();
}
/**
* 開始將截圖圖片儲存為GIF圖片,
*/
private void saveGIF() {
label.setBackground(Color.gray);
label.setBorder(new LineBorder(Color.black, 2));
label.setSize(400, 60);
label.setText("正在儲存圖片,請稍等...");
label.setFont(new Font("宋體", Font.BOLD, 20));
System.out.println("正在儲存GIF圖片...");
// GIF圖片儲存路徑預設為桌面,沒有提供選擇儲存路徑介面,可以優化
String desktopPath = FileSystemView.getFileSystemView().getHomeDirectory() + "/";
ScreenCapture.createGIF(tempFilePath, desktopPath + "JAVA截圖" + System.currentTimeMillis() + ".GIF", interval);
System.out.println("完成");
dispose();
System.exit(0);
}
}).start();
}
/**
* 視窗閃爍效果
*/
class BlinkRunnable implements Runnable {
@Override
public void run() {
while (true) {
try {
// isRecording為false表示沒有錄製,就一直等待
if (!isRecording) {
Thread.sleep(100);
continue;
}
// 來切換邊框的顏色 黑紅黑紅的閃爍,表示正在錄製
Color color = null;
if ("black".equals(label.getName())) {
color = Color.red;
label.setName("red");
} else {
color = Color.black;
label.setName("black");
}
label.setBorder(new LineBorder(color, 4));
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
new GIFCapture();
}
}
自己封裝的截圖工具類:ScreenCapture.java
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import com.test.lib.AnimatedGifEncoder;
/**
* 螢幕擷取工具
*
* @author ding.yi 2017年3月10日 上午11:17:45
*
*/
public class ScreenCapture {
static List<BufferedImage> captureBuffList = new ArrayList<BufferedImage>();
/**
* 通過座標和大小擷取螢幕,得到BufferedImage
* @param x 截圖起點座標x
* @param y 截圖起點座標y
* @param w 寬度
* @param h 高度
* @return BufferedImage
*/
public static BufferedImage getScreen(int x, int y, int w, int h) {
Rectangle rect = new Rectangle(x, y, w, h);
BufferedImage captureImg = null;
Point p = MouseInfo.getPointerInfo().getLocation();
try {
captureImg = new Robot().createScreenCapture(rect);
// 這裡截圖的時候花了一個紅圓圈,標識滑鼠所在的位置,也可以換成一個滑鼠央視的圖片
// 是為了製作gif動畫用的,如果是單純的截圖就不需要
Graphics g = captureImg.getGraphics();
g.setColor(Color.red);
g.fillArc(p.x - x, p.y - y, 15, 15, 0, 360);
} catch (AWTException e) {
e.printStackTrace();
}
return captureImg;
}
public static void saveScreen(Rectangle rect, String savePath) {
saveScreen(rect.x, rect.y, rect.width, rect.height, savePath);
}
public static void saveScreen(Rectangle rect) {
BufferedImage captureImg = getScreen(rect.x, rect.y, rect.width, rect.height);
captureBuffList.add(captureImg);
}
public static void createGIF(String gifPath, int interval) {
try {
AnimatedGifEncoder e = new AnimatedGifEncoder();
e.setRepeat(0);
e.start(gifPath);
for (BufferedImage bufferedImage : captureBuffList) {
e.setDelay(interval);下·
e.addFrame(bufferedImage);
}
e.finish();
} catch (Exception e) {
e.printStackTrace();
} finally {
captureBuffList.clear();
}
}
/**
* 儲存截圖
* @param x 截圖x座標
* @param y 截圖y座標
* @param w 截圖寬度
* @param h 截圖高度
* @param savePath 截圖圖片儲存位置
*/
public static void saveScreen(int x, int y, int w, int h, String savePath) {
BufferedImage captureImg = getScreen(x, y, w, h);
File saveFile = new File(savePath);
if (!saveFile.getParentFile().exists()) {
saveFile.mkdirs();
}
try {
ImageIO.write(captureImg, "PNG", saveFile);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 將資料夾中的所有圖片製作成GIF圖片,GIF圖片製作的方法是從網上找來的(AnimatedGifEncoder、LZWEncoder和NeuQuant三個類)。
* @param folderPath 幀圖片所在資料夾
* @param gifPath 儲存的GIF圖片路徑
* @param interval 沒幀間隔(毫秒)
*/
public static void createGIF(String folderPath, String gifPath, int interval) {
File[] pic = new File(folderPath).listFiles();
try {
AnimatedGifEncoder e = new AnimatedGifEncoder();
e.setRepeat(0);
e.start(gifPath);
BufferedImage src[] = new BufferedImage[pic.length];
for (int i = 0; i < src.length; i++) {
e.setDelay(interval); // 設定播放的延遲時間
src[i] = ImageIO.read(pic[i]); // 讀入需要播放的jpg檔案
e.addFrame(src[i]); // 新增到幀中
}
e.finish();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 1; i <= 100; i++) {
final int j = i;
new Thread(new Runnable() {
@Override
public void run() {
saveScreen(0, 0, 1069, 746, "F:/a/" + (j < 10 ? "0" : "") + j + ".png");
}
}).start();
Thread.sleep(100);
}
createGIF("F:/a/", "F:/a/gif.gif", 100);
}
}
GIF工具類,一共三個
NeuQuant.java
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 = (((int) 1) << intbiasshift);
protected static final int gammashift = 10; /* gamma = 1024 */
protected static final int gamma = (((int) 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 = (((int) 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 = (((int) 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 = (((int) 1) << radbiasshift);
protected static final int alpharadbshift = (alphabiasshift + radbiasshift);
protected static final int alpharadbias = (((int) 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(byte[] thepic, int len, 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() {
byte[] map = new byte[3 * netsize];
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++) {
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, rad, alpha, step, delta, samplepixels;
byte[] p;
int pix, 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;
if (rad <= 1)
rad = 0;
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 + 0] & 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(int b, int g, 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() {
int i, j;
for (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(int rad, int i, int b, int g, 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 (Exception e) {
} // 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 (Exception e) {
}
}
}
}
/*
* Move neuron i towards biased (b,g,r) by factor alpha
* ----------------------------------------------------
*/
protected void altersingle(int alpha, int i, int b, int g, int r) {
/* alter hit neuron */
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(int b, int g, 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 = ~(((int) 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);
}
}
LZWEncoder.java
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
public class LZWEncoder {
private static final int EOF = -1;
相關推薦
Java、JFrame製作錄製GIF小工具
和截圖工具類似,選取一塊區域截圖儲存成圖片,gif錄製就是選取一塊區域持續錄製,最後儲存成gif動畫圖片。
執行效果
1、選取需要錄製的區域(滑鼠拖拽選擇錄製的區域)
2、點選開始按鈕開始錄製GIF圖片(開始錄製時,區域邊框會閃爍)
3
java -- jre 精簡,為桌面小工具開發瘦身
開發桌面應用程式經常需要打包執行。這時就要jre執行環境,jre包比較大180M左右。好多沒用的檔案,jar包就要去掉。
1,第一步,先用工具。GreenJVMMake.jar
對jre包裡的rt.jar精簡這裡連線資源上傳了這個小工具。 裡邊有執行步驟。得到的是經常別
Java Log4j2 動態調整log級別小工具
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import o
用Java Swing編寫簡單的測試小工具介面(原始碼)
Author:Pirate Leo
前段時間我負責在系統中添加了HBase用於管理海量資料,功能實現後自然到了效能測試階段,效能、可靠性、穩定性,性性都不能少。
因此就有了個內部的小需求:“給測試部提供一個工具,可以向HBase寫入資料,以達到測試所需的資料量”。
Java開發報表匯入,匯出小工具類
當前演示是是一個自己寫的小工具類報表 匯入 匯出 :
當前的位置是具體的實現 註釋位置是我們需要自己去新增的(匯出或者匯入)
@RequestMapping(value="/exportData",method = RequestMethod.POST)
pu
Java11 & JavaFX 初體驗 - Java 代碼生成 Markdown 的小工具
bash 生成文檔 要求 with 路徑 ast lsa j2objc 跨平臺開發 2019新春支付寶紅包技術大揭秘在線峰會將於03-07日開始,點擊這裏報名屆時即可參與大牛互動。
概述
Java 11 自 2018.9.25 發布以來,已經好幾個月了,在還沒正式 GA 之
java 小工具之--zip包解壓,刪除目錄及文件、
str 備份 odin .get flag source input director 使用 import org.apache.tools.ant.BuildException;import org.apache.tools.ant.Project;import org
python小工具 - alert彈框輸出姓名年齡、求和
sum entry 數字 之間 col import 技術分享 app button 使用python自帶的tkinter庫進行GUI編程,完成兩個功能:
(1)要求用戶輸入姓名和年齡然後打印出來
(2)要求用戶輸入一個數字,然後計算1到該數字之間的和
代碼部分:
# 導
看到一個詞語提取小工具,分享給有標簽、詞庫需求的同學們
詞庫 搜索 新詞發現 標簽 自然語言處理 關於詞語小工具的描述快戳下面鏈接~~~
https://forum.huaweicloud.com/thread-8391-1-1.html
不想看文章,想立即試用小工具的,請戳下面~~~http://fe2e6fd859034d40a3269f7
Java開發 小工具累計
integer spa list arr pre () filter head mob array to list
Integer[] spam = new Integer[] { 1, 2, 3 };
List<Integer> rlt = Arrays.a
Github Java/Python小工具---終端執行的新華字典,查詢字,成語,歇後語
新增Python版本
今天使用Python做了一下,發現比Java做起來簡單很多,已經上傳到github上了,使用起來也更加簡單了,因為Python本來就是指令碼語言,所以就不用再寫一個指令碼了,直接chmod a+x 新華字典.py ,然後./新華字典 就可以了
今天做了
經緯座標(BLH)資料建立.kml檔案小工具設計 Java版
技術背景 KML,是標記語言(Keyhole Markup Language)的縮寫,最初由Keyhole公司開發,是一種基於XML 語法與格式的、用於描述和儲存地理資訊(如點、線、影象、多邊形和模型等)的編碼規範,可以被 Google Earth 和 Google Maps 識別並顯
java問題、知識(編譯環境)工具類
1、在JRE任意jar包中的META-INF-》MANIFEST.MF 可以檢視當前java的版本
2、錯誤1316
開啟登錄檔regedit-》 計算機\HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\
把其中的已有的(和所需安裝的)版本號刪掉再安
3、ver
java工具(二):MessageFormat在沒有jdk環境的電腦上執行java專案,製作exe檔案
把jar檔案打包成可執行的.exe檔案,在沒有jdk的環境的電腦執行
1.準備2個檔案,1個是你要打包的jar檔案,另1個是jdk檔案下面的jre
如果嫌jre檔案太大,你們可以去網上找下精簡版的jre
2.安裝exe4j打包工具,執行打包操作
一個線上排版小工具:中文、英文、數字、符號中間加個空格
我一直相信這個世界是懶人創造的。
大家如果仔細看我的文章,會發現一個有趣的地方。就是數字、英文和中文之間會多一個空格,比如 1 是數字,1 兩邊有空格。如果你再仔細觀察,微信文字訊息的排版風格也是這樣,不信你試試。
這個排版的風格是師從 stormzhang,包括微信整個排版風格都跟他差不多,只是我比較喜歡在
從0到1製作WordPress主題#11使用小工具widgets
建立widgets顯示位置
這一章節,我們學習如何在主題中建立視窗小工具。 我們將有一個小工具位置,這將位於側邊欄中。
1、開啟index.php,找到class=main的div標籤,在其結束標籤下方建立一個class=sidebar的div,和一個class
WordPress主題製作進階#9使用主題小工具widget
這節我們學習使用小公具
我們現在有個側邊欄,但是其內容都是靜態的,我們把側邊欄替換成動態的小公具。在部落格頁面和任何其他頁面上,除了我們稍後將建立的自定義主頁之外,這將是唯一的小工具。我們將在functions檔案中新增小工具的顯示位置。
開啟functions
#資料結構與演算法學習筆記#劍指Offer30:把陣列排成最小的數 + 自定義比較器 + 測試用例(Java、C/C++)
2018.10.6
1.求全排列最小。事實上用全排列硬剛這道題確實是最直接的辦法,因為乍一眼看上去實在不好歸納數字之間的順序關係,全排列具體實現原理可以參考上述文章。
2.自定義比較器。為什麼說
Java類的組合與繼承 小問題分析(建構函式引數的傳遞方法 、資料隱藏的處理: 對比C++)
一、類的組合:
1、初始化問題(建構函式的引數傳遞方法):
在C++中,通常只要物件中不含有指標類資料的話,物件與物件之間是可以相互賦值且不會出錯的,因此組合出來的類完全可以將傳遞過來的物件引數直接賦值給對應資料成員;
而在java中,物
推薦各類程式語言的IDE整合開發工具: Java、PHP、web、Python等
古語有云“紙上學來終覺淺,絕知此事要躬行”。想要學好學通學精一門程式語言,還是要勤加練習啊~今天小編為大家推薦幾類IDE整合開發工具,好的工具不僅能幫你提高工作效率,而且還能提高你的工作能力。
Java篇
Java JDK API
JDK(Java Development Kit