OpenGLES添加水印

版權(quán)聲明:本文為衛(wèi)偉學(xué)習(xí)總結(jié)文章献宫,轉(zhuǎn)載請注明出處!
原理:把文字變成圖片实撒,用多紋理渲染的方式來添加姊途。其他圖片水印直接是多紋理渲染即可。即添加水印=多個紋理繪制在同一個surface上知态。
理解了添加水印的原理捷兰,不管是視頻水印還是圖片水印都是很簡單的了,只是使用的紋理不一樣而已负敏。如果是繪制文字水印的話寂殉,則需要將文字生成圖片,然后將圖片使用紋理繪制即可原在。
那么怎樣將多個紋理添加到同一個surface上友扰?
簡單示例代碼:

public class WlEncodecRender implements WLEGLSurfaceView.WlGLRender {

private Context context;
//頂點坐標
private float[] vertexData = { // in counterclockwise order:
        -1f, -1f, 0.0f, // bottom left
        1f, -1f, 0.0f,// bottom right
        -1f, 1f, 0.0f,// top left
        1f, 1f,0.0f,// top right

        0f, 0f, 0f, // 水印預(yù)留位置
        0f, 0f, 0f,
        0f, 0f, 0f,
        0f, 0f, 0f
};

// 紋理坐標 對應(yīng)頂點坐標  與之映射
private float[] fragmentData = {
        0f, 1f, 0.0f, // bottom left
        1f, 1f, 0.0f, // bottom right
        0f, 0f, 0.0f, // top left
        1f, 0f, 0.0f, // top right
};

// 位置
private FloatBuffer vertexBuffer;
// 紋理
private FloatBuffer fragmentBuffer;

private int program;
private int vPosition;
// 紋理位置
private int fPosition;
// 紋理 默認第0個位置 可以不獲取
private int textureid;

// vbo id
private int vboId;

private int fboTextureId;

private Bitmap bitmap;
private int waterTextureId;

private int bitmapTextureid;


public WlEncodecRender(Context context, int textureid) {
    this.context = context;
    this.textureid = textureid;

    initWater(); 

    vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(vertexData);
    vertexBuffer.position(0);

    fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(fragmentData);
    fragmentBuffer.position(0);

}

private void initWater() {
    bitmap = WlShaderUtil.createTextImage("我是水印",40,"#fff000","#00000000",0);

    // 設(shè)置位置 根據(jù)需求自己配置
    float r = 1.0f * bitmap.getWidth() / bitmap.getHeight();
    float w = r * 0.1f;
    vertexData[12] = 0.8f - w;
    vertexData[13] = -0.8f;
    vertexData[14] = 0;

    vertexData[15] = 0.8f;
    vertexData[16] = -0.8f;
    vertexData[17] = 0;

    vertexData[18] = 0.8f - w;
    vertexData[19] = -0.7f;
    vertexData[20] = 0;

    vertexData[21] = 0.8f;
    vertexData[22] = -0.7f;
    vertexData[23] = 0;
}

@Override
public void onSurfaceCreated() {
    // 啟用透明
    GLES20.glEnable(GLES20.GL_BLEND);
    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA,GLES20.GL_ONE_MINUS_SRC_ALPHA);
    String vertexSource = WlShaderUtil.getRawResource(context, R.raw.vertex_shader_screen);
    String fragmentSource = WlShaderUtil.getRawResource(context, R.raw.fragment_shader_screen);

    program = WlShaderUtil.createProgram(vertexSource, fragmentSource);

    vPosition = GLES20.glGetAttribLocation(program, "v_Position");
    fPosition = GLES20.glGetAttribLocation(program, "f_Position");

    // 創(chuàng)建vbo
    createVBO();

    //創(chuàng)建水印紋理
    bitmapTextureid =  createWaterTextureId();
}

/**
 * 創(chuàng)建vbo
 */
private void createVBO() {
    //1. 創(chuàng)建VBO
    int [] vbos = new int[1];
    GLES20.glGenBuffers(1, vbos, 0);
    vboId = vbos[0];
    //2. 綁定VBO
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
    //3. 分配VBO需要的緩存大小
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4 + fragmentData.length * 4, null, GLES20. GL_STATIC_DRAW);
    //4. 為VBO設(shè)置頂點數(shù)據(jù)的值
    GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);
    GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, fragmentData.length * 4, fragmentBuffer);
    //5. 解綁VBO
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}

/**
 * 創(chuàng)建水印紋理
 */
private int createWaterTextureId() {
    int[] textureIds = new int[1];
    // 創(chuàng)建紋理
    GLES20.glGenTextures(1,textureIds,0);
    waterTextureId = textureIds[0];
    // 綁定紋理
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, waterTextureId);
    //環(huán)繞(超出紋理坐標范圍)  (s==x t==y GL_REPEAT 重復(fù))
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
    //過濾(紋理像素映射到坐標點)  (縮小、放大:GL_LINEAR線性)
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

    ByteBuffer bitmapBuffer = ByteBuffer.allocate(bitmap.getHeight() * bitmap.getWidth() * 4);//RGBA
    bitmap.copyPixelsToBuffer(bitmapBuffer);
    //將bitmapBuffer位置移動到初始位置
    bitmapBuffer.flip();

    //設(shè)置內(nèi)存大小綁定內(nèi)存地址
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(),
            0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, bitmapBuffer);

    //解綁紋理
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
    return textureIds[0];
}

@Override
public void onSurfaceChanged(int width, int height) {
    GLES20.glViewport(0, 0, width, height);
}

@Override
public void onDrawFrame() {
    // 清空顏色
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    // 設(shè)置北京顏色
    GLES20.glClearColor(1f,0f, 0f, 1f);

    //使用程序
    GLES20.glUseProgram(program);

    // 設(shè)置紋理
    // 綁定渲染紋理  默認是第0個位置
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureid);

    GLES20.glEnableVertexAttribArray(vPosition);
    GLES20.glEnableVertexAttribArray(fPosition);

    // 使用VBO設(shè)置紋理和頂點值
    useVboSetVertext();

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);


    //bitmap
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,bitmapTextureid);

    GLES20.glEnableVertexAttribArray(vPosition);
    GLES20.glVertexAttribPointer(vPosition,2,GLES20.GL_FLOAT,false,12,
            48);
    GLES20.glEnableVertexAttribArray(fPosition);
    GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 12,
            vertexData.length * 4);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

}

/**
 * 使用vbo設(shè)置頂點位置
 */
private void useVboSetVertext() {
    //1. 綁定VBO
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
    //2. 設(shè)置頂點數(shù)據(jù)
    GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8,
            0);
    GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8,
            vertexData.length * 4);
    //3. 解綁VBO
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}

ShaderUtil.java

/**
 * 根據(jù)文字創(chuàng)建圖片
 */
public static Bitmap createTextImage(String text, int textSize, String textColor, String bgColor, int padding) {
    Paint paint = new Paint();
    paint.setColor(Color.parseColor(textColor));
    paint.setTextSize(textSize);
    paint.setStyle(Paint.Style.FILL);
    paint.setAntiAlias(true);

    float width = paint.measureText(text,0,text.length());

    float top = paint.getFontMetrics().top;
    float bottom = paint.getFontMetrics().bottom;

    Bitmap bm = Bitmap.createBitmap((int) (width + padding * 2), (int) ((bottom - top) + padding * 2), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bm);

    canvas.drawColor(Color.parseColor(bgColor));
    canvas.drawText(text, padding, - top + padding, paint);
    return bm;
}

public static int loadBitmapTexture(Bitmap bitmap) {
    int[] textureIds = new int[1];
    GLES20.glGenTextures(1,textureIds,0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureIds[0]);

    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

    ByteBuffer bitmapBuffer = ByteBuffer.allocate(bitmap.getHeight() * bitmap.getWidth() * 4);
    bitmap.copyPixelsToBuffer(bitmapBuffer);
    bitmapBuffer.flip();

    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(),
            bitmap.getHeight(), 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, bitmapBuffer);
    return textureIds[0];
}

在當前GL_TEXTURE_2D紋理繪制之后在glBindTexture綁定水印的紋理繪制即可庶柿。需要注意的幾個點:

    1. 需要開啟透明村怪,不然沒有透明效果。
//啟用透明
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, 
GLES20.GL_ONE_MINUS_SRC_ALPHA);
    1. 如果是使用fbo來離屏渲染OES紋理添加水印浮庐,需要在開個fbo來使用2D繪制OES的紋理和添加水印甚负,然后另外用一個Render來繪制fbo紋理,即:fbo里面OES和2d不能混用审残,不然不會起作用梭域。
    1. 使用VBO需要注意點的位置。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搅轿,一起剝皮案震驚了整個濱河市病涨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌璧坟,老刑警劉巖既穆,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異雀鹃,居然都是意外死亡幻工,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門黎茎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來囊颅,“玉大人,你說我怎么就攤上這事√叽” “怎么了先鱼?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長奸鬓。 經(jīng)常有香客問我焙畔,道長,這世上最難降的妖魔是什么串远? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任宏多,我火速辦了婚禮,結(jié)果婚禮上澡罚,老公的妹妹穿的比我還像新娘伸但。我一直安慰自己,他們只是感情好留搔,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布更胖。 她就那樣靜靜地躺著,像睡著了一般隔显。 火紅的嫁衣襯著肌膚如雪却妨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天括眠,我揣著相機與錄音彪标,去河邊找鬼。 笑死掷豺,一個胖子當著我的面吹牛捞烟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播当船,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼题画,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了德频?” 一聲冷哼從身側(cè)響起苍息,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抱婉,沒想到半個月后档叔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡蒸绩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铃肯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片患亿。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出步藕,到底是詐尸還是另有隱情惦界,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布咙冗,位于F島的核電站沾歪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏雾消。R本人自食惡果不足惜灾搏,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望立润。 院中可真熱鬧狂窑,春花似錦、人聲如沸桑腮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽破讨。三九已至丛晦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間提陶,已是汗流浹背采呐。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留搁骑,地道東北人斧吐。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像仲器,于是被迫代替她去往敵國和親煤率。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

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