首先看一下效果,左邊是一張黑白的文字圖像,右邊是混合以後的數字水印效果java

實現原理算法
主要是利用位圖塊遷移算法,首先提取文字骨架,寬度爲一個像素。而後將提取的骨架,按ide
照必定的像素值填充到目標圖像中便可。關於位圖塊遷移算法說明請看這裏:測試
http://en.wikipedia.org/wiki/Bit_blitthis
程序思路:url
1. 首先建立兩張白板的單色位圖,讀入黑白文字圖片,spa
2. 移動一個像素位開始讀取文字圖片中的像素,將每一個對應像素與白板單色圖片疊加,直.net
至黑白文字圖片徹底copy到單色白板中。orm
3. 重複上面操做,惟一不一樣的,將白板像素移動一個像素爲,之後開始填充blog
4. 分別將兩張位圖塊遷移圖片與原黑白文字圖片像素完成一個或操做,則獲得左上和右下
的文字骨架。
5. 將兩個文字骨架的像素填充到目標彩色圖片中,即獲得軋花效果的圖片
根據輸入參數不一樣,還可獲得雕刻效果圖片。
關鍵代碼解釋:
實現位圖塊遷移算法的代碼以下:
// one pixel transfer
for(int row=1; row<height; row++) {
int ta = 0, tr = 0, tg = 0, tb = 0;
for(int col=1; col<width; col++) {
index = row * width + col;
index2 = (row-1) * width + (col-1);
ta = (inPixels[isTop?index:index2] >> 24) & 0xff;
tr = (inPixels[isTop?index:index2] >> 16) & 0xff;
tg = (inPixels[isTop?index:index2] >> 8) & 0xff;
tb = inPixels[isTop?index:index2] & 0xff;
outPixels[isTop?index2:index] = (ta << 24) | (tr<< 16) | (tg << 8) | tb;
}
}
布爾變量isTop決定是否填充單色白板位移(Offset)是零仍是一。
獲取一個像素寬度骨架的方法爲processonePixelWidth()主要是利用文字圖片是一個二值圖像,
從而remove掉多餘的像素。
混合軋花的方法爲embossImage()主要是簡單的像素填充,布爾變量主要是用來控制是凹軋花
仍是凸軋花效果。全部對文字圖像的處理和軋花效果的處理封裝在BitBltFilter一個類中.
程序效果以下:

位圖塊位移算法實現徹底源代碼以下:
- package com.gloomyfish.zoom.study;
-
- import java.awt.image.BufferedImage;
-
- import com.process.blur.study.AbstractBufferedImageOp;
-
- public class BitBltFilter extends AbstractBufferedImageOp {
-
-
- private boolean isTop = true;
-
-
-
-
-
-
- public void setTop(boolean isTop) {
- this.isTop = isTop;
- }
-
-
-
-
-
-
-
- public void emboss(BufferedImage textImage, BufferedImage targetImage) {
-
- BufferedImage topImage = filter(textImage, null);
- setTop(false);
- BufferedImage buttomImage = filter(textImage, null);
-
- int width = textImage.getWidth();
- int height = textImage.getHeight();
-
- int[] inPixels = new int[width*height];
- int[] outPixels = new int[width*height];
- getRGB( textImage, 0, 0, width, height, inPixels );
- getRGB( topImage, 0, 0, width, height, outPixels );
- processonePixelWidth(width, height, inPixels, outPixels, topImage);
- getRGB( buttomImage, 0, 0, width, height, outPixels );
- processonePixelWidth(width, height, inPixels, outPixels, buttomImage);
-
-
- embossImage(topImage, targetImage, true);
- embossImage(buttomImage, targetImage, false);
- }
-
- @Override
- public BufferedImage filter(BufferedImage src, BufferedImage dest) {
- int width = src.getWidth();
- int height = src.getHeight();
-
- if ( dest == null )
- dest = createCompatibleDestImage(src, null);
-
- int[] inPixels = new int[width*height];
- int[] outPixels = new int[width*height];
- getRGB( src, 0, 0, width, height, inPixels );
- int index = 0;
- int index2 = 0;
-
- for(int row=0; row<height; row++) {
- for(int col=0; col<width; col++) {
- index = row * width + col;
- outPixels[index] = (255 << 24) | (255 << 16) | (255 << 8) | 255;
- }
- }
-
-
- for(int row=1; row<height; row++) {
- int ta = 0, tr = 0, tg = 0, tb = 0;
- for(int col=1; col<width; col++) {
- index = row * width + col;
- index2 = (row-1) * width + (col-1);
- ta = (inPixels[isTop?index:index2] >> 24) & 0xff;
- tr = (inPixels[isTop?index:index2] >> 16) & 0xff;
- tg = (inPixels[isTop?index:index2] >> 8) & 0xff;
- tb = inPixels[isTop?index:index2] & 0xff;
- outPixels[isTop?index2:index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
- }
- }
- setRGB( dest, 0, 0, width, height, outPixels );
- return dest;
- }
-
-
-
-
-
-
-
-
-
- private void processonePixelWidth(int width, int height, int[] inPixels, int[] outPixels, BufferedImage destImage) {
-
- int index = 0;
- for(int row=0; row<height; row++) {
- int ta = 0, tr = 0, tg = 0, tb = 0;
- int ta2 =0, tr2 = 0, tg2 = 0, tb2 = 0;
- for(int col=0; col<width; col++) {
- index = row * width + col;
- ta = (inPixels[index] >> 24) & 0xff;
- tr = (inPixels[index] >> 16) & 0xff;
- tg = (inPixels[index] >> 8) & 0xff;
- tb = inPixels[index] & 0xff;
-
- ta2 = (outPixels[index] >> 24) & 0xff;
- tr2 = (outPixels[index] >> 16) & 0xff;
- tg2 = (outPixels[index] >> 8) & 0xff;
- tb2 = outPixels[index] & 0xff;
-
- if(tr2 == tr && tg == tg2 && tb == tb2) {
- outPixels[index] = (255 << 24) | (255 << 16) | (255 << 8) | 255;
- } else {
- if(tr2 < 5 && tg2 < 5 && tb2 < 5) {
- outPixels[index] = (ta2 << 24) | (tr2 << 16) | (tg2 << 8) | tb2;
- } else {
- outPixels[index] = (255 << 24) | (255 << 16) | (255 << 8) | 255;
- }
- }
- }
- }
- setRGB( destImage, 0, 0, width, height, outPixels );
- }
-
-
-
-
-
-
-
- private void embossImage(BufferedImage src, BufferedImage dest, boolean colorInverse)
- {
- int width = src.getWidth();
- int height = src.getHeight();
- int dw = dest.getWidth();
- int dh = dest.getHeight();
-
- int[] sinPixels = new int[width*height];
- int[] dinPixels = new int[dw*dh];
- src.getRGB( 0, 0, width, height, sinPixels, 0, width );
- dest.getRGB( 0, 0, dw, dh, dinPixels, 0, dw );
- int index = 0;
- int index2 = 0;
- for ( int y = 0; y < height; y++ ) {
- for ( int x = 0; x < width; x++ ) {
- index = y * width + x;
- int srgb = sinPixels[index];
- int r1 = (srgb >> 16) & 0xff;
- int g1 = (srgb >> 8) & 0xff;
- int b1 = srgb & 0xff;
- if(r1 > 200 || g1 >=200 || b1 >=200) {
- continue;
- }
- index2 = y * dw + x;
- if(colorInverse) {
- r1 = 255 - r1;
- g1 = 255 - g1;
- b1 = 255 - b1;
- }
- dinPixels[index2] = (255 << 24) | (r1 << 16) | (g1 << 8) | b1;
- }
- }
- dest.setRGB( 0, 0, dw, dh, dinPixels, 0, dw );
- }
- }
程序測試代碼以下:
- package com.gloomyfish.zoom.study;
-
- import java.awt.BorderLayout;
- import java.awt.Dimension;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.image.BufferedImage;
- import java.io.File;
- import java.io.IOException;
-
- import javax.imageio.ImageIO;
- import javax.swing.JComponent;
- import javax.swing.JFileChooser;
- import javax.swing.JFrame;
-
-
- public class BitBltFilterTest extends JComponent {
-
-
-
- private static final long serialVersionUID = 7462704254856439832L;
- private BufferedImage rawImg;
- private BufferedImage modImg;
- private Dimension mySize;
- public BitBltFilterTest(File f) {
- try {
- rawImg = ImageIO.read(f);
- modImg = ImageIO.read(new File("D:\\resource\\geanmm.png"));
-
- } catch (IOException e) {
- e.printStackTrace();
- }
- mySize = new Dimension(2*modImg.getWidth() + 20, modImg.getHeight()+ 100);
- filterImage();
- final JFrame imageFrame = new JFrame("Emboss Text - gloomyfish");
- imageFrame.getContentPane().setLayout(new BorderLayout());
- imageFrame.getContentPane().add(this, BorderLayout.CENTER);
- imageFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- imageFrame.pack();
- imageFrame.setVisible(true);
- }
-
- private void filterImage() {
- BitBltFilter filter = new BitBltFilter();
- filter.emboss(rawImg, modImg);
- }
-
- public void paint(Graphics g) {
- Graphics2D g2 = (Graphics2D) g;
- g2.drawImage(rawImg, 0, 0, rawImg.getWidth(), rawImg.getHeight(), null);
- g2.drawImage(modImg, rawImg.getWidth()+10, 0, modImg.getWidth(), modImg.getHeight(), null);
- g2.drawString("text image", rawImg.getWidth()/2, rawImg.getHeight()+10);
- g2.drawString("sharped text in image", modImg.getWidth() + 10, modImg.getHeight()+10);
- }
- public Dimension getPreferredSize() {
- return mySize;
- }
-
- public Dimension getMinimumSize() {
- return mySize;
- }
-
- public Dimension getMaximumSize() {
- return mySize;
- }
-
- public static void main(String[] args) {
- JFileChooser chooser = new JFileChooser();
- chooser.showOpenDialog(null);
- File f = chooser.getSelectedFile();
- new BitBltFilterTest(f);
- }
- }