Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/Parser/Command/PrintRasterBitImageCmd.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,55 @@ public function asPng()
{
// Just a format conversion PBM -> PNG
$pbmBlob = $this -> asPbm();
if (!class_exists(Imagick::class)) {
return $this->asPngUsingGD($pbmBlob);
}

$im = new Imagick();
$im -> readImageBlob($pbmBlob, 'pbm');
$im->setResourceLimit(6, 1); // Prevent libgomp1 segfaults, grumble grumble.
$im -> setFormat('png');
return $im -> getImageBlob();
}

private function asPngUsingGD($pbmBlob) {
$fp = fopen("php://memory", "r+");
fwrite($fp, $pbmBlob);
rewind($fp);

$header = trim(fgets($fp));
do {
$pos = ftell($fp);
$line = trim(fgets($fp));
} while ($line !== false && str_starts_with($line, "#"));
fseek($fp, $pos);

[$width, $height] = array_map("intval", preg_split('/\s+/', trim(fgets($fp))));
$img = imagecreatetruecolor($width, $height);
imagefilledrectangle($img, 0, 0, $width, $height, imagecolorallocate($img, 255, 255, 255));

$black = imagecolorallocate($img, 0, 0, 0);
$rowBytes = (int)ceil($width / 8);
for ($y = 0; $y < $height; $y++) {
$row = fread($fp, $rowBytes);
$bits = unpack("C*", $row);
$x = 0;
foreach ($bits as $byte) {
for ($bit = 7; $bit >= 0; $bit--) {
if ($x >= $width) break;
$val = ($byte >> $bit) & 1;
if ($val === 1) {
imagesetpixel($img, $x, $y, $black);
}
$x++;
}
}
}

fclose($fp);
ob_start();
imagepng($img);
imagedestroy($img);
return ob_get_clean();
}
}
95 changes: 91 additions & 4 deletions src/Parser/Command/SelectBitImageModeCmd.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,21 @@ public function getWidth()
{
return $this -> width;
}

protected function asReflectedPbm()
{
// Gemerate a PBM image from the source data. If we add a PBM header to the column
// format ESC/POS data with the width and height swapped, then we get a valid PBM, with
// the image reflected diagonally compared with the original.
return "P4\n" . $this -> getHeight() . " " . $this -> getWidth() . "\n" . $this -> data;
}

public function asPbm()
{
if (!class_exists(Imagick::class)) {
return $this->asPbmUsingGD($this -> asReflectedPbm());
}

// Reflect image diagonally from internally generated PBM
$pbmBlob = $this -> asReflectedPbm();
$im = new Imagick();
Expand All @@ -73,15 +77,98 @@ public function asPbm()
$im -> flopImage();
return $im -> getImageBlob();
}

public function asPng()
{
if (!class_exists(Imagick::class)) {
return $this->asPngUsingGD($this -> asReflectedPbm());
}

// Just a format conversion PBM -> PNG
$pbmBlob = $this -> asPbm();
$im = new Imagick();
$im -> readImageBlob($pbmBlob, 'pbm');
$im->setResourceLimit(6, 1); // Prevent libgomp1 segfaults, grumble grumble.
$im->setResourceLimit(6, 1); // Prevent libgomp1 segfaults, grumble grumble.
$im -> setFormat('png');
return $im -> getImageBlob();
}

private function asPbmUsingGD($pbmBlob)
{
$image = $this->createImageFromPBMUsingGd($pbmBlob);
if (!$image) {
throw new \Exception("No se pudo crear la imagen GD desde PBM");
}

$image = imagerotate($image, -90, 0);
$width = imagesx($image);
$height = imagesy($image);
$flipped = imagecreatetruecolor($width, $height);
imagecopyresampled($flipped, $image, 0, 0, $width - 1, 0, $width, $height, -$width, $height);
imagedestroy($image);

ob_start();
imagegd2($flipped);
$pngData = ob_get_clean();
imagedestroy($flipped);

return $pngData;
}

private function asPngUsingGD($pbmBlob)
{
$image = $this->createImageFromPBMUsingGd($pbmBlob);
if (!$image) {
throw new \Exception("No se pudo crear la imagen GD desde PBM");
}

$image = imagerotate($image, -90, 0);
$width = imagesx($image);
$height = imagesy($image);
$flipped = imagecreatetruecolor($width, $height);
imagecopyresampled($flipped, $image, 0, 0, $width - 1, 0, $width, $height, -$width, $height);
imagedestroy($image);

ob_start();
imagepng($flipped);
$pngData = ob_get_clean();
imagedestroy($flipped);

return $pngData;
}

private function createImageFromPBMUsingGd(string $pbmBlob)
{
$lines = preg_split('/\s+/', trim($pbmBlob));
if (count($lines) < 3 || $lines[0] !== 'P4') {
return null;
}

$width = (int) $lines[1];
$height = (int) $lines[2];
$headerEnd = strpos($pbmBlob, "\n", strpos($pbmBlob, $height) + strlen($height)) + 1;
$bitmapData = substr($pbmBlob, $headerEnd);

$img = imagecreatetruecolor($width, $height);
$white = imagecolorallocate($img, 255, 255, 255);
$black = imagecolorallocate($img, 0, 0, 0);
imagefill($img, 0, 0, $white);

$rowBytes = (int) ceil($width / 8);
$offset = 0;

for ($y = 0; $y < $height; $y++) {
$row = substr($bitmapData, $offset, $rowBytes);
$offset += $rowBytes;

for ($x = 0; $x < $width; $x++) {
$byteIndex = intdiv($x, 8);
$bitIndex = 7 - ($x % 8);
$bit = (ord($row[$byteIndex]) >> $bitIndex) & 1;
imagesetpixel($img, $x, $y, $bit ? $black : $white);
}
}

return $img;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,55 @@ public function asPbm()
public function asPng()
{
$pbmBlob = $this -> asPbm();
if (!class_exists(Imagick::class)) {
return $this->asPngUsingGD($pbmBlob);
}

$im = new Imagick();
$im -> readImageBlob($pbmBlob, 'pbm');
$im->setResourceLimit(6, 1); // Prevent libgomp1 segfaults, grumble grumble.
$im -> setFormat('png');
return $im -> getImageBlob();
}

private function asPngUsingGD($pbmBlob) {
$fp = fopen("php://memory", "r+");
fwrite($fp, $pbmBlob);
rewind($fp);

$header = trim(fgets($fp));
do {
$pos = ftell($fp);
$line = trim(fgets($fp));
} while ($line !== false && str_starts_with($line, "#"));
fseek($fp, $pos);

[$width, $height] = array_map("intval", preg_split('/\s+/', trim(fgets($fp))));
$img = imagecreatetruecolor($width, $height);
imagefilledrectangle($img, 0, 0, $width, $height, imagecolorallocate($img, 255, 255, 255));

$black = imagecolorallocate($img, 0, 0, 0);
$rowBytes = (int)ceil($width / 8);
for ($y = 0; $y < $height; $y++) {
$row = fread($fp, $rowBytes);
$bits = unpack("C*", $row);
$x = 0;
foreach ($bits as $byte) {
for ($bit = 7; $bit >= 0; $bit--) {
if ($x >= $width) break;
$val = ($byte >> $bit) & 1;
if ($val === 1) {
imagesetpixel($img, $x, $y, $black);
}
$x++;
}
}
}

fclose($fp);
ob_start();
imagepng($img);
imagedestroy($img);
return ob_get_clean();
}
}