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

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

水印

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

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

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

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

然后點擊同步 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 的一個特色,它支持兩種不同方式的隱形水印:

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

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

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

     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ù)的位置傳進 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ì)小變化是根本不會被觀察到的,我們將水印的文字(或是圖片)信息編碼為一串二進制的字符,將每個 ARGB 的值的最后一位清零,用二進制字符替換,達(dá)到了利用最后一位色階來儲存隱藏的信息的作用。

LSB 編碼方式

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

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

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

但是其也有不可忽視地巨大缺點:

  • 在空間域上繪制數(shù)字水印,水印會隨著圖片變化而破壞
  • 穩(wěn)定性差,不能抵抗圖像的裁剪、縮放和 jpg 壓縮
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內(nèi)容