The best way to get a map of all image pixels using GD

The following code uses the SimpleImage library

I have a function that gets a pixel from an image:

function getPixel($x, $y) { $colors = imagecolorsforindex($this->image, imagecolorat($this->image, $x, $y)); $n[0] = $colors['red']; $n[1] = $colors['green']; $n[2] = $colors['blue']; $str = "#"; for($x=0;$x < 3; $x++){ $n[$x] = intval($n[$x],10); if (is_nan($n[$x])) return "00"; $n[$x] = max(0, min($n[$x],255)); $bam = "0123456789ABCDEF"; $str .= $bam{($n[$x]-$n[$x]%16)/16} . $bam{$n[$x]%16}; } return $str; } 

To get every pixel in the image, I use this loop:

 $arr = []; for($y = 0;$y < $image->getHeight(); $y++){ $arr[$y] = []; for($x = 0; $x < $image->getWidth(); $x++){ $arr[$y][$x] = $image->getPixel($x, $y); } } 

I am wondering if there is a faster way to do this using GD and PHP?

EDIT

What I'm thinking of is a way to get the value of each pixel from GD without a PHP loop.

+7
source share
2 answers

This is an ugly brute force method using imagecolorat () on every pixel. In my tests with large (6.5Mpixel) images, it is about 3.6 seconds, or about 1.1 seconds faster than the more elegant GD hack offered by @cleong. It also has the advantage of brutal simplicity and independence from the undocumented GD2 internal format.

 $alphaLookup = array( 0x00000000=>"\xff",0x01000000=>"\xfd",0x02000000=>"\xfb",0x03000000=>"\xf9", 0x04000000=>"\xf7",0x05000000=>"\xf5",0x06000000=>"\xf3",0x07000000=>"\xf1", 0x08000000=>"\xef",0x09000000=>"\xed",0x0a000000=>"\xeb",0x0b000000=>"\xe9", 0x0c000000=>"\xe7",0x0d000000=>"\xe5",0x0e000000=>"\xe3",0x0f000000=>"\xe1", 0x10000000=>"\xdf",0x11000000=>"\xdd",0x12000000=>"\xdb",0x13000000=>"\xd9", 0x14000000=>"\xd7",0x15000000=>"\xd5",0x16000000=>"\xd3",0x17000000=>"\xd1", 0x18000000=>"\xcf",0x19000000=>"\xcd",0x1a000000=>"\xcb",0x1b000000=>"\xc9", 0x1c000000=>"\xc7",0x1d000000=>"\xc5",0x1e000000=>"\xc3",0x1f000000=>"\xc1", 0x20000000=>"\xbf",0x21000000=>"\xbd",0x22000000=>"\xbb",0x23000000=>"\xb9", 0x24000000=>"\xb7",0x25000000=>"\xb5",0x26000000=>"\xb3",0x27000000=>"\xb1", 0x28000000=>"\xaf",0x29000000=>"\xad",0x2a000000=>"\xab",0x2b000000=>"\xa9", 0x2c000000=>"\xa7",0x2d000000=>"\xa5",0x2e000000=>"\xa3",0x2f000000=>"\xa1", 0x30000000=>"\x9f",0x31000000=>"\x9d",0x32000000=>"\x9b",0x33000000=>"\x99", 0x34000000=>"\x97",0x35000000=>"\x95",0x36000000=>"\x93",0x37000000=>"\x91", 0x38000000=>"\x8f",0x39000000=>"\x8d",0x3a000000=>"\x8b",0x3b000000=>"\x89", 0x3c000000=>"\x87",0x3d000000=>"\x85",0x3e000000=>"\x83",0x3f000000=>"\x81", 0x40000000=>"\x7f",0x41000000=>"\x7d",0x42000000=>"\x7b",0x43000000=>"\x79", 0x44000000=>"\x77",0x45000000=>"\x75",0x46000000=>"\x73",0x47000000=>"\x71", 0x48000000=>"\x6f",0x49000000=>"\x6d",0x4a000000=>"\x6b",0x4b000000=>"\x69", 0x4c000000=>"\x67",0x4d000000=>"\x65",0x4e000000=>"\x63",0x4f000000=>"\x61", 0x50000000=>"\x5f",0x51000000=>"\x5d",0x52000000=>"\x5b",0x53000000=>"\x59", 0x54000000=>"\x57",0x55000000=>"\x55",0x56000000=>"\x53",0x57000000=>"\x51", 0x58000000=>"\x4f",0x59000000=>"\x4d",0x5a000000=>"\x4b",0x5b000000=>"\x49", 0x5c000000=>"\x47",0x5d000000=>"\x45",0x5e000000=>"\x43",0x5f000000=>"\x41", 0x60000000=>"\x3f",0x61000000=>"\x3d",0x62000000=>"\x3b",0x63000000=>"\x39", 0x64000000=>"\x37",0x65000000=>"\x35",0x66000000=>"\x33",0x67000000=>"\x31", 0x68000000=>"\x2f",0x69000000=>"\x2d",0x6a000000=>"\x2b",0x6b000000=>"\x29", 0x6c000000=>"\x27",0x6d000000=>"\x25",0x6e000000=>"\x23",0x6f000000=>"\x21", 0x70000000=>"\x1f",0x71000000=>"\x1d",0x72000000=>"\x1b",0x73000000=>"\x19", 0x74000000=>"\x17",0x75000000=>"\x15",0x76000000=>"\x13",0x77000000=>"\x11", 0x78000000=>"\x0f",0x79000000=>"\x0d",0x7a000000=>"\x0b",0x7b000000=>"\x09", 0x7c000000=>"\x07",0x7d000000=>"\x05",0x7e000000=>"\x03",0x7f000000=>"\x00" ); // Lookup table for chr(255-(($x >> 23) & 0x7f)). $chr = array( "\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07","\x08","\x09","\x0A","\x0B","\x0C","\x0D","\x0E","\x0F", "\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17","\x18","\x19","\x1A","\x1B","\x1C","\x1D","\x1E","\x1F", "\x20","\x21","\x22","\x23","\x24","\x25","\x26","\x27","\x28","\x29","\x2A","\x2B","\x2C","\x2D","\x2E","\x2F", "\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\x3A","\x3B","\x3C","\x3D","\x3E","\x3F", "\x40","\x41","\x42","\x43","\x44","\x45","\x46","\x47","\x48","\x49","\x4A","\x4B","\x4C","\x4D","\x4E","\x4F", "\x50","\x51","\x52","\x53","\x54","\x55","\x56","\x57","\x58","\x59","\x5A","\x5B","\x5C","\x5D","\x5E","\x5F", "\x60","\x61","\x62","\x63","\x64","\x65","\x66","\x67","\x68","\x69","\x6A","\x6B","\x6C","\x6D","\x6E","\x6F", "\x70","\x71","\x72","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7A","\x7B","\x7C","\x7D","\x7E","\x7F", "\x80","\x81","\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x8A","\x8B","\x8C","\x8D","\x8E","\x8F", "\x90","\x91","\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\x9A","\x9B","\x9C","\x9D","\x9E","\x9F", "\xA0","\xA1","\xA2","\xA3","\xA4","\xA5","\xA6","\xA7","\xA8","\xA9","\xAA","\xAB","\xAC","\xAD","\xAE","\xAF", "\xB0","\xB1","\xB2","\xB3","\xB4","\xB5","\xB6","\xB7","\xB8","\xB9","\xBA","\xBB","\xBC","\xBD","\xBE","\xBF", "\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6","\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE","\xCF", "\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6","\xD7","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE","\xDF", "\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6","\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE","\xEF", "\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6","\xF7","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE","\xFF", ); // Lookup for chr($x): much faster. function lookUpImageBytes($canvas) { global $alphaLookup, $chr; $imageWidth = imagesx($canvas); $imageHeight = imagesy($canvas); // Faster than append, and >500mb more memory efficient for a 6.5MPx image! $imageData = str_repeat("\x00\x00\x00\x00", $imageWidth * $imageHeight); // Loop over each single pixel. $j = 0; for ($y = 0; $y < $imageHeight; $y++) { for ($x = 0; $x < $imageWidth; $x++) { // Grab the pixel data. $argb = imagecolorat($canvas, $x, $y); $imageData[$j++] = $alphaLookup[$argb & 0x7f000000]; // A (convert from GD). // NB: three $chr arrays to replace the shifts WON'T improve speed. $imageData[$j++] = $chr[($argb >> 16) & 0xFF]; // R $imageData[$j++] = $chr[($argb >> 8) & 0xFF]; // G $imageData[$j++] = $chr[$argb & 0xFF]; // B } } return $imageData; } 
+3
source

There is a faster way, but it is very difficult. It includes exporting the image to GD2 format, and then direct access to bytes. GD stores pixels in pieces, so the loop through the pixels is not straight. When done correctly, this gives a much better performance, since you no longer impose the overhead of calling the function on each pixel.

Here is the code that I have that I wrote that captures the alpha channel from the image. As you can see, the loop is not so terribly obvious due to chunking:

  imagesavealpha($image, true); ob_start(); imagegd2($image); $gdRawData = ob_get_clean(); $array = unpack("Nheader/nversion/nimageWidth/nimageHeight/nchunkSize/ndataFormat/ncolumnCount/nrowCount", $gdRawData); $imageWidth = $array['imageWidth']; $imageHeight = $array['imageHeight']; $chunkWidth = $chunkHeight = $array['chunkSize']; $columnCount = $array['columnCount']; $rowCount = $array['rowCount']; $lastColumnWidth = $imageWidth - ($columnCount - 1) * $chunkWidth; $lastRowHeight = $imageHeight - ($rowCount - 1) * $chunkHeight; static $transparencyToAlpha = array("\x7f" => "\x00", "\x7f" => "\x01", "\x7e" => "\x02", "\x7e" => "\x03", "\x7d" => "\x04", "\x7d" => "\x05", "\x7c" => "\x06", "\x7c" => "\x07", "\x7b" => "\x08", "\x7b" => "\x09", "\x7a" => "\x0a", "\x7a" => "\x0b", "\x79" => "\x0c", "\x79" => "\x0d", "\x78" => "\x0e", "\x78" => "\x0f", "\x77" => "\x10", "\x77" => "\x11", "\x76" => "\x12", "\x76" => "\x13", "\x75" => "\x14", "\x75" => "\x15", "\x74" => "\x16", "\x74" => "\x17", "\x73" => "\x18", "\x73" => "\x19", "\x72" => "\x1a", "\x72" => "\x1b", "\x71" => "\x1c", "\x71" => "\x1d", "\x70" => "\x1e", "\x70" => "\x1f", "\x6f" => "\x20", "\x6f" => "\x21", "\x6e" => "\x22", "\x6e" => "\x23", "\x6d" => "\x24", "\x6d" => "\x25", "\x6c" => "\x26", "\x6c" => "\x27", "\x6b" => "\x28", "\x6b" => "\x29", "\x6a" => "\x2a", "\x6a" => "\x2b", "\x69" => "\x2c", "\x69" => "\x2d", "\x68" => "\x2e", "\x68" => "\x2f", "\x67" => "\x30", "\x67" => "\x31", "\x66" => "\x32", "\x66" => "\x33", "\x65" => "\x34", "\x65" => "\x35", "\x64" => "\x36", "\x64" => "\x37", "\x63" => "\x38", "\x63" => "\x39", "\x62" => "\x3a", "\x62" => "\x3b", "\x61" => "\x3c", "\x61" => "\x3d", "\x60" => "\x3e", "\x60" => "\x3f", "\x5f" => "\x40", "\x5f" => "\x41", "\x5e" => "\x42", "\x5e" => "\x43", "\x5d" => "\x44", "\x5d" => "\x45", "\x5c" => "\x46", "\x5c" => "\x47", "\x5b" => "\x48", "\x5b" => "\x49", "\x5a" => "\x4a", "\x5a" => "\x4b", "\x59" => "\x4c", "\x59" => "\x4d", "\x58" => "\x4e", "\x58" => "\x4f", "\x57" => "\x50", "\x57" => "\x51", "\x56" => "\x52", "\x56" => "\x53", "\x55" => "\x54", "\x55" => "\x55", "\x54" => "\x56", "\x54" => "\x57", "\x53" => "\x58", "\x53" => "\x59", "\x52" => "\x5a", "\x52" => "\x5b", "\x51" => "\x5c", "\x51" => "\x5d", "\x50" => "\x5e", "\x50" => "\x5f", "\x4f" => "\x60", "\x4f" => "\x61", "\x4e" => "\x62", "\x4e" => "\x63", "\x4d" => "\x64", "\x4d" => "\x65", "\x4c" => "\x66", "\x4c" => "\x67", "\x4b" => "\x68", "\x4b" => "\x69", "\x4a" => "\x6a", "\x4a" => "\x6b", "\x49" => "\x6c", "\x49" => "\x6d", "\x48" => "\x6e", "\x48" => "\x6f", "\x47" => "\x70", "\x47" => "\x71", "\x46" => "\x72", "\x46" => "\x73", "\x45" => "\x74", "\x45" => "\x75", "\x44" => "\x76", "\x44" => "\x77", "\x43" => "\x78", "\x43" => "\x79", "\x42" => "\x7a", "\x42" => "\x7b", "\x41" => "\x7c", "\x41" => "\x7d", "\x40" => "\x7e", "\x40" => "\x7f", "\x3f" => "\x80", "\x3f" => "\x81", "\x3e" => "\x82", "\x3e" => "\x83", "\x3d" => "\x84", "\x3d" => "\x85", "\x3c" => "\x86", "\x3c" => "\x87", "\x3b" => "\x88", "\x3b" => "\x89", "\x3a" => "\x8a", "\x3a" => "\x8b", "\x39" => "\x8c", "\x39" => "\x8d", "\x38" => "\x8e", "\x38" => "\x8f", "\x37" => "\x90", "\x37" => "\x91", "\x36" => "\x92", "\x36" => "\x93", "\x35" => "\x94", "\x35" => "\x95", "\x34" => "\x96", "\x34" => "\x97", "\x33" => "\x98", "\x33" => "\x99", "\x32" => "\x9a", "\x32" => "\x9b", "\x31" => "\x9c", "\x31" => "\x9d", "\x30" => "\x9e", "\x30" => "\x9f", "\x2f" => "\xa0", "\x2f" => "\xa1", "\x2e" => "\xa2", "\x2e" => "\xa3", "\x2d" => "\xa4", "\x2d" => "\xa5", "\x2c" => "\xa6", "\x2c" => "\xa7", "\x2b" => "\xa8", "\x2b" => "\xa9", "\x2a" => "\xaa", "\x2a" => "\xab", "\x29" => "\xac", "\x29" => "\xad", "\x28" => "\xae", "\x28" => "\xaf", "\x27" => "\xb0", "\x27" => "\xb1", "\x26" => "\xb2", "\x26" => "\xb3", "\x25" => "\xb4", "\x25" => "\xb5", "\x24" => "\xb6", "\x24" => "\xb7", "\x23" => "\xb8", "\x23" => "\xb9", "\x22" => "\xba", "\x22" => "\xbb", "\x21" => "\xbc", "\x21" => "\xbd", "\x20" => "\xbe", "\x20" => "\xbf", "\x1f" => "\xc0", "\x1f" => "\xc1", "\x1e" => "\xc2", "\x1e" => "\xc3", "\x1d" => "\xc4", "\x1d" => "\xc5", "\x1c" => "\xc6", "\x1c" => "\xc7", "\x1b" => "\xc8", "\x1b" => "\xc9", "\x1a" => "\xca", "\x1a" => "\xcb", "\x19" => "\xcc", "\x19" => "\xcd", "\x18" => "\xce", "\x18" => "\xcf", "\x17" => "\xd0", "\x17" => "\xd1", "\x16" => "\xd2", "\x16" => "\xd3", "\x15" => "\xd4", "\x15" => "\xd5", "\x14" => "\xd6", "\x14" => "\xd7", "\x13" => "\xd8", "\x13" => "\xd9", "\x12" => "\xda", "\x12" => "\xdb", "\x11" => "\xdc", "\x11" => "\xdd", "\x10" => "\xde", "\x10" => "\xdf", "\x0f" => "\xe0", "\x0f" => "\xe1", "\x0e" => "\xe2", "\x0e" => "\xe3", "\x0d" => "\xe4", "\x0d" => "\xe5", "\x0c" => "\xe6", "\x0c" => "\xe7", "\x0b" => "\xe8", "\x0b" => "\xe9", "\x0a" => "\xea", "\x0a" => "\xeb", "\x09" => "\xec", "\x09" => "\xed", "\x08" => "\xee", "\x08" => "\xef", "\x07" => "\xf0", "\x07" => "\xf1", "\x06" => "\xf2", "\x06" => "\xf3", "\x05" => "\xf4", "\x05" => "\xf5", "\x04" => "\xf6", "\x04" => "\xf7", "\x03" => "\xf8", "\x03" => "\xf9", "\x02" => "\xfa", "\x02" => "\xfb", "\x01" => "\xfc", "\x01" => "\xfd", "\x00" => "\xfe", "\x00" => "\xff"); $alphaDataSize = $imageWidth * $imageHeight; $alphaData = str_repeat("\x00", $alphaDataSize); // loop through all rows for($r = 0, $j = 23; $r < $rowCount; $r++) { $rowHeight = ($r == $rowCount - 1) ? $lastRowHeight : $chunkHeight; // loop through chunks in each row for($c = 0; $c < $columnCount; $c++) { $columnWidth = ($c == $columnCount - 1) ? $lastColumnWidth : $chunkWidth; $firstY = $r * $chunkHeight; $lastY = $firstY + $rowHeight; // loop through scanlines in each chunk for($y = $firstY; $y < $lastY; $y++) { $firstX = $c * $chunkWidth; $firstAlphaPosition = $y * $imageWidth + $firstX; $lastAlphaPosition = $firstAlphaPosition + $columnWidth; // loop through each pixel in each chunk scanline for($i = $firstAlphaPosition; $i < $lastAlphaPosition; $i++, $j+= 4) { $alphaData[$i] = $transparencyToAlpha[$gdRawData[$j]]; } } } } 

Each pixel consists of four bytes: alpha, red, green and blue. Here I just commit the first byte.

+2
source

All Articles