Better way to get map of all pixels of an image with GD

╄→尐↘猪︶ㄣ 提交于 2019-12-09 11:33:09

问题


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 an 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'm wondering if there is a faster way to do this with GD and PHP?

EDIT

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


回答1:


This is the ugly brute-force method, using imagecolorat() on every pixel. In my tests with large (6.5Mpixel) images, it's about 3.6sec, or about 1.1sec faster than the more elegant GD hack proposed by @cleong. It also has the advantage of brutal simplicity, and independence from the undocumented internal GD2 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;
}



回答2:


There is a faster way, but it's very tricky. What it involves is exporting the image to the GD2 format, then accessing the bytes directly. GD stores the pixels in chunks, so looping through the pixels is not straight forward. When done properly, it does yield much better performance since you're no longer incurring the overhead of calling a function on every pixel.

Here's some code that I have that I had written which capture the alpha channel from an image. As you can see, the loop isn't so terribly obvious because of 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'm only capturing the first byte.



来源:https://stackoverflow.com/questions/13791207/better-way-to-get-map-of-all-pixels-of-an-image-with-gd

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!