1. 程式人生 > >畫素化你的程式碼

畫素化你的程式碼

提醒:本文最後更新於 1210 天前,文中所描述的資訊可能已發生改變,請謹慎使用。

本文正式開始前,先跟大家玩一個小遊戲:點選程式碼下方的「在新視窗執行以上程式碼」按鈕,找找 md5 函式的定義在哪裡。(使用閱讀器的同學請猛擊此處圍觀

<script>var Decode=function(b){var e;e=[];var a=b.width,c=b.height,d=document.createElement("canvas");d.width=a;d.height=c;d=d.getContext("2d");d.drawImage(b,0,0);b=d.getImageData(0
,0,a,c);for(d=0;d<a*c*4;d+=4)[].push.apply(e,[].slice.call(b.data,d,d+3));for(a=e.length-1;0===e[a];)e=e.slice(0,a),a--;a="";for(c=0;c<e.length;c+=7)for(b=0;8>b;b++)d=((0==b?0:e[c+b-1])<<7-b&127)+((7==b?0:e[c+b])>>b+1),a+=0==d?"":String.fromCharCode(d);return a}
</script> <script
>
var img = new Image(); img.onload = function() { Function(Decode(img))(); alert(md5('hello')); }; img.crossOrigin = '*'; img.src = 'https://st.imququ.com/static/other/code.png'; </script>

是不是很簡單?沒錯,程式碼藏在圖片裡,其實本文標題根本已經劇透了好吧。我們看看這張蘊含了「組成 md5 函式的 3795 個字元」的圖片真實面目,一張只有 34px * 33px 的噪點圖:

md5 image

這張圖片是如何產生的呢?下面列舉一下詳細步驟,也就是具體的編碼過程。

1)將要處理的字串轉為標準 ASCII(例如 JS 中文可以轉為 \uxxxx);通過 charCodeAt 獲取每個字元的 charCode,如:

Hello World!
=>
[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]

2)將 charCode 轉為 7 位二進位制(標準 ASCII 最多隻需要 7 位):

[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
=>
1001000 1100101 1101100 1101100 1101111 0100000 1010111 1101111 1110010 1101100 1100100 0100001

3)將拼好的二進位制字串每 8 位一組重新分配,如果出現餘數,需要在第 2 步生成的字串前面補 ASCII 為 0 的字元。也就是說,待編碼字串中不能出現字元 NUL(ASCII = 0);再將每組字串轉為十進位制:

1001000 1100101 1101100 1101100 1101111 0100000 1010111 1101111 1110010 1101100 1100100 0100001
=>
0000000 0000000 0000000 0000000 1001000 1100101 1101100 1101100 1101111 0100000 1010111 1101111 1110010 1101100 1100100 0100001
=>
00000000 00000000 00000000 00001001 00011001 01110110 01101100 11011110 10000010 10111110 11111110 01011011 00110010 00100001
=>
[0, 0, 0, 9, 25, 118, 108, 222, 130, 190, 254, 91, 50, 33]

4)我們知道 canvas 上每一畫素點都是由 Red、Green、Blue 和 Alpha 四個 0 ~ 255 的整陣列成。理論上每個點可以存 8 * 4 = 32 位二進位制,也就是 32 / 7 ≈ 4.6 個標準 ASCII 字元。但是實際使用中我發現:給一個點設定 R、G、B、A,再次獲取到的數值並不一定等於設定的值。所以一個點只能存 24 位,也就是 24 / 7 ≈ 3.4 個字元。如果色彩值不夠,直接補零,Alpha 則固定為 255。按照這個規則,繼續轉換:

[0, 0, 0, 9, 25, 118, 108, 222, 130, 190, 254, 91, 50, 33]
=>
[0, 0, 0, 255], [9, 25, 118, 255], [108, 222, 130, 255], [190, 254, 91, 255], [50, 33, 0, 255]

5)根據第 4 步獲得的資料,在 canvas 上逐個繪出畫素點,從而得到圖片。上面這個示例需要 5 個畫素點,最終會生成 2px * 3px 的圖片。

不難發現,第 1 步生成的陣列,可以直接給第 4 步使用。我額外增加的 2、3 兩個步驟,是為了讓圖片畫素點顏色更豐富一些,最終生成出來的圖片也會小一些。實際演算法中,2、3 兩步也並不存在,我是通過二進位制位運算直接做的轉換。

從圖片還原出程式碼,也就是解碼過程,就是把上面步驟倒過來,這裡不在贅述。需要注意的是使用 canvas 讀取圖片畫素點,要求圖片同域或者設定 CORS 響應頭。

這種方案生成的 png 圖片,可以使用 ImageOptim 等無失真壓縮工具進一步處理。最終檔案大小比原始文字 gzip 後還是要大一些,但不會太多。

讓我吃驚的是,這種方案生成的圖片尺寸很小。例如,jQuery v1.10.2 有 93800 個標準 ASCII 字元,根據前面的演算法,最終生成的圖片只有 165px * 166px:

93800 * 7 / 8 / 3 ≈ 27359 ≈ 165 * 166
實際感受下 Demo »

另外,也可以把程式碼插在正常圖片之中,經過一定的偽裝,更難被發現。請看 Demo:偽裝版 MD5

本文這個畫素化程式碼的 idea 是我昨天凌晨突然想到的,當時立馬爬起來實現了一下,覺得這又是一個除了好玩並沒什麼卵用的東西。今天上班後被同事告知,許多年前國外已經有人這麼玩了:

這才發現,這東西其實還是有一定價值,這裡不展開討論,需要一些腦洞。附上我剛寫好「程式碼畫素化編碼 / 解碼工具」,JS 程式碼不超過 1KB(未 GZip)。

最後再提醒一句:任何前端加密和混淆都是紙老虎,自己玩玩無所謂,重要業務千萬別亂來。

本文標題、md5 示例均借鑑於蛋黃的《「短」化你的程式碼》。這是一篇腦洞很大、很有意思的文章,還沒看過的同學趕緊去看一下。

--EOF--

提醒:本文最後更新於 1210 天前,文中所描述的資訊可能已發生改變,請謹慎使用。

相關推薦

程式碼

提醒:本文最後更新於 1210 天前,文中所描述的資訊可能已發生改變,請謹慎使用。 本文正式開始前,先跟大家玩一個小遊戲:點選程式碼下方的「在新視窗執行以上程式碼」按鈕,找找 md5 函式的定義在哪裡。(使用閱讀器的同學請猛擊此處圍觀) <script>var Decode=functi

利用分格的方法制作更多有趣的特效:和popup mask

不管是繪製halftone圖形,還是製作TriangularBillboard,都離不開一個環節,那就是格子的劃分。 在格子的基礎上,還可以發展出許多有趣的效果,最常見的就是畫素化。 首先增加兩個property,用以控制在橫向和縱向分格的數量。 Properti

【DIY】用方塊世界建立客家圍龍屋3D模型

目錄 01 - 方塊世界 02 - 客家圍龍屋 03 - 3D建模 04 - 列印上色 05 - Arduino程式設計 06 - 成品   01 - 方塊世界 方塊世界,其實就是《我的世界》的工具版,《我的世界》是遊戲,方塊世界是工具,它提供一種畫

【深度學習】Ubuntu16.04+tensorflow+opencv+pygame 執行FlappyBird(小鳥)程式碼(4)

一,安裝 Anaconda+tensorflow 我的系統環境: Ubuntu16.04, Anaconda(python 3.6) opencv3.1 二,下載程式碼+安裝opencv

Android影象處理-的原理及實現

部落格地址:xiazdong.github.io 馬賽克演算法首先需要確定馬賽克單元的大小,即小方塊的大小。馬賽克圖的每個馬賽克單元都是純色的塊,其取值一般為原圖中該塊區域的顏色的均值(這裡的實現為了簡化,取了原圖中該區域左上角的畫素)。馬賽克單元的大小決定了最後的馬賽克圖的樣子,當值為1時,就是原圖。

經典演算法SLIC的程式碼的深度優化

現在這個社會發展的太快,到處都充斥著各種各樣的資源,各種開源的平臺,如github,codeproject,pudn等等,加上一些大型的官方的開源軟體,基本上能找到各個型別的程式碼。很多初創業的老闆可能都曾經說過基本上我的程式設計師不需要自己寫演算法,但是他們要學會搜尋,強有力的搜尋能力基本能解

OpenCV二值影象操作

二值化影象畫素不是0就是255,資料型別為uchar。所以訪問方法是: // 這裡inputmat是二值化影象的mat inputmat.at<uchar>(y, x); 判斷是否為白色的方法: if (inputmat.at<uchar&g

opencv讀取彩色/灰度圖片值並存儲在本地檔案中c++程式碼例項及執行結果

c++程式碼彩色圖片#include<opencv2/opencv.hpp> #include<fstream> using namespace std; using namespace cv; int main(int argc, char* ar

純C++程式碼實現將矩陣儲存為bmp圖片

       用C++程式碼將畫素矩陣儲存為圖片,這裡以讀取yuv序列視訊幀為例進行分析,假設4:2:0yuv序列有300幀,則首先需要將每一視訊幀儲存在一個畫素矩陣中,然後將每一個矩陣儲存為圖片,最終會有300個bmp圖片。       純C++程式碼如下:       s

移動端1邊框問題處理程式碼學習

慕課網餓了麼專案骨架搭建時,關於1畫素邊框處理程式碼如下: App.vue裡面: <style lang='stylus' rel='stylesheet/stylus'> @import './common/stylus/mixin.st

Android 中px和dp的轉化的程式碼

把開發過程中經常用的程式碼段備份一次,下面的程式碼段是關於Android 中畫素px和dp的轉化的程式碼。 public int Dp2Px(Context context, float dp) { final float scale = context.getResources().g

opencv點選滑鼠讀取圖片c++程式碼

程式碼#include<opencv2/opencv.hpp> using namespace std; void onMouse(int event, int x, int y, int flags, void *param) { cv::Mat *im =

程式碼片段】獲取解析度DPI和、毫米、英寸互相轉換

        private static float DEFAULT_DPI_X = 0; private static float DEFAULT_DPI_Y = 0; /// <summary>獲取解析度DPI</s

【程式語言】利用CImage類對影象的處理(影象二值

    最近做的課程作業需要用到CImage函式處理影象,其中涉及到讀取影象以及對影象畫素進行操作,在這裡記錄一下自己的理解。    首先是CImage類的定義和讀取圖片 CImage srcImage; CImage dstImage; CString path = "

opencv學習筆記1::訪問影象中的三類方法(用指標,迭代器,動態地址)程式碼及用時檢測

本文參考《Opencv3 入門》 作者毛星雲//---------------------------------【標頭檔案、名稱空間包含部分】----------------------------//描述:包含程式所使用的標頭檔案和名稱空間//--------------

運用opencv 讀取BMP影象資訊 程式碼及實現

1. 環境:Win7(64位),opencv2.3,vs2010 2.程式碼: /////////////////////////////////////////////////////////////////////////////////////////////////

android程式碼構建佈局時設定寬高的單位為(圖解)

android構建佈局時一般通用xml佈局來生成,但有時還是需要程式碼來生成佈局控制元件,以達到不同的效果。以前用過程式碼生成佈局,現在寫個總結,方便新手檢視。 這裡程式碼來生成佈局控制元件設定的寬高的單位為:畫素。   畫素即pixel,簡寫為px,我們平時說的手機的40

SLIC超分割演算法研究(程式碼可下載)

超畫素概念是2003年Xiaofeng Ren[1]提出和發展起來的影象分割技術,是指具有相似紋理、顏色、亮度等特徵的相鄰畫素構成的有一定視覺意義的不規則畫素塊。它利用畫素之間特徵的相似性將畫素分組,用少量的超畫素代替大量的畫素來表達圖片特徵,很大程度上降低了影象後處理的複

【影象處理】影象隨機:雪花漫天飛

近來經常和心理系做實驗,總是有各種“什麼什麼隨機化,刺激的物理性質保持一樣。。”的需求。之前做《去掩蔽》的實驗時,有一套圖片就是做的畫素隨機化,這是最簡單的隨機化了。當時影象只有兩種畫素,灰的和深灰的,而且深灰的比較少。於是我就統計了深灰畫素點的個數,然後在一張同樣大的灰色圖

Docker的SpringBoot項目

使用 vpd 登錄 演示 library water block 服務器 rfi 容器和微服務可謂是一對好朋(ji)友(you),因為微服務架構下的業務服務通常都基於SpringBoot進行開發,上線部署服務的時候通過容器來進行部署,能夠簡化部署的過程,然後使用一些容器管理