Tuesday 14 August 2018

Image Protection Using PHP, the GD Library, JavaScript, and XHTML

There are two solutions presented in this post: one by myself and one by MooTools creator Valerio Proietti. Each has its advantages and disadvantages.

The CSS (Both Solutions)
.image { position:relative; overflow:hidden; }
.pixel { width:1px; height:1px; position:absolute; }
#pixels .pixel { float:left; position:relative; width:1px; height:1px; }
We set up a container and pixel. I needed to add overflow:hidden; because IE6 was having fits.

The PHP: Store Pixels
// settings
$image = 'top-logo-pixel.png';

// get the image size
list($width,$height) = getimagesize($image);
$img = imagecreatefrompng($image);

// data array
$data = array('height'=>$height,'width'=>$width,'pixels'=>array());

// start the height loop
for ($y = 0; $y < $height; $y++){
for ($x = 0; $x < $width; $x++){
$color_index = imagecolorat($img, $x, $y);
$a = ($color_index & 0x7F000000) >> 24;
$r = ($color_index >> 16) & 0xFF;
$g = ($color_index >> 8) & 0xFF;
$b = $color_index & 0xFF;
if ($a > 0){
$a = abs(($a / 127) - 1);
$a = hex(round($a * 255));
} else {
$a = '';
}
$r = hex($r);
$g = hex($g);
$b = hex($b);
$data['pixels'][] = "$r$g$b$a";
}
}

// clean up
imagedestroy($img);

/* utility function */
function hex($v){
$bit = dechex($v);
if (strlen($bit) == 1) $bit = "0$bit";
return $bit;
}
The above functionality simply stores the image information in an array. No output to this point.

View Demo
The PHP: Output Method 1: HTML/DIVs
/* output as divs */
$top = $left = 0;
echo '<div class="image" style="width:',$data['width'],'px;height:',$data['height'],'px">';
foreach($data['pixels'] as $index=>$pixel) {
echo '<div class="pixel" style="background:#',substr($pixel,0,6),';top:',$top,'px;left:',$left,'px;"></div>';
if($index && ($index % $data['width'] == 0)) { $top++; $left = 0; } else { $left++; }
}
echo '</div>';
My method is the simpler of the two: for every pixel, output a DIV with a background color equal to the pixel.

The PHP: Output Method 1: JSON -> MooTools -> DIVs
<?php
function optimize_data($data){

$image = array(
'colors' => array(),
'data' => array(),
'height' => $data['height'],
'width' => $data['width']
);

$iterator = array();

$i = 0;
$gidx = 0;
$num = 1;

foreach($data['pixels'] as $color){
if (!isset($image['colors'][$color])) $image['colors'][$color] = dechex($i++);

$di = $image['colors'][$color];

if ($pdi['c'] == $di){
$num++;
$image['data'][$pdi['i']] = $di.'-'.$num;
} else {
$num = 1;
$image['data'][$gidx] = $di;
$pdi = array('c' => $di, 'i' => $gidx);
$gidx++;
}
}

$image['data'] = implode($image['data'], ';');
foreach($image['colors'] as $c => $v) $k[] = $v.':'.$c;
$image['colors'] = implode($k, ';');

return json_encode($image);

}

?>

<script type="text/javascript">
/* kamicane's version */
var image = <?php print_r(optimize_data($data)); ?>;
var colors = image.colors;
var data = image.data;
var height = image.height;
var width = image.width;

colors = colors.split(';');
var ch = {};
colors.each(function(c){
var b = c.split(':');
ch[b[0]] = b[1];
});

data = data.split(';');
var pixels = [];

data.each(function(d){
d = d.split('-');
if (d[1] == null) d[1] = 1;
Number(d[1]).times(function(i){
pixels.push(ch[d[0]]);
});
});

document.addEvent('domready', function(){

var pixelsE = $('pixels');

pixelsE.setStyles({'height': image.height, 'width': image.width });

pixels.each(function(p){
var d = new Element('div', {'class': 'pixel'});
d.style.backgroundColor = '#' + p;
d.inject(pixelsE);
});

});
</script>

<div id="pixels"></div>
Valerio chose to take the array of pixels and use a simple compression method to output the pixels as JSON. He then creates MooTools JavaScript code to read the algorithm and output a series of DIVs to create the image.

0 comments:

Post a Comment