手作り画像圧縮ソフト Handmade image compression software
Processingで作った手作り画像圧縮ソフトです。
PNG、ZIF、JPEG、BMP形式の画像を圧縮することができます。
拡大すると、ドット絵に見えます。
拡大せずに見ると、何も変わっていないように見えますが、中間色で見えるため、目の錯覚で変わっていないように見えるのです。
256色しか使わない画像に変換します。BMPならば、3分の1のサイズになります。
Windows32ビット用、64ビット用、Mac用を作りました。
It is handmade image compression software made with “Processing”.
PNG, ZIF, JPEG, BMP format images can be compressed.
When you magnify, it looks like a dot picture.
Looking without enlargement, nothing seems to have changed, but it looks like a neutral color, so it looks like it has not changed with the illusion of the eye.
It converts to an image that uses only 256 colors. If BMP, it will be one-third the size.
I made Windows 32 bit, 64 bit, Mac.
Download zip file here ↓
実行後の拡大写真は、こちら↓Enlarged photograph after execution, here ↓
これが、拡大前の写真です。⇩ This is a picture before enlargement.
使用画像は、こちら↓Used images, here ↓
ソースコードは、こちら↓Source code is here
Mac↓
PFont font; int mode = 0; PImage ins; PImage bg; void Text(String t, float x, float y) { fill(0, 3); for (float i = -4; i < 5; i += 1) { for (float f = -4; f < 5; f += 1) { text(t, x+i, y+f); } } fill(255); text(t, x, y); } String passa; boolean one; void setup() { ins = loadImage("data/ins.png"); bg = loadImage("data/bg.png"); size(800, 480); dragDropFile(); surface.setTitle("圧縮"); } int en = 0; boolean cc; PImage img; void draw() { if (mode == 1) { background(100); if (bg != null)image(bg, 0, 0); font = createFont("MS PGothic", 32); if (font == null) { font = createFont("Osaka", 32); println("Osaka"); } if (font != null) { textFont (font); textSize(32); println("フォントロード成功"); String noload = "画像がまだロードされていません"; String noload2 = "このウィンドウにドラック&ドロップしてください。"; Text(noload, 320-(textWidth(noload)/2), 230); Text(noload2, 320-(textWidth(noload2)/2), 270); } mode = 2; } if (mode == 0) { if (ins != null)image(ins, 0, 0); mode = 1; } ; ; if (pass != null) { background(100); if (bg != null)image(bg, 0, 0); println("ドロップされました "+pass); en = 0; println(); if (pass.substring(pass.length()-3, pass.length()).equals("kig")) { println("自作のやつです"); en = 1; } if (en == 0) { img = loadImage(pass); } else { img = ucon(loadBytes(pass)); } if (img != null) { float xs = img.width; float ys = img.height; int xss = int(xs); int yss = int(ys); float w = 1; if (xs > ys) { w = 640/xs; } else { w = 480/ys; } xs *= w; ys *= w; String str = xss+" x "+yss; textSize(32); Text(str, (640+80)-(textWidth(str)/2), 30); textSize(16); str = "予測サイズ"+nf(((float)filesize(img)/1024/1024), 2, 2)+"MB"; if (en == 0)Text(str, (640+80)-(textWidth(str)/2), 60); println("ロードできました!"); println("拡大率は"+nf(w, 2, 2)+"%でした"); image(img, 320-(xs/2), 240-(ys/2), xs, ys); textSize(64); str = "実行"; if (en == 1)str = "保存"; Text(str, (640+80)-(textWidth(str)/2), 460); } else { println("このファイルは壊れています"); } passa = pass; pass = null; } if (mouseX >= 640) { if (mouseY >= 480-80) { if (mousePressed && !cc) { one = true; cc = true; } else { cc = false; } } } if (one) { String str = "OK"; Text(str, (640+80)-(textWidth(str)/2), 460-64); if (en == 0) { saveBytes(passa+".kig", con(img)); println(passa+".kig"+" に保存されました"); } if (en == 1) { img.save(passa+".png"); println(passa+".png"+" に保存されました"); } one = false; } }
Windows64bit
import processing.core.*; import processing.data.*; import processing.event.*; import processing.opengl.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import java.io.File; import java.io.IOException; import java.awt.Component; import java.util.List; import java.util.HashMap; import java.util.ArrayList; import java.io.File; import java.io.BufferedReader; import java.io.PrintWriter; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; public class ASYUKU extends PApplet { PFont font; int mode = 0; PImage ins; PImage bg; public void Text(String t, float x, float y) { fill(0, 3); for (float i = -4; i < 5; i += 1) { for (float f = -4; f < 5; f += 1) { text(t, x+i, y+f); } } fill(255); text(t, x, y); } String passa; boolean one; public void setup() { ins = loadImage("data/ins.png"); bg = loadImage("data/bg.png"); dragDropFile(); surface.setTitle("圧縮"); } int en = 0; boolean cc; PImage img; public void draw() { if (mode == 1) { background(100); if (bg != null)image(bg, 0, 0); font = createFont("MS PGothic", 32); if (font == null) { font = createFont("Osaka", 32); println("Osaka"); } if (font != null) { textFont (font); textSize(32); println("フォントロード成功"); String noload = "画像がまだロードされていません"; String noload2 = "このウィンドウにドラック&ドロップしてください。"; Text(noload, 320-(textWidth(noload)/2), 230); Text(noload2, 320-(textWidth(noload2)/2), 270); } mode = 2; } if (mode == 0) { if (ins != null)image(ins, 0, 0); mode = 1; } ; ; if (pass != null) { background(100); if (bg != null)image(bg, 0, 0); println("ドロップされました "+pass); en = 0; println(); if (pass.substring(pass.length()-3, pass.length()).equals("kig")) { println("自作のやつです"); en = 1; } if (en == 0) { img = loadImage(pass); } else { img = ucon(loadBytes(pass)); } if (img != null) { float xs = img.width; float ys = img.height; int xss = PApplet.parseInt(xs); int yss = PApplet.parseInt(ys); float w = 1; if (xs > ys) { w = 640/xs; } else { w = 480/ys; } xs *= w; ys *= w; String str = xss+" x "+yss; textSize(32); Text(str, (640+80)-(textWidth(str)/2), 30); textSize(16); str = "予測サイズ"+nf(((float)filesize(img)/1024/1024), 2, 2)+"MB"; if (en == 0)Text(str, (640+80)-(textWidth(str)/2), 60); println("ロードできました!"); println("拡大率は"+nf(w, 2, 2)+"%でした"); image(img, 320-(xs/2), 240-(ys/2), xs, ys); textSize(64); str = "実行"; if (en == 1)str = "保存"; Text(str, (640+80)-(textWidth(str)/2), 460); } else { println("このファイルは壊れています"); } passa = pass; pass = null; } if (mouseX >= 640) { if (mouseY >= 480-80) { if (mousePressed && !cc) { one = true; cc = true; } else { cc = false; } } } if (one) { String str = "OK"; Text(str, (640+80)-(textWidth(str)/2), 460-64); if (en == 0) { saveBytes(passa+".kig", con(img)); println(passa+".kig"+" に保存されました"); } if (en == 1) { img.save(passa+".png"); println(passa+".png"+" に保存されました"); } one = false; } } public int filesize(PImage img) { int bh = (img.width*img.height)+4; return bh; } public byte[] con(PImage img) { int bh = 0; bh = (img.width*img.height)+4; byte[] bytes = new byte[bh]; char xs = PApplet.parseChar(img.width); char ys = PApplet.parseChar(img.height); println("変換やりまーす"); println("画像サイズ:"+xs+"x"+ys); //上位 8bit を送出 byte up = PApplet.parseByte(xs >> 8); bytes[0] = up; byte down = PApplet.parseByte(xs & 255); bytes[1] = down; ; up = PApplet.parseByte(ys >> 8); bytes[2] = up; down = PApplet.parseByte(ys & 255); bytes[3] = down; ; int f = 0; boolean ffA = false; for (int y = 0; y < ys; y++) { ffA = !ffA; boolean ffa = ffA; for (int x = 0; x < xs; x++) { int F = -8; if(ffa)F = 8; int R = PApplet.parseInt(( red(img.get(x, y)) +F)/32 ); int G = PApplet.parseInt(( green(img.get(x, y))+F)/32 ); int B = PApplet.parseInt(( blue(img.get(x, y) )+F)/64 ); if(R > 7)R = 7; if(G > 7)G = 7; if(B > 3)B = 3; if(R < 0)R = 0; if(G < 0)G = 0; if(B < 0)B = 0; String r = binary(R , 3); String g = binary(G , 3); String b = binary(B , 2); String rgb = r+g+b; byte in = PApplet.parseByte(unbinary(rgb)); bytes[4+f] = in; //println(r,g,b); f++; ffa = !ffa; } } return bytes; } ; public PImage ucon(byte[] img) { PImage out = null; PGraphics pg = null; if (img != null) { int mask = 0b10000000; for (int i = 0; i < img.length; i++) { img[i] ^= mask; } int xs = ((img[0]+128)*256)+(img[1]+128); int ys = ((img[2]+128)*256)+(img[3]+128); println(xs, ys); pg = createGraphics(xs, ys); pg.beginDraw(); pg.loadPixels(); for (int i = 0; i < pg.pixels.length; i++) { String k = binary(PApplet.parseInt(img[i+4]+128), 8); String R = k.substring(0, 3); String G = k.substring(3, 6); String B = k.substring(6, 8); float r = unbinary(R)*36.5714285f; float g = unbinary(G)*36.5714285f; float b = unbinary(B)*85.3333333f; //r = 255-r; //g = 255-g; //b = 255-b; //println(r, g, b); pg.pixels[i] = color(r, g, b, 256); } pg.updatePixels(); pg.endDraw(); //pg.save(pass+".png"); } out = pg.get(); return out; } String pass = null; DropTarget dropTarget; Component component; public void dragDropFile() { component = (Component)this.surface.getNative(); dropTarget = new DropTarget(component, new DropTargetListener() { public void dragEnter(DropTargetDragEvent dtde) { } public void dragOver(DropTargetDragEvent dtde) { } public void dropActionChanged(DropTargetDragEvent dtde) { } public void dragExit(DropTargetEvent dte) { } public void drop(DropTargetDropEvent dtde) { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); Transferable trans = dtde.getTransferable(); List<File> fileNameList = null; if (trans.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { try { fileNameList = (List<File>) trans.getTransferData(DataFlavor.javaFileListFlavor); } catch (UnsupportedFlavorException ex) { println(ex); } catch (IOException ex) { println(ex); } } if (fileNameList == null) return; for (File f : fileNameList) { println(f.getAbsolutePath()); pass = f.getAbsolutePath(); } } } ); } public void settings() { size(800, 480); } static public void main(String[] passedArgs) { String[] appletArgs = new String[] { "ASYUKU" }; if (passedArgs != null) { PApplet.main(concat(appletArgs, passedArgs)); } else { PApplet.main(appletArgs); } } }
Windows32bit↓
import processing.core.*; import processing.data.*; import processing.event.*; import processing.opengl.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import java.io.File; import java.io.IOException; import java.awt.Component; import java.util.List; import java.util.HashMap; import java.util.ArrayList; import java.io.File; import java.io.BufferedReader; import java.io.PrintWriter; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; public class ASYUKU extends PApplet { PFont font; int mode = 0; PImage ins; PImage bg; public void Text(String t, float x, float y) { fill(0, 3); for (float i = -4; i < 5; i += 1) { for (float f = -4; f < 5; f += 1) { text(t, x+i, y+f); } } fill(255); text(t, x, y); } String passa; boolean one; public void setup() { ins = loadImage("data/ins.png"); bg = loadImage("data/bg.png"); dragDropFile(); surface.setTitle("圧縮"); } int en = 0; boolean cc; PImage img; public void draw() { if (mode == 1) { background(100); if (bg != null)image(bg, 0, 0); font = createFont("MS PGothic", 32); if (font == null) { font = createFont("Osaka", 32); println("Osaka"); } if (font != null) { textFont (font); textSize(32); println("フォントロード成功"); String noload = "画像がまだロードされていません"; String noload2 = "このウィンドウにドラック&ドロップしてください。"; Text(noload, 320-(textWidth(noload)/2), 230); Text(noload2, 320-(textWidth(noload2)/2), 270); } mode = 2; } if (mode == 0) { if (ins != null)image(ins, 0, 0); mode = 1; } ; ; if (pass != null) { background(100); if (bg != null)image(bg, 0, 0); println("ドロップされました "+pass); en = 0; println(); if (pass.substring(pass.length()-3, pass.length()).equals("kig")) { println("自作のやつです"); en = 1; } if (en == 0) { img = loadImage(pass); } else { img = ucon(loadBytes(pass)); } if (img != null) { float xs = img.width; float ys = img.height; int xss = PApplet.parseInt(xs); int yss = PApplet.parseInt(ys); float w = 1; if (xs > ys) { w = 640/xs; } else { w = 480/ys; } xs *= w; ys *= w; String str = xss+" x "+yss; textSize(32); Text(str, (640+80)-(textWidth(str)/2), 30); textSize(16); str = "予測サイズ"+nf(((float)filesize(img)/1024/1024), 2, 2)+"MB"; if (en == 0)Text(str, (640+80)-(textWidth(str)/2), 60); println("ロードできました!"); println("拡大率は"+nf(w, 2, 2)+"%でした"); image(img, 320-(xs/2), 240-(ys/2), xs, ys); textSize(64); str = "実行"; if (en == 1)str = "保存"; Text(str, (640+80)-(textWidth(str)/2), 460); } else { println("このファイルは壊れています"); } passa = pass; pass = null; } if (mouseX >= 640) { if (mouseY >= 480-80) { if (mousePressed && !cc) { one = true; cc = true; } else { cc = false; } } } if (one) { String str = "OK"; Text(str, (640+80)-(textWidth(str)/2), 460-64); if (en == 0) { saveBytes(passa+".kig", con(img)); println(passa+".kig"+" に保存されました"); } if (en == 1) { img.save(passa+".png"); println(passa+".png"+" に保存されました"); } one = false; } } public int filesize(PImage img) { int bh = (img.width*img.height)+4; return bh; } public byte[] con(PImage img) { int bh = 0; bh = (img.width*img.height)+4; byte[] bytes = new byte[bh]; char xs = PApplet.parseChar(img.width); char ys = PApplet.parseChar(img.height); println("変換やりまーす"); println("画像サイズ:"+xs+"x"+ys); //上位 8bit を送出 byte up = PApplet.parseByte(xs >> 8); bytes[0] = up; byte down = PApplet.parseByte(xs & 255); bytes[1] = down; ; up = PApplet.parseByte(ys >> 8); bytes[2] = up; down = PApplet.parseByte(ys & 255); bytes[3] = down; ; int f = 0; boolean ffA = false; for (int y = 0; y < ys; y++) { ffA = !ffA; boolean ffa = ffA; for (int x = 0; x < xs; x++) { int F = -8; if(ffa)F = 8; int R = PApplet.parseInt(( red(img.get(x, y)) +F)/32 ); int G = PApplet.parseInt(( green(img.get(x, y))+F)/32 ); int B = PApplet.parseInt(( blue(img.get(x, y) )+F)/64 ); if(R > 7)R = 7; if(G > 7)G = 7; if(B > 3)B = 3; if(R < 0)R = 0; if(G < 0)G = 0; if(B < 0)B = 0; String r = binary(R , 3); String g = binary(G , 3); String b = binary(B , 2); String rgb = r+g+b; byte in = PApplet.parseByte(unbinary(rgb)); bytes[4+f] = in; //println(r,g,b); f++; ffa = !ffa; } } return bytes; } ; public PImage ucon(byte[] img) { PImage out = null; PGraphics pg = null; if (img != null) { int mask = 0b10000000; for (int i = 0; i < img.length; i++) { img[i] ^= mask; } int xs = ((img[0]+128)*256)+(img[1]+128); int ys = ((img[2]+128)*256)+(img[3]+128); println(xs, ys); pg = createGraphics(xs, ys); pg.beginDraw(); pg.loadPixels(); for (int i = 0; i < pg.pixels.length; i++) { String k = binary(PApplet.parseInt(img[i+4]+128), 8); String R = k.substring(0, 3); String G = k.substring(3, 6); String B = k.substring(6, 8); float r = unbinary(R)*36.5714285f; float g = unbinary(G)*36.5714285f; float b = unbinary(B)*85.3333333f; //r = 255-r; //g = 255-g; //b = 255-b; //println(r, g, b); pg.pixels[i] = color(r, g, b, 256); } pg.updatePixels(); pg.endDraw(); //pg.save(pass+".png"); } out = pg.get(); return out; } String pass = null; DropTarget dropTarget; Component component; public void dragDropFile() { component = (Component)this.surface.getNative(); dropTarget = new DropTarget(component, new DropTargetListener() { public void dragEnter(DropTargetDragEvent dtde) { } public void dragOver(DropTargetDragEvent dtde) { } public void dropActionChanged(DropTargetDragEvent dtde) { } public void dragExit(DropTargetEvent dte) { } public void drop(DropTargetDropEvent dtde) { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); Transferable trans = dtde.getTransferable(); List<File> fileNameList = null; if (trans.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { try { fileNameList = (List<File>) trans.getTransferData(DataFlavor.javaFileListFlavor); } catch (UnsupportedFlavorException ex) { println(ex); } catch (IOException ex) { println(ex); } } if (fileNameList == null) return; for (File f : fileNameList) { println(f.getAbsolutePath()); pass = f.getAbsolutePath(); } } } ); } public void settings() { size(800, 480); } static public void main(String[] passedArgs) { String[] appletArgs = new String[] { "ASYUKU" }; if (passedArgs != null) { PApplet.main(concat(appletArgs, passedArgs)); } else { PApplet.main(appletArgs); } } }