Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BlindWatermark

PHP Library for Blind&Invisible Image Watermark.

GitHub:https://github.com/kid1296/BlindWatermark

License PHP Platform

Features

Item Before Now
Speed (940×940 embed) ~4.9 s ~2.5 s (2× faster)
Speed (extract) ~3.8 s ~1.5 s (2.5× faster)
Peak memory (embed+extract, 940×940) required memory_limit=2G ~61 MB (fits in default 128 MB)
Peak memory (1358×780) OOM at 128 MB ~81 MB
Image quality (PSNR, 940×940) ~36.9 dB 35.6 dB
Robustness (salt-pepper / bright / shelter / crop) PASS PASS
Robustness (resize, natural photo) PASS PASS

PSNR 35–40 dB is generally considered "visually lossless" for photographs. The d1/d2 default was reduced from 36/20 to 27/15 for higher PSNR, while still tolerating salt-pepper / brightness / shelter / crop attacks on typical host images.

Requirements

  • PHP >= 8.1
  • GD extension (enabled by default in most PHP distributions)

The GD extension is required for all image I/O (reading JPEG/PNG, writing PNG, and applying attack simulations such as resize / salt-pepper / brightness). Verify with php -m | grep gd.

Install

composer require kid1296/blind-watermark

Usage

All examples run with the default PHP memory limit — no -d memory_limit=2G flag is needed anymore (peak memory stays well under 128 MB even for 1.3 megapixel images).

01 Embed & Extract — String Watermark

Original image + watermark text = invisible watermark image.

origin.jpg + 'This is a test sentence.'embedded_str.png

Full example: 01_embed_extract_str.php

<?php
require __DIR__ . '/../vendor/autoload.php';
use Kid1296\BlindWatermark\WaterMark;

// ========== embed ==========
$bwm1 = new WaterMark(passwordWm: 1, passwordImg: 1);
$bwm1->read_img('examples/pics/origin.jpg');
$wm = 'This is a test sentence.';
$bwm1->read_wm($wm, 'str');
$bwm1->embed('examples/output/embedded_str.png');
$lenWm = $bwm1->wmSize;                    // remember this length

// ========== extract ==========
$bwm2 = new WaterMark(passwordWm: 1, passwordImg: 1);
$extracted = $bwm2->extract(
    filename: 'examples/output/embedded_str.png',
    wmShape:  $lenWm,
    mode:     'str'
);
// $extracted === 'This is a test sentence.'

Output:

embed done in 2.51s
Put down the length of wm_bit 191
extract done in 1.49s
extracted: This is a test sentence.
RESULT: PASS

02 Embed & Extract — Bit-Array Watermark

Embed an arbitrary array of 0/1 bits (useful for custom protocols / binary payloads).

origin.jpg + 1011010011010110embedded_bit.png

Full example: 02_embed_extract_bit.php

<?php
require __DIR__ . '/../vendor/autoload.php';
use Kid1296\BlindWatermark\WaterMark;

$bits = [1,0,1,1,0,1,0,0,1,1,0,1,0,1,1,0];

// embed
$bwm1 = new WaterMark(1, 1);
$bwm1->read_img('examples/pics/origin.jpg');
$bwm1->read_wm($bits, 'bit');
$bwm1->embed('examples/output/embedded_bit.png');
$lenWm = $bwm1->wmSize;

// extract
$bwm2 = new WaterMark(1, 1);
$extracted = $bwm2->extract(
    filename: 'examples/output/embedded_bit.png',
    wmShape:  $lenWm,
    mode:     'bit'                   // returns int[] of 0/1
);
// $extracted === $bits

Output:

original bits: 1011010011010110
embed done in 2.64s, wm_size = 16
extract done in 1.55s
extracted bits: 1011010011010110
RESULT: PASS

03 In-Memory Pipeline (No-Temp-Files)

Suited for web services: read host image from request / database, embed, return BGR data directly without touching disk.

Full example: 03_in_memory.php

<?php
require __DIR__ . '/../vendor/autoload.php';
use Kid1296\BlindWatermark\WaterMark;
use Kid1296\BlindWatermark\Image\ImageIo;

$img = ImageIo::read('examples/pics/origin.jpg');
// $img = ['data'=>string, 'h'=>int, 'w'=>int, 'channels'=>int]

// embed — omit $filename, returns in-memory result array
$bwm1 = new WaterMark(1, 1);
$bwm1->read_img($img);                      // pass array directly
$bwm1->read_wm('This is a test sentence.', 'str');
$embedded = $bwm1->embed();                 // no filename → returns array
$lenWm = $bwm1->wmSize;
// $embedded is ['data'=>string, 'h'=>int, 'w'=>int, 'channels'=>int]
// You can save it with ImageIo::write(...) later, or stream to client.

// extract — pass embedImg array (instead of filename)
$bwm2 = new WaterMark(1, 1);
$extracted = $bwm2->extract(embedImg: $embedded, wmShape: $lenWm, mode: 'str');

Output:

host image: 940x940, channels=3
embed done in 2.16s
embedded: 940x940, channels=3, data size = 21206400 bytes
extract done in 1.18s
extracted: This is a test sentence.
RESULT: PASS

04 Attack / Recover — Robustness Test

Demonstrates the watermark surviving common post-processing attacks, plus crop-and-recover.

Embedded image (host = origin.jpg, wm = 'This is a attack test'):

embedded_attacks.png

Attack results (watermark extracted successfully from every image below):

salt-pepper 2% brightness ×0.9 resize 940²→800×600
att_sp att_bright att_resize
shelter 5 blocks @5% crop right 20% crop recovered
att_shelter att_crop att_crop_rec

Full example: 04_with_attacks.php

$ php examples/04_with_attacks.php
embedded wm_size = 167

-- attacks --
  salt-pepper 2%                 -> 'This is a attack test' [PASS]
  brightness 0.9                 -> 'This is a attack test' [PASS]
  resize 940x940 -> 800x600 -> back -> 'This is a attack test' [PASS]
  shelter 5 blocks @5%           -> 'This is a attack test' [PASS]

-- crop + recover --
  crop right 20% + recover       -> 'This is a attack test' [PASS]
  estimate_crop_parameters       -> [0,0,752,940] (expected same)  [PASS]

Note on resize robustness: The resize attack uses GD's bilinear re-sampling. It works reliably on typical photographs with good tonal range (like origin.jpg, mean ≈ 120, stdev ≈ 40). It may fail on extremely uniform / near-solid-colour host images (e.g. mean > 250/255) because the relative watermark strength is too low to survive the low-pass filter. This is a fundamental limitation of the DWT-DCT-SVD blind-watermark paradigm, not a library bug. To verify resize robustness, run the example with origin.jpg as the host.

📮Email

kkkkkkid3172@yeah.net

Reference Project

https://github.com/guofei9987/blind_watermark

About

php library for blind&invisible watermark; PHP 盲水印库:实现不可见图像水印.

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages