I have a JAVA application who send compressed image over network. Each pixel value is converted into new Byte type. My problem is that I don't know how to correctly decode thos Byte with PHP.
Here is the JAVA compression:
public byte[] CompressedImage(BufferedImage img, int color_type) {
if ((img.getType() != 2) && (img.getType() != 1)) {
throw new RuntimeException("Image format not supported");
}
int sizeX = img.getWidth(); // 640px
int sizeY = img.getHeight(); // 80px
Vector compressedData = new Vector(sizeY * (1 + 3 * sizeX) + 1);
DataBuffer data = img.getRaster().getDataBuffer();
int count = 0;
int nextPix = 0;
int ptr = 0;
for (int y = 0; y < sizeY; y++) {
compressedData.add(new Byte((byte)-128));
int currPix = data.getElem(ptr++);
int x = 1;
do{
if (x < sizeX) {
nextPix = data.getElem(ptr++);
if ((nextPix == currPix) && (count < 63)) {
count++;
continue;
}
}
int color_R = (currPix & 0xFF0000) >> 16;
int color_G = (currPix & 0xFF00) >> 8;
int color_B = currPix & 0xFF;
compressedData.add(new Byte((byte)((color_R & 0xFF) >> 1)));
compressedData.add(new Byte((byte)((color_G & 0xFF) >> 1)));
compressedData.add(new Byte((byte)((color_B & 0xFF) >> 1)));
if (count != 0) {
compressedData.add(new Byte((byte)(0xFFFFFFC0 | count)));
}
count = 0;
currPix = nextPix;
} while (x++ < sizeX);
}
byte[] result = new byte[compressedData.size()];
Enumeration e = compressedData.elements();
int i = 0;
while (e.hasMoreElements()) {
result[(i++)] = ((Byte)e.nextElement()).byteValue();
}
return result;
}
Using WireShark software I have been able to capture a packet with full image that I stored in a file "scalio.bin"
Now I try to read this scalio.bin file with PHP in order to recreate the image. I know that each -128 value means a new line I know that I should be able to get 4 values: R, G, B and count.
I tried to play with unpack() and sprintf() without real success:
$filename = "scalio.bin";
$handle = fopen($filename, "rb");
$content = fread($handle, filesize($filename));
/* METHOD 1 */
for ($i=0; $i<strlen($content); $i++){
$v = sprintf("%d", bin2hex($content[$i]));
if(hexdec($v) == 128) {
$line++;
} else {
$imgArray[$line][] = hexdec($v);
}
}
echo "<pre>";
print_r($imgArray);
echo "</pre>";
/* METHOD 2 */
$data = unpack("c*", $content);
foreach($data as $val){
switch($val){
case -128:
$line++;
break;
default:
$imgArray[$line][] = $val;
}
}
for($i=0; $i<sizeof($imgArray); $i++){
$imgArray[$i] = array_chunk($imgArray[$i], 4);
}
echo "<pre>";
print_r($imgArray);
echo "</pre>";
I have read that Byte type is limited from -128 to 127 so I expect to get only value from -128 to 127 in my PHP code, but I get only hexadecimal value, or even char, or some large number like 4294967252
I've found that 'count' variable need a XOR to be reverted (i.e somethnig like $val ^ 0xFFFFFFC0 Also R, G, B value need to be shift back like ($val & 0xFF) << 1
Finally my question is: how to decode this .bin file who is plenty of JAVA Byte value from my PHP ?
Finally I got it ! However I'm not very happy about performance. Any idea how I could optimize my code ?
<?php
$filename = "scalio.bin";
$handle = fopen($filename, "rb");
$content = fread($handle, filesize($filename));
$line=-1;
$imgArray=array();
$arr=array("r", "g", "b");
$color=-1;
function getNextColor(){
global $arr, $color;
if($color > 1)
$color = -1;
$color++;
return $arr[$color];
}
$pix=-1;
for ($i=0; $i<strlen($content); $i++){
$buf = bin2hex($content[$i]);
$dec = hexdec($buf);
$bytes = (($dec+128)%256) -128;
if($bytes == -128){
$line++;
$pix=-1;
}elseif($bytes < 0){
$b = substr(decbin($bytes), -8);
$imgArray[$line][$pix]['count'] = (bindec($b) ^ 0xC0) + 1;
}else{
$col = getNextColor();
$b = ($bytes & 0xFF) << 1;
if($col == "r")
$pix++;
$imgArray[$line][$pix][$col] = $b;
}
}
$sizeX = 640;
$sizeY = 80;
$gd = imagecreatetruecolor($sizeX, $sizeY);
$imgArrayTrue=array();
foreach($imgArray as $lineIndex=>$line){
foreach($line as $pixelIndex=>$pixel){
if( array_key_exists('count', $pixel) ){
for($x=0; $x<$pixel['count']; $x++){
$imgArrayTrue[$lineIndex][] = array("r"=>$pixel['r'], "g"=>$pixel['g'], "b"=>$pixel['b']);
}
}else{
$imgArrayTrue[$lineIndex][] = $pixel;
}
}
}
foreach($imgArrayTrue as $lineIndex=>$line){
foreach($line as $pixelIndex=>$pixel){
$color = imagecolorallocate($gd, $pixel['r'], $pixel['g'], $pixel['b']);
imagesetpixel($gd, $pixelIndex, $lineIndex, $color);
}
}
header('Content-Type: image/gif');
imagegif($gd);
?>