2008年6月26日木曜日
GIF解码和编码操作库源码
1.AnimatedGifEncoder.java2.GifDecoder.java3.LZWEncoder.java4.NeuQuant.java简单应用: import javax.imageio.ImageIO;
import java.io.*;
import java.awt.image.*;
public class Testgif{
public static void main(String args[]){
try{
BufferedImage src = ImageIO.read(new File("c:/work/1.jpg")); // 读入文件
BufferedImage src1 = ImageIO.read(new File("c:/work/2.jpg")); // 读入文件
BufferedImage src2 = ImageIO.read(new File("c:/work/3.jpg")); // 读入文件
AnimatedGifEncoder e = new AnimatedGifEncoder();
e.setRepeat(0);
e.start("c:/work/laoma.gif");
e.setDelay(3000); // 1 frame per sec
e.addFrame(src);
e.setDelay(1000);
e.addFrame(src1);
e.setDelay(100);
e.addFrame(src2);
e.finish();
}catch(IOException e){
e.printStackTrace();
}
}
}
下面的例子来自:http://blog.csdn.net/ideas/archive/2006/08/25/1116198.aspx作者: ideas
1 多张jpg图合成gif动画
/** *//** * 把多张jpg图片合成一张 * @param pic String[] 多个jpg文件名 包含路径 * @param newPic String 生成的gif文件名 包含路径 */
private synchronized void jpgToGif(String pic[], String newPic) ...{ try ...{ AnimatedGifEncoder e = new AnimatedGifEncoder(); e.setRepeat(0); e.start(newPic); BufferedImage src[] = new BufferedImage[pic.length]; for (int i = 0; i < src.length; i++) ...{ e.setDelay(200); //设置播放的延迟时间 src[i] = ImageIO.read(new File(pic[i])); // 读入需要播放的jpg文件 e.addFrame(src[i]); //添加到帧中 } e.finish(); } catch (Exception e) ...{ System.out.println( "jpgToGif Failed:"); e.printStackTrace(); } }
2 gif动画分解成多张jpg
/** *//** * 把gif图片按帧拆分成jpg图片 * @param gifName String 小gif图片(路径+名称) * @param path String 生成小jpg图片的路径 * @return String[] 返回生成小jpg图片的名称 */ private synchronized String[] splitGif(String gifName,String path) ...{ try ...{ GifDecoder decoder = new GifDecoder(); decoder.read(gifName); int n = decoder.getFrameCount(); //得到frame的个数 String[] subPic = new String[n]; String tag = this.getTag(); for (int i = 0; i < n; i++) ...{ BufferedImage frame = decoder.getFrame(i); //得到帧 //int delay = decoder.getDelay(i); //得到延迟时间 //生成小的JPG文件 subPic[i] = path + String.value(i)+ ".jpg"; FileOutputStream out = new FileOutputStream(subPic[i]); ImageIO.write(frame, "jpeg", out); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(frame); //存盘 out.flush(); out.close(); } return subPic; } catch (Exception e) ...{ System.out.println( "splitGif Failed!"); e.printStackTrace(); return null; } }
3 根据提供的文字生成jpg图片
/** *//** * 根据提供的文字生成jpg图片 * @param s String 文字 * @param smallWidth int 每个字的宽度和高度是一样的 * @param bgcolor Color 背景色 * @param fontcolor Color 字色 * @param fontPath String 字体文件 * @param jpgname String jpg图片名 * @return */ private String createJpgByFont(String s, int smallWidth,Color bgcolor,Color fontcolor,String fontPath,String jpgname) ...{ try ...{ BufferedImage bimage = new BufferedImage(s.length()*smallWidth, smallWidth,BufferedImage.TYPE_INT_RGB); Graphics2D g = bimage.createGraphics(); g.setColor(bgcolor); //背景色 g.fillRect(0, 0, smallWidth, smallWidth); //画一个矩形 //去除锯齿(当设置的字体过大的时候,会出现锯齿) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); g.setColor(fontcolor); //字的颜色 File file = new File(fontPath); //字体文件 //根据字体文件所在位置,创建新的字体对象(此语句在jdk1.5下面才支持) Font font = Font.createFont(Font.TRUETYPE_FONT, file); //font.deriveFont(float f)复制当前 Font 对象并应用新设置字体的大小 g.setFont(font.deriveFont((float) smallWidth)); g.drawString(s,0, smallWidth); //在指定坐标除添加文字 g.dispose(); FileOutputStream out = new FileOutputStream(jpgname); //指定输出文件 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage); param.setQuality(50f, true); encoder.encode(bimage, param); //存盘 out.flush(); out.close(); } catch (Exception e) ...{ System.out.println( "createJpgByFont Failed!"); e.printStackTrace(); } }
4 多张小jpg图合成一张大JPG图,在这里对大图只作宽度限制,不做高度限制
/** *//** * 将多个小图片合成一张大jpg图 (小的jpg图片按照行列顺序平铺) * @param smallJPG ArrayList 一组小的jpg图片 * @param bigWidth int 大图宽度 * @param smallWidth int 单个文字生成的小图的宽度和高度是一致的 * @return */ private void createBigJPG(ArrayList smallJPG, int bigWidth, int smallHeigh,Color bgColor ,String picName) ...{ try ...{ if (bigWidth < smallWidth) //如果大图片的高度比小图片的高度还小 直接返回 return; int colCount = bigWidth / smallWidth; //每行放置的字数 int leftMargin = (int) ((bigWidth - colCount * smallWidth) / 2f); //左边距 int rowCount = smallJPG.size(); //小图行数 int setWidth = bigWidth; //每列中间不留空隙,只留左右边距 int setHeight = smallWidth * rowCount ; //按照大图片宽高绘制一个背景图片 BufferedImage bufImage = new BufferedImage(setWidth, setHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g = bufImage.createGraphics(); g.setColor(bgColor); //背景的颜色 g.fillRect(0, 0, setWidth, setHeight); int y = 0; //纵坐标 for (int i = 0; i < rowCount; i++) ...{ //遍历每行 ArrayList col = (ArrayList) (smallJPG.get(i)); int x = leftMargin; //横坐标 可能会出现左边距 for (int j = 0; j < col.size(); j++) ...{ String jpgname = (String) (col.get(j)); ImageIcon icon = new ImageIcon(jpgname); Image img = icon.getImage(); int imgWidth = img.getHeight(null); g.drawImage(img, x, y, null); x += imgWidth; } y += (smallWidth); } g.dispose(); FileOutputStream out = new FileOutputStream(picName); //指定输出文件 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); //设置文件格式 JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bufImage); //从图片缓冲中读取 param.setQuality(50f, true); encoder.encode(bufImage, param); //存盘 out.flush(); out.close(); } catch (Exception e) ...{ System.out.println( "createBigJPG Failed!"); e.printStackTrace(); } }
eucJP-ms
eucJP-ms
TOG/JVC
(オープン・グループ / 日本ベンダ協議会) CDE/Motif 技術検討 WG が定めたコードセット名です。UI-OSF共通日本語EUC にユーザー定義文字とIBM拡張文字、NEC特殊文字を追加した 日本語EUC (eucJP-open) と Unicode (UCS) との間のコード変換規則に Microsoft Windows NT 3.51 の式の変換規則を用いる場合に、このコードセット名を用います。
Unicode 経由で Windows-31J で使用できる全文字 (コードポイント) の相互変換が可能となるように変換規則が定められています。
変換規則
eucJP-ms の変換規則の概要は次の通りです。
- EUC コードセット0 (ASCII)
- ASCII (ISO/IEC 646 IRV) とみなして Unicode に変換する。
- EUC コードセット1 (JIS X 0208 + NEC特殊文字 + ユーザー定義文字)
- 1区~84区は Microsoft Windows NT 3.51 での 1区~84区の変換と同様の変換をする。
- 85区~94区 (ユーザー定義文字領域) は、U+E000~U+E3AB (私用領域) に変換する。
- EUC コードセット2 (JIS X 0201 片仮名)
- U+FF61~U+FF9F (HALFWIDTH KATKANA) に変換する。
- EUC コードセット3 (JIS X 0212 + JIS X 0208/0212 に無いIBM拡張文字 + ユーザー定義文字)
- JIS X 0212 補助漢字は、それぞれ対応する Unicode のコードポイントに変換する。
- 83区~84区 (JIS X 0208/0212 に無いIBM拡張文字) は、それぞれ対応する Unicode のコードポイントに変換する。
- 85区~94区 (ユーザー定義文字領域)は、U+E3AC~U+E757 (私用領域) に変換する。
TOG/JVC CDE/Motif 技術検討 WG の資料では、NEC特殊文字についての記述がありませんが、同WG の資料「Unicode とユーザ定義文字・ベンダ定義文字に関する問題点と解決策」では eucJP-ms について「Windows の動作するコンピュータとの間のデータ交換 に使われることを想定している」とあるので、それに必要な変換規則を補ってあります。
eucJP-ms の変換表は、このページの最後に掲げる「参考文献・資料等」の「オープン・グループ」の Web ページから入手可能です。
各文字セットの eucJP-ms でのコード割り当て
eucJP-ms での NEC特殊文字、IBM拡張文字、ユーザー定義文字のコード割り当てを簡単に説明します。
- NEC特殊文字 (13区)
Windows-31J で 13区に定義されている NEC特殊文字は、EUC コードセット 1 (JIS X 0208) の 13区にそのまま割り当てられています。
次の文字コード表の水色のコードポイントに割り当てられている文字は、JIS X 0208:1997 の 2区にも定義されている文字で、Unicode 経由で文字コードの変換を行うと、これらのコードポイントは、JIS のコードポイントに変換されます。また、灰色のコードポイントは、IBM特殊文字でも定義されています。重複符号化されている文字の変換については後で説明します。
- IBM拡張文字 (Windows-31J:115区~119区)
Windows-31J では、一部の記号文字を除いて89区~92区と115区~119区の両方でで重複して割り当てがなされていますが、eucJP-ms では、大文字のローマ数字を含む後者の文字セットが EUC コードセット3 に割り当てられています。詳細は次の通りです。
IBM拡張文字のうち、JIS X 0208, JIS X 0212 に対応する文字があるものについては、JIS のコードポイントを用います。
それ以外の文字については、コードセット3 の 84区94点から逆方向に割り当てられています。次の文字コード表に、その割り当てを示しておきます。灰色のコードポイントについては、NEC特殊文字の方にもあります。重複符号化されている文字の変換については後で説明します。
- ユーザー定義文字 (95区~114区)
Windows-31J のユーザー定義文字領域 95区~114区は、次の2個所に分割して割り当てられています。
- Windows31-J の 95区~104区
- EUC コードセット0 の 85区~94区
- Windows31-J の 105区~114区
- EUC コードセット3 の 85区~94区
重複符号化されている文字
TOG/JVC CDE/Motif 技術検討 WG が配っている eucJP-ms の変換表では表1の文字が重複符号化されています。
ほとんどの文字は、Windows での Windows-31J と Unicode との変換の規則をそのまま適用可能ですが、次の文字に関しては JIS X 0212 補助漢字の文字と重複符号化されているため検討が必要です。
- U+2116 NUMERO SIGN
- U+FF5E FULLWIDTH TILDE
U+FF5E FULLWIDTH TILDE は、本来であれば、JIS X 0212 の2区23点 (EUCでは 0x8FA2B7) に対応させるべきですが、マイクソロソフトの Windows では、 JIS X 0208 の 1区33点 (WAVE DASH, EUC では 0xA1C1) を U+FF5E FULLWIDTH TILDE と対応付けている為、JIS X 0212 と組み合わせて使う場合に問題が生じます。
eucJP-ms は、Windows の動作するコンピュータとの間のデータ交換 に使われることを想定しているため、Windows-31J のコードポイントが正しく変換できるようにする必要があります。その事から、U+FF5E FULLWIDTH TILDE は、JIS X 0208 の1区33点 (0xA1C1) と対応付けるのが妥当と思われます。U+2116 NUMERO SIGN に関しても Windows-31J との文字コード変換を優先されるのが妥当と思われます。
以上のことを踏まえて、eucJP-ms で重複符号化されている文字は次のように変換するのが妥当と思われます。
- Unicode → eucJP-ms の変換は、Unicode → Windows-31J と同じ規則を適用し表1 の○印の付いているコードポイントに変換する。
- eucJP-ms → Unicode の変換は、多対1 の変換とする。
文字 | Unicode | JIS X 0208 | NEC特殊文字 | JIS X 0212 | IBM拡張文字 | 文字名称(Unicode) |
---|---|---|---|---|---|---|
№(No.) | U+2116 | 0xADE2 ○ | 0x8FA2F1 | 0x8FF4AC | NUMERO SIGN | |
℡(TEL) | U+2121 | 0xADE4 ○ | 0x8FF4AD | TELEPHONE SIGN | ||
Ⅰ( I ) | U+2160 | 0xADB5 ○ | 0x8FF3FD | ROMAN NUMERAL ONE | ||
Ⅱ( II ) | U+2161 | 0xADB6 ○ | 0x8FF3FE | ROMAN NUMERAL TWO | ||
Ⅲ( III ) | U+2162 | 0xADB7 ○ | 0x8FF4A1 | ROMAN NUMERAL THREE | ||
Ⅳ( IV ) | U+2163 | 0xADB8 ○ | 0x8FF4A2 | ROMAN NUMERAL FOUR | ||
Ⅴ( V ) | U+2164 | 0xADB9 ○ | 0x8FF4A3 | ROMAN NUMERAL FIVE | ||
Ⅵ( VI ) | U+2165 | 0xADBA ○ | 0x8FF4A4 | ROMAN NUMERAL SIX | ||
Ⅶ( VII ) | U+2166 | 0xADBB ○ | 0x8FF4A5 | ROMAN NUMERAL SEVEN | ||
Ⅷ( VIII ) | U+2167 | 0xADBC ○ | 0x8FF4A6 | ROMAN NUMERAL EIGHT | ||
Ⅸ( IX ) | U+2168 | 0xADBD ○ | 0x8FF4A7 | ROMAN NUMERAL NINE | ||
Ⅹ( X ) | U+2169 | 0xADBE ○ | 0x8FF4A8 | ROMAN NUMERAL TEN | ||
√ | U+221A | 0xA2E5 ○ | 0xADF5 | SQUARE ROOT | ||
∠ | U+2220 | 0xA2DC ○ | 0xADF7 | ANGLE | ||
∩ | U+2229 | 0xA2C1 ○ | 0xADFB | INTERSECTION | ||
∪ | U+222A | 0xA2C0 ○ | 0xADFC | UNION | ||
∫ | U+222B | 0xA2E9 ○ | 0xADF2 | INTEGRAL | ||
∵ | U+2235 | 0xA2E8 ○ | 0xADFA | BECAUSE | ||
≒ | U+2252 | 0xA2E2 ○ | 0xADF0 | APPROXIMATELY EQUAL TO OR THE IMAGE OF | ||
≡ | U+2261 | 0xA2E1 ○ | 0xADF1 | IDENTICAL TO | ||
⊥ | U+22A5 | 0xA2DD ○ | 0xADF6 | UP TACK | ||
㈱((株)) | U+3231 | 0xADEA ○ | 0x8FF4AB | PARENTHESIZED IDEOGRAPH STOCK | ||
~ | U+FF5E | 0xA1C1 ○ | 0x8FA2B7 | FULLWIDTH TILDE |
eucJP-ms を使用する上での注意点
以下のような問題があるため、eucJP-ms は、Windows-31J との相互変換のみに用い、なおかつ使用する文字は、Windows-31J と同等の文字に限定して使うのが望ましいと思われます。
Windows-31J と共通する注意点
次の文字が、Unicode への変換が Unicodeコンソーシアムの JIS0208.TXT や、JIS X 0208:1997 の文字名称を元にした変換と異なるので注意が必要です。
文字 EUC eucJP-ms JIS0208.TXT JIS X 0208:1997 Unicode Unicode Unicode ― 0xA1BD U+2015 U+2015 U+2014 EM DASH ~ 0xA1C1 U+FF5E U+301C U+301C WAVE DASH ∥ 0xA1C2 U+2225 U+2016 U+2016 DOUBLE VERTICAL LINE - 0xA1DD U+FF0D U+2212 U+2212 MINUS SIGN ¢ 0xA1F1 U+FFE0 U+00A2 U+00A2 CENT SIGN £ 0xA1F2 U+2225 U+00A3 U+00A3 POUND SIGN ¬ 0xA2CC U+FFE2 U+00AC U+00AC NOT SIGN
JIS X 0212 に関する注意点
Windows-31J に変換する時には、IBM拡張文字にある文字のみが変換可能です。
JIS X 0212 の次の区-点 位置の文字は、eucJP-ms → Unicode → eucJP-ms の変換で、次のように変換されます。
JIS X 0212 区-点 eucJP-ms → Unicode → eucJP-ms 2-23 (TILDE) 0x8FA2B7 → U+FF5E (FULLWIDTH TILDE) → 0xA1C1 (~) 2-81 (NUMERO SIGN) 0x8FA2F1 → U+2116 (NUMERO SIGN) → 0xADE2 (No.)
Unicode ⇔ UTF-8
/**********************************************************************
*
* Unicode ⇔ UTF-8
*
* Copyright (c) 2005 AOK
*
**********************************************************************/
function _to_utf8(s) {
var c, d = "";
for (var i = 0; i < s.length; i++) {
c = s.charCodeAt(i);
if (c <= 0x7f) {
d += s.charAt(i);
} else if (c >= 0x80 && c <= 0x7ff) {
d += String.fromCharCode(((c >> 6) & 0x1f) 0xc0);
d += String.fromCharCode((c & 0x3f) 0x80);
} else {
d += String.fromCharCode((c >> 12) 0xe0);
d += String.fromCharCode(((c >> 6) & 0x3f) 0x80);
d += String.fromCharCode((c & 0x3f) 0x80);
}
}
return d;
}
function _from_utf8(s) {
var c, d = "", flag = 0, tmp;
for (var i = 0; i < s.length; i++) {
c = s.charCodeAt(i);
if (flag == 0) {
if ((c & 0xe0) == 0xe0) {
flag = 2;
tmp = (c & 0x0f) << 12;
} else if ((c & 0xc0) == 0xc0) {
flag = 1;
tmp = (c & 0x1f) << 6;
} else if ((c & 0x80) == 0) {
d += s.charAt(i);
} else {
flag = 0;
}
} else if (flag == 1) {
flag = 0;
d += String.fromCharCode(tmp (c & 0x3f));
} else if (flag == 2) {
flag = 3;
tmp = (c & 0x3f) << 6;
} else if (flag == 3) {
flag = 0;
d += String.fromCharCode(tmp (c & 0x3f));
} else {
flag = 0;
}
}
return d;
}