Android 實現(xiàn)圖片水印與隱形數(shù)字水印

在使用知乎,微博的時候,我們經(jīng)??梢钥吹阶约荷蟼鞯膱D片被加上了文字水印,在實際的應(yīng)用開發(fā)過程中,很多客戶端都需要開發(fā)者自己編寫 Canvs 繪制圖形水印的方法,今天我想在這里介紹一個輕量級的開源 Android 圖片水印框架來避免開發(fā)過程中編寫復(fù)雜的繪圖代碼:AndroidWM,并且剖析它的實現(xiàn)過程和特色用法。

水印

這個框架最大程度上簡化了圖片水印繪制的問題,暴露了靈活的接口給用戶使用。在繪制水印的時候,只需要創(chuàng)建一個水印對象,一個水印創(chuàng)建者對象,然后把定制的水印對象傳給水印創(chuàng)建者即可。

實現(xiàn)水印第一步:引用類庫 androidWM

如果你使用 Android Studio 進(jìn)行項目的開發(fā),只需要在應(yīng)用 app 的 build.gradle 里面添加上這么一行代碼:

dependencies {
  ...
  implementation 'com.huangyz0918:androidwm:0.2.3'
  ...
}

然后點(diǎn)擊同步 gradle,讓其自動下載并且安裝好依賴即可。

實現(xiàn)水印第二步:創(chuàng)建一個水印,完工!

androidWM 給我們提供了四種不同的水印:

  • 圖形水印
  • 文字水印
  • 隱形圖形水印
  • 隱形文字水印

我們可以創(chuàng)建不同的水印對象來實現(xiàn)對水印風(fēng)格的定制化,比如我想創(chuàng)建一個文字水印,我就實例化一個WatermarkText,并且設(shè)置它的屬性:

 WatermarkText watermarkText = new WatermarkText(“Hello World”)
                    .setPositionX(0.5) // 橫坐標(biāo)
                    .setPositionY(0.5) // 縱坐標(biāo)
                    .setTextAlpha(100) // 透明度
                    .setTextColor(Color.WHITE) // 文字水印文字顏色
                    .setTextFont(R.font.champagne) // 字體
                    .setTextShadow(0.1f, 5, 5, Color.BLUE); // 字體的陰影

這樣我就拿到了一個文字水印 watermarkText ,接下來,我還需要一個畫師幫助我把水印畫到我想要的背景底圖上面,于是我們需要實例化一個WatermarkBuilder

    WatermarkBuilder.create(this, backgroundBitmap) // 加載背景底圖
                    .loadWatermarkText(watermarkText) // 加載水印對象
                    .getWatermark() // 繪制帶有水印的圖片
                    .setToImageView(backgroundView); // 設(shè)置結(jié)果到 ImageView 里

這里一氣呵成,首先傳入一個上下文 context,然后傳入一張你想要繪制的背景底圖,這個背景圖片可以來自于一個 ImageView, 也可以來自于系統(tǒng)的資源(如: R.drawable.image),你要是想直接傳入一個 Bitmap 也是可以的。最后,在調(diào)用完方法 .getWatermark() 以后,androidWM 可以幫助你直接將帶有水印的圖片設(shè)置到一個ImageView里面,或者使用方法 .getOutputImage() 獲得輸出的 Bitmap。

水印創(chuàng)建好啦!

同理,你也可以通過實例化一個 WatermarkImage 來創(chuàng)建一個圖像水印:

  WatermarkImage watermarkImage = new WatermarkImage(watermarkBitmap)
                    .setImageAlpha(80)
                    .setPositionX(0.5)
                    .setPositionY(0.5)
                    .setRotation(15)
                    .setSize(0.3);

            WatermarkBuilder
                    .create(this, backgroundBitmap)
                    .loadWatermarkImage(watermarkImage)
                    .getWatermark()
                    .setToImageView(backgroundView);

Boom ! 畫出來的水印長這樣:

圖片水?。⌒⊙劬?!

創(chuàng)建隱形水印

隱形水印是框架 androidWM 的一個特色,它支持兩種不同方式的隱形水?。?/p>

  • LSB 空域隱形水印
  • 頻域水印

創(chuàng)建隱形水印的話,設(shè)置水印的位置和大小顏色就沒有意義了,水印將被編碼到肉眼不可見的空間,只有使用框架的某些方法才能夠成功地檢測出來。

創(chuàng)建一個隱形的水印也是很簡單的,我們同樣可以通過 WatermarkBuilder 來繪制一個隱形的文字或者是圖形水?。?/p>

     WatermarkBuilder
            .create(this, backgroundBitmap)
            .loadWatermarkImage(watermarkBitmap)
            .setInvisibleWMListener(true, new BuildFinishListener<Bitmap>() {
                @Override
                public void onSuccess(Bitmap object) {
                    if (object != null) {
                       // do something...
                    }
                }

                @Override
                public void onFailure(String message) {
                      // do something...
                }
            });

在方法 .setInvisibleWMListener() 中第一個參數(shù)是用于選擇水印模式的參數(shù):

  • true 使用空域 LSB 方法繪制隱形水印
  • false 使用頻域隱形水印

同樣,對于隱形水印的檢測,我們可以初始化一個水印檢測器 WatermarkDetector :

     WatermarkDetector
            .create(inputBitmap, true)
            .detect(false, new DetectFinishListener() {
                @Override
                public void onSuccess(DetectionReturnValue returnValue) {
                       Bitmap watermarkImage = returnValue.getWatermarkBitmap();
                       String watermarkString = returnValue.getWatermarkString();
                 }

                @Override
                public void onFailure(String message) {
                       // do something...
                }
            });

在函數(shù)創(chuàng)建的時候,也需要選擇一種檢測模式,如果是 LSB 空域水印的檢測,在第二個布爾參數(shù)的位置傳進(jìn) true,反正是頻域隱形水印的話就傳 false。在檢測方法 detect() 的第一個參數(shù)也是類似,如果需要檢測文字類的水印傳入 true,圖片類的水印傳入 false。

添加圖片作為隱形水印

LSB 實現(xiàn)隱形水印的原理

講完了框架的使用,我們來說一下關(guān)于 androidWM 實現(xiàn)圖片隱形水印的原理,首先要說 LSB 空域水印。LSB 的全稱是 Least Significant Bits,即通過圖形中最不重要的一些信息位來儲存我們隱藏信息(水印)。LSB 方法是最簡單的嵌入水印的方法,事實上,任何一幅圖片都具備一定的容噪性,這表現(xiàn)在像素數(shù)據(jù)的最低有效位 (Least Significant Bit,LSB) 對人眼的視覺影響很小,秘密信息就隱藏在圖像每一個像素的最低位或次低位,實現(xiàn)其不可見性。

添加文字作為圖片水印

為了實現(xiàn)我們的隱形水印,androidWM 將一幅圖片的所有像素提取出來,其中每個像素都可以分解為 ARGB 四位信息(分別是 alpha, red, green, blue),作為標(biāo)準(zhǔn)的 ARGB 編碼方式,每一位都由一個從 0 到 255 的整形數(shù)字表示,其中作為人眼來說,最后一位色階的細(xì)小變化是根本不會被觀察到的,我們將水印的文字(或是圖片)信息編碼為一串二進(jìn)制的字符,將每個 ARGB 的值的最后一位清零,用二進(jìn)制字符替換,達(dá)到了利用最后一位色階來儲存隱藏的信息的作用。

LSB 編碼方式

在實際的工程中,我們將水印信息編碼成二進(jìn)制以后,加上了非二進(jìn)制的前后綴用于識別程序檢測,同時,為了讓整張圖片都被水印給覆蓋,我們的算法將水印信息循環(huán)地鋪設(shè)在背景圖片中,只要圖片之中含有一個有效的水印信息,就能夠成功地檢測到。

對于 LSB 空域數(shù)字水印來說,其有如下優(yōu)點(diǎn):

  • 支持的水印信息量大
  • 對原圖影響小
  • 算法簡單

但是其也有不可忽視地巨大缺點(diǎn):

  • 在空間域上繪制數(shù)字水印,水印會隨著圖片變化而破壞
  • 穩(wěn)定性差,不能抵抗圖像的裁剪、縮放和 jpg 壓縮
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容