There's a few ways you could do it:
- format the data as PPM as above, or perhaps raw would be better.
- use the setscanline() method to write data a scanline at a time to the image. Unfortunately this expects data in a particular format, so you'll still need to adjust the data a bit.
# untested
my $im = Imager->new(xsize=>$width, ysize=>$height);
my $per_line = $width * 4;
# adjust the data to the format setscanline() takes
$nfr =~ s/(.)(.)(.)/$3$2$1\xFF/gs;
# paint it
for my $y (0..$height-1) {
$im->setscanline(y=>$y, pixels =>
substr($nfr, $y * per_line, $per_line));
}
if performance is an issue you could use Inline::C or an XS module to reformat the data and draw it using i_plin() at the C level. Here's some Inline C code to do the job:
use Imager 0.48;
# this assumes you've created an image of the right
# size first.
# if you call it with too large an image for the data
# supplied then it will crash
use Inline C => <<'EOS' => WITH => 'Imager';
void
capture2image(Imager::ImgRaw out, unsigned char *data) {
i_color *line_buf = mymalloc(sizeof(i_color) * out->xsize);
i_color *pixelp;
int x, y;
for (y = 0; y < out->ysize; ++y) {
pixelp = line_buf;
for (x = 0; x < out->xsize; ++x) {
pixelp->rgba.b = *data++;
pixelp->rgba.g = *data++;
pixelp->rgba.r = *data++;
++pixelp;
}
i_plin(out, 0, out->xsize, y, line_buf);
}
myfree(line_buf);
}
EOS
Perhaps Imager needs a more general data to image method, but I haven't had much feedback on setscanline() and friends yet.
Edit: added the Inline C code, hard to test without video capture data though.