PDL-IO-Image
view release on metacpan or search on metacpan
void
save(PDL::IO::Image self, SV * destination, SV * f=NULL, int flags=0);
PPCODE:
{
if (self->dib) {
FIMEMORY *hmem = NULL;
BYTE *mem_buffer = NULL;
DWORD size_in_bytes = 0;
FREE_IMAGE_FORMAT fif = _sv2fif(f);
FREE_IMAGE_TYPE fit = FreeImage_GetImageType(self->dib);
if(SvROK(destination) && SvTYPE(SvRV(destination)) < SVt_PVAV) {
/* destination is a reference to scalar */
SV *output = SvRV(destination);
BYTE *output_ptr = NULL;
if (fif == FIF_UNKNOWN) croak("FAIL: unspecified format");
hmem = FreeImage_OpenMemory(NULL, 0);
if (!FreeImage_SaveToMemory(fif, self->dib, hmem, flags)) {
warn("FreeImage_SaveToMemory failed (format '%d', image type '%d')", fif, fit);
}
FreeImage_AcquireMemory(hmem, &mem_buffer, &size_in_bytes);
sv_setpvn(output, "", 0);
output_ptr = SvGROW(output, size_in_bytes);
SvCUR_set(output, size_in_bytes);
SvPOK_only(output);
Copy(mem_buffer, output_ptr, size_in_bytes, BYTE);
FreeImage_CloseMemory(hmem);
}
else {
/* destination is a filename */
STRLEN flen = 0;
char * filename = SvPV(destination, flen);
if (!filename || flen<=0) croak("FAIL: invalid filename");
if (fif == FIF_UNKNOWN) fif = FreeImage_GetFIFFromFilename(filename);
if (fif == FIF_UNKNOWN) croak("FAIL: unspecified format");
if (!FreeImage_Save(fif, self->dib, filename, flags)) {
warn("FreeImage_Save failed (format '%d', image type '%d')", fif, fit);
}
}
}
XPUSHs(ST(0)); /* return self */
}
pdl*
palette_to_pdl(PDL::IO::Image self)
CODE:
{
pdl *pal_pdl = NULL;
PDL_Indx dims[] = {0, 0, 0};
int cu = FreeImage_GetColorsUsed(self->dib);
if (cu==0) XSRETURN_UNDEF;
PDL_Byte *pdata;
int i;
dims[0] = 3;
dims[1] = cu;
pal_pdl = PDL->pdlnew();
pal_pdl->datatype = PDL_B;
PDL->setdims (pal_pdl, dims, 2);
PDL->allocdata (pal_pdl);
pdata = (PDL_Byte *) pal_pdl->data;
RGBQUAD *pal = FreeImage_GetPalette(self->dib);
for (i = 0; i < cu; i++) {
pdata[i*3] = (PDL_Byte) pal[i].rgbRed;
pdata[i*3 + 1] = (PDL_Byte) pal[i].rgbGreen;
pdata[i*3 + 2] = (PDL_Byte) pal[i].rgbBlue;
}
RETVAL = pal_pdl;
}
OUTPUT:
RETVAL
pdl*
pixels_to_pdl(PDL::IO::Image self, long x1=0, long x2=0, long y1=0, long y2=0)
CODE:
{
pdl *bmp_pdl = NULL;
PDL_Indx dims[] = {0, 0, 0};
PDL_Indx x, y, wxh;
unsigned long w, h, wp, hp;
int bpp, it;
w = FreeImage_GetWidth(self->dib);
h = FreeImage_GetHeight(self->dib);
bpp = FreeImage_GetBPP(self->dib);
it = FreeImage_GetImageType(self->dib);
wp = w;
hp = h;
if (!FreeImage_HasPixels(self->dib) || w == 0 || h == 0) {
warn("FAIL: no pixels");
XSRETURN_UNDEF;
}
/* handle negative boundaries */
if (x1 < 0) x1 = w - 1 + x1;
if (y1 < 0) y1 = h - 1 + y1;
if (x2 <= 0) x2 = w - 1 + x2;
if (y2 <= 0) y2 = h - 1 + y2;
/* handle region selection */
wp = (x2 - x1 + 1);
hp = (y2 - y1 + 1);
wxh = wp * hp;
if (x1>x2 || y1>y2 || x1<0 || y1<0 || x2<0 || y2<0 || wp>w || hp>h) {
warn("FAIL: invalid region");
XSRETURN_UNDEF;
}
switch (it) {
case FIT_BITMAP: /* Standard image: 1-, 4-, 8-, 16-, 24-, 32-bit */
if (bpp==32) {
PDL_Byte *pdata;
dims[0] = wp;
dims[1] = hp;
dims[2] = 4;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_B;
PDL->setdims (bmp_pdl, dims, 3);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Byte *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
RGBQUAD *bits = (RGBQUAD*) FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_Byte) bits[x+x1].rgbRed;
pdata[y*wp + x + wxh] = (PDL_Byte) bits[x+x1].rgbGreen;
pdata[y*wp + x + 2*wxh] = (PDL_Byte) bits[x+x1].rgbBlue;
pdata[y*wp + x + 3*wxh] = (PDL_Byte) bits[x+x1].rgbReserved;
}
}
}
else if (bpp==24) {
PDL_Byte *pdata;
dims[0] = wp;
dims[1] = hp;
dims[2] = 3;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_B;
PDL->setdims (bmp_pdl, dims, 3);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Byte *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
RGBTRIPLE *bits = (RGBTRIPLE*) FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_Byte) bits[x+x1].rgbtRed;
pdata[y*wp + x + wxh] = (PDL_Byte) bits[x+x1].rgbtGreen;
pdata[y*wp + x + 2*wxh] = (PDL_Byte) bits[x+x1].rgbtBlue;
}
}
}
else if (bpp==16) {
unsigned red_mask, green_mask, blue_mask;
PDL_Byte *pdata;
dims[0] = wp;
dims[1] = hp;
dims[2] = 3;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_B;
PDL->setdims (bmp_pdl, dims, 3);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Byte *) bmp_pdl->data;
red_mask = FreeImage_GetRedMask(self->dib);
green_mask = FreeImage_GetGreenMask(self->dib);
blue_mask = FreeImage_GetBlueMask(self->dib);
if ( (red_mask == FI16_565_RED_MASK) && (green_mask == FI16_565_GREEN_MASK) && (blue_mask == FI16_565_BLUE_MASK) ) {
for(y = 0; y < hp; y++) {
WORD *bits = (WORD*)FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
PDL_Byte r5 = (PDL_Byte)((bits[x+x1] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) ;
PDL_Byte g6 = (PDL_Byte)((bits[x+x1] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT);
PDL_Byte b5 = (PDL_Byte)((bits[x+x1] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) ;
/* http://stackoverflow.com/questions/2442576/how-does-one-convert-16-bit-rgb565-to-24-bit-rgb888 */
pdata[y*wp + x] = (r5 << 3) | (r5 >> 2);
pdata[y*wp + x + wxh] = (g6 << 2) | (g6 >> 4);
pdata[y*wp + x + 2*wxh] = (b5 << 3) | (b5 >> 2);
}
}
}
else {
for(y = 0; y < hp; y++) {
WORD *bits = (WORD*)FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
PDL_Byte r5 = (PDL_Byte)((bits[x+x1] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) ;
PDL_Byte g5 = (PDL_Byte)((bits[x+x1] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT);
PDL_Byte b5 = (PDL_Byte)((bits[x+x1] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) ;
pdata[y*wp + x] = (r5 << 3) | (r5 >> 2);
pdata[y*wp + x + wxh] = (g5 << 3) | (g5 >> 2);
pdata[y*wp + x + 2*wxh] = (b5 << 3) | (b5 >> 2);
}
}
}
}
else if (bpp==8) {
PDL_Byte *pdata;
dims[0] = wp;
dims[1] = hp;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_B;
PDL->setdims (bmp_pdl, dims, 2);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Byte *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
BYTE *bits = FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_Byte) bits[x+x1];
}
}
}
else if (bpp==4) {
PDL_Byte *pdata;
dims[0] = wp;
dims[1] = hp;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_B;
PDL->setdims (bmp_pdl, dims, 2);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Byte *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
BYTE *bits = FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_Byte) ((bits[(x+x1)/2] >> 4*(1-(x+x1)%2)) & 0x0F);
}
}
}
else if (bpp==1) {
PDL_Byte *pdata;
dims[0] = wp;
dims[1] = hp;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_B;
PDL->setdims (bmp_pdl, dims, 2);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Byte *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
BYTE *bits = FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_Byte) ((bits[(x+x1)/8] >> (7-(x+x1)%8)) & 0x01);
}
}
}
else {
warn("FAIL: unknown bits per pixel '%d'", bpp);
}
break;
case FIT_UINT16: /* Array of unsigned short: unsigned 16-bit */
{
PDL_Ushort *pdata;
dims[0] = wp;
dims[1] = hp;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_US;
PDL->setdims (bmp_pdl, dims, 2);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Ushort *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
PDL_Ushort *bits = (PDL_Ushort*)FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = bits[x+x1];
}
}
}
break;
case FIT_INT16: /* Array of short: signed 16-bit */
{
PDL_Short *pdata;
dims[0] = wp;
dims[1] = hp;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_S;
PDL->setdims (bmp_pdl, dims, 2);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Short *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
PDL_Short *bits = (PDL_Short*)FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = bits[x+x1];
}
}
}
break;
case FIT_UINT32: /* Array of unsigned long: unsigned 32-bit */
{ /* XXX hack: using INT64 for UINT32 */
PDL_LongLong *pdata;
dims[0] = wp;
dims[1] = hp;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_LL;
PDL->setdims (bmp_pdl, dims, 2);
PDL->allocdata (bmp_pdl);
pdata = (PDL_LongLong *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
DWORD *bits = (DWORD*)FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_LongLong)bits[x+x1];
}
}
}
break;
case FIT_INT32: /* Array of long: signed 32-bit */
{
PDL_Long *pdata;
dims[0] = wp;
dims[1] = hp;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_L;
PDL->setdims (bmp_pdl, dims, 2);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Long *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
PDL_Long *bits = (PDL_Long*)FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = bits[x+x1];
}
}
}
break;
case FIT_FLOAT: /* Array of float: 32-bit IEEE floating point */
{
PDL_Float *pdata;
dims[0] = wp;
dims[1] = hp;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_F;
PDL->setdims (bmp_pdl, dims, 2);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Float *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
PDL_Float *bits = (PDL_Float*)FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = bits[x+x1];
}
}
}
break;
case FIT_DOUBLE: /* Array of double: 64-bit IEEE floating point */
{
PDL_Double *pdata;
dims[0] = wp;
dims[1] = hp;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_D;
PDL->setdims (bmp_pdl, dims, 2);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Double *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
PDL_Double *bits = (PDL_Double*)FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = bits[x+x1];
}
}
}
break;
case FIT_COMPLEX: /* Array of FICOMPLEX: 2 x 64-bit IEEE floating point */
warn("FAIL: FIT_COMPLEX not supported");
/* for(y = 0; y < hp; y++) {
* FICOMPLEX *bits = (FICOMPLEX *)FreeImage_GetScanLine(self->dib, h-y-1-y1);
* for(x = 0; x < wp; x++) {
* pdata[y*wp + x] = (PDL_Double) bits[x+x1].r;
* pdata[y*wp + x] = (PDL_Double) bits[x+x1].i;
* }
* }
*/
break;
case FIT_RGB16: /* 48-bit RGB image: 3 x 16-bit */
{
PDL_Ushort *pdata;
dims[0] = wp;
dims[1] = hp;
dims[2] = 3;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_US;
PDL->setdims (bmp_pdl, dims, 3);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Ushort *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
FIRGB16 *bits = (FIRGB16*) FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_Ushort) bits[x+x1].red;
pdata[y*wp + x + wxh] = (PDL_Ushort) bits[x+x1].green;
pdata[y*wp + x + 2*wxh] = (PDL_Ushort) bits[x+x1].blue;
}
}
}
break;
case FIT_RGBA16: /* 64-bit RGBA image: 4 x 16-bit */
{
PDL_Ushort *pdata;
dims[0] = wp;
dims[1] = hp;
dims[2] = 4;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_US;
PDL->setdims (bmp_pdl, dims, 3);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Ushort *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
FIRGBA16 *bits = (FIRGBA16*) FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_Ushort) bits[x+x1].red;
pdata[y*wp + x + wxh] = (PDL_Ushort) bits[x+x1].green;
pdata[y*wp + x + 2*wxh] = (PDL_Ushort) bits[x+x1].blue;
pdata[y*wp + x + 3*wxh] = (PDL_Ushort) bits[x+x1].alpha;
}
}
}
break;
case FIT_RGBF: /* 96-bit RGB float image: 3 x 32-bit IEEE floating point */
{
PDL_Float *pdata;
dims[0] = wp;
dims[1] = hp;
dims[2] = 3;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_F;
PDL->setdims (bmp_pdl, dims, 3);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Float *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
FIRGBF *bits = (FIRGBF*) FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_Float) bits[x+x1].red;
pdata[y*wp + x + wxh] = (PDL_Float) bits[x+x1].green;
pdata[y*wp + x + 2*wxh] = (PDL_Float) bits[x+x1].blue;
}
}
}
break;
case FIT_RGBAF: /* 128-bit RGBA float image: 4 x 32-bit IEEE floating point */
{
PDL_Float *pdata;
dims[0] = wp;
dims[1] = hp;
dims[2] = 4;
bmp_pdl = PDL->pdlnew();
bmp_pdl->datatype = PDL_F;
PDL->setdims (bmp_pdl, dims, 3);
PDL->allocdata (bmp_pdl);
pdata = (PDL_Float *) bmp_pdl->data;
for(y = 0; y < hp; y++) {
FIRGBAF *bits = (FIRGBAF*) FreeImage_GetScanLine(self->dib, h-y-1-y1);
for(x = 0; x < wp; x++) {
pdata[y*wp + x] = (PDL_Float) bits[x+x1].red;
pdata[y*wp + x + wxh] = (PDL_Float) bits[x+x1].green;
pdata[y*wp + x + 2*wxh] = (PDL_Float) bits[x+x1].blue;
pdata[y*wp + x + 3*wxh] = (PDL_Float) bits[x+x1].alpha;
}
}
}
break;
default:
warn("FAIL: unknown image type '%d'", it);
break;
}
if (bmp_pdl == NULL) XSRETURN_UNDEF;
RETVAL = bmp_pdl;
}
OUTPUT:
RETVAL
void
DESTROY(PDL::IO::Image self)
CODE:
if (self->dib != NULL) FreeImage_Unload(self->dib);
Safefree(self);
ENDXS
############################################################### PM part
pp_bless('PDL');
pp_add_exported('wimage');
pp_add_exported('rimage');
pp_addpm( <<'ENDPM' );
use strict;
use warnings;
use Carp;
#XXX FIXME probably OK for now
{
no strict 'refs';
*{'PDL::wimage'} = \&PDL::IO::Image::wimage;
}
sub _val2list {
return @{$_[0]} if ref $_[0] eq 'ARRAY';
return $_[0];
};
sub rimage {
my $options = ref $_[-1] eq 'HASH' ? pop : {};
my $filename = shift;
$options->{format} = "AUTO" unless defined $options->{format};
$options->{format_flag} = 0 unless defined $options->{format_flag};
$options->{page} = 0 unless defined $options->{page};
my $pimage = PDL::IO::Image->new_from_file($filename, $options->{format}, $options->{format_flag}, $options->{page});
if (my $flip = $options->{flip}) {
( run in 1.803 second using v1.01-cache-2.11-cpan-39bf76dae61 )