by Li y.c.
一、內容簡介
本文介紹一種簡單的圖片加/解密算法,算法的基本原理十分簡單,即逐個(逐行、逐列)地獲取圖片的像素點顏色值,對其進行一些簡單的算數運算操作進行加密,解密過程則相應地為加密運算的逆運算。
二、圖片表示基礎
在計算機中,圖片(我們使用.jpg文件作為示例)在內存中是使用RGB數組進行存儲,舉例:
以上圖片中,每一個像素點用一個rgb值表示,一般為6位16進制數,例如0x123456,這里0x12表示紅度(RED)值,0x34表示綠度(GREEN)值,0x56表示藍度(BLUE)值。注意到,兩位16進制數的取值范圍為0~255(0x00到0xFF)。
三、R/G/B值的獲取
假如我們知道當前像素點的rgb值為0x123456,如何從中獲取到分離的r/g/b值呢?通過簡單的位運算即可。如以下java代碼:
public class RGBTest {public static void main(String[] args) {String format1 = String.format("%x", (0x123456 >> 16)); // 獲取red值(前兩位)String format2 = String.format("%x", (0x123456 >> 8) & 0xFF); // 獲取green值(中間兩位)String format3 = String.format("%x", (0x123456) & 0xFF); // 獲取blue值(末兩位)String format = String.format("%x", (0x123456) & 0xFFFFFF); // 不做改變System.out.println(format1);System.out.println(format2);System.out.println(format3);System.out.println(format);}
}
運行結果正是我們想要的:
四、獲取整張圖片的RGB數組
有了以上的基礎,我們就可以將整張圖片存儲為一個RGB表示的數組,為之后的加/解密操作做基礎。使用如下的Java代碼:
public List<Integer> getRGB(BufferedImage image, int x, int y) {List<Integer> rgb = new ArrayList<Integer>();if (image != null && x <= image.getWidth() && y <= image.getHeight()) {for (int h = 0; h < y; h++) {for (int w = 0; w < x; w++) {//獲得w,h坐標的顏色int pixel = image.getRGB(w, h);rgb.add(pixel);}}}return rgb;}
五、加密函數
我們使用簡單的加密操作,即把圖片的R/G/B值同時加50后模256(防止值溢出造成噪點【可以想見,若某一通道出現進位,后果是災難性的】):
// 加密函數public static void Encrypt(Integer[] rgb, int width, int height) {// 輸出文件名File file = new File("image_out.jpg");BufferedImage bi = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);Graphics2D g2 = (Graphics2D) bi.getGraphics();for (int h = 0; h < height; h++) {for (int w = 0; w < width; w++) {int color = rgb[w + width * h];int red = color >> 16;int green = (color >> 8) & 0xFF;int blue = color & 0xFF;int red_ = (red + 50) % 256;int green_ = (green + 50) % 256;int blue_ = (blue + 50) % 256;Color c = new Color(red_ << 16 | green_ << 8 | blue_);g2.setColor(c);g2.drawLine(w, h, w + 1, h + 1);}}try {ImageIO.write(bi, "jpg", file);} catch (IOException e) {e.printStackTrace();}}
看看加密效果:(以下代碼位于主函數中)
// 加密部分:【image_1_1.jpg】---【image_out.jpg】Image_Encrypt r = new Image_Encrypt();File f = new File("image_1_1.jpg");BufferedImage bi = ImageIO.read(f);int width = bi.getWidth();int height = bi.getHeight();List<Integer> l = null;Integer[] rbg = new Integer[width * height];l = r.getRGB(bi, width, height);
// 查看rgb值:
// System.out.print(l);for (int i = 0; i < width * height; i++) {rbg[i] = l.get(i);}Encrypt(rbg, width, height);
加密后的圖像:
六、解密函數
解密函數應為加密函數的逆運算,考慮到邊緣條件,代碼如下:
// 解密函數public static void Decrypt(Integer[] rgb, int width, int height) {// 輸出文件名File file = new File("image_out_de.jpg");BufferedImage bi = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);Graphics2D g2 = (Graphics2D) bi.getGraphics();for (int h = 0; h < height; h++) {for (int w = 0; w < width; w++) {int color = rgb[w + width * h];int red = color >> 16;int green = (color >> 8) & 0xFF;int blue = color & 0xFF;int red_;if (red == 255){red_ = 255;}else{red_ = (red - 50 + 255) % 255;}int green_;if (green == 255){green_ = 255;}else{green_ = (green - 50 + 255) % 255;}int blue_;if (blue == 255){blue_ = 255;}else{blue_ = (blue - 50 + 255) % 255;}Color c = new Color(red_ << 16 | green_ << 8 | blue_);g2.setColor(c);g2.drawLine(w, h, w + 1, h + 1);}}try {ImageIO.write(bi, "jpg", file);} catch (IOException e) {e.printStackTrace();}}
解密后的圖像卻是這樣的:
推測是由于邊緣條件造成的,修改代碼中……
【debug】
我們寫一個測試類,看看從0到255的值里面,是否有不滿足該逆運算關系的:
public class Test {public static void main(String[] args){for (int i = 0;i <= 255;i ++){int j = (i + 50) % 256;int j_ = (j - 50 + 256) % 256;if (i != j_){System.out.print("errr");}}}
}
輸出如下:
【沒有報錯】……??
基準測試
加/解密均不做任何操作,直接由三通道的值拼湊出rgb數組:
加密函數
// 加密函數public static void Encrypt(Integer[] rgb, int width, int height) {// 輸出文件名File file = new File("image_out.jpg");BufferedImage bi = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);Graphics2D g2 = (Graphics2D) bi.getGraphics();for (int h = 0; h < height; h++) {for (int w = 0; w < width; w++) {int color = rgb[w + width * h];int red = color >> 16;int green = (color >> 8) & 0xFF;int blue = color & 0xFF;// 基準測試int red_ = red;int green_ = green;int blue_ = blue;// int red_ = (red + 50) % 256;
// int green_ = (green + 50) % 256;
// int blue_ = (blue + 50) % 256;Color c = new Color(red_ << 16 | green_ << 8 | blue_);g2.setColor(c);g2.drawLine(w, h, w + 1, h + 1);}}try {ImageIO.write(bi, "jpg", file);} catch (IOException e) {e.printStackTrace();}}
解密函數
// 解密函數public static void Decrypt(Integer[] rgb, int width, int height) {// 輸出文件名File file = new File("image_out_de.jpg");BufferedImage bi = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);Graphics2D g2 = (Graphics2D) bi.getGraphics();for (int h = 0; h < height; h++) {for (int w = 0; w < width; w++) {int color = rgb[w + width * h];int red = color >> 16;int green = (color >> 8) & 0xFF;int blue = color & 0xFF;// 基準測試int red_ = red;int green_ = green;int blue_ = blue;
// int red_;
// if (red == 255){
// red_ = 255;
// }
// else{
// red_ = (red - 50 + 256) % 256;
// }// int green_;
// if (green == 255){
// green_ = 255;
// }
// else{
// green_ = (green - 50 + 256) % 256;
// }// int blue_;
// if (blue == 255){
// blue_ = 255;
// }
// else{
// blue_ = (blue - 50 + 256) % 256;
// }Color c = new Color(red_ << 16 | green_ << 8 | blue_);g2.setColor(c);g2.drawLine(w, h, w + 1, h + 1);}}try {ImageIO.write(bi, "jpg", file);} catch (IOException e) {e.printStackTrace();}}