sapbucket
asked on
PERL: Don't understand the "Variant" type returned by COM objects
Hello,
VB6 has great built in support for the Variant type, for example:
Private Sub cmdStart_Click()
Dim ImageData As Variant
Dim x As Integer, y As Integer
ICImagingControl1.MemorySn apImage
ImageData = ICImagingControl1.MemoryGe tImageData
For y = 0 To ICImagingControl1.ImageHei ght - 1
For x = 0 To ICImagingControl1.ImageWid th - 1
ImageData(x, y) = 255 - ImageData(x, y) '!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!
Next x
Next y
ICImagingControl1.MemoryRe leaseImage Data ImageData
ICImagingControl1.Display
End Sub
I would like to perform the same thing as above (esp. '!!!!!!!!!!!!!!!!!!!!!!!!) but using PERL.
I have a testscript:
#!/usr/bin/perl -w
#use strict;
use Win32::GUI;
use Win32::GUI::DIBitmap;
use Win32::OLE::Variant;
use Win32::OLE;
$imaging = Win32::OLE->new('IC.ICImag ingControl ') or die "oops\n";
#------------------------- -------
# Use the Dialog to get settings:
# If we want to change settings we need to use the dialog and and save
# the state so we can load from file.
#$imaging->ShowDeviceSetti ngsDialog( );
#$imaging->SaveDeviceState ToFile("c: \\ocr\\dev ice_state. xml");
#------------------------- -------
$imaging->LoadDeviceStateF romFile("c :\\ocr\\de vice_state .xml",1);
$imaging->MemorySnapImage( );
$dib=newFromFile Win32::GUI::DIBitmap ("c:\\ocr\\test.bmp");
print "dib is: $dib\n";
print "width / height \n";
print $dib->GetWidth(); print ", ";
print $dib->GetHeight(); print "\n";
$imagedata=$imaging->Memor yGetImageD ata(); # so, $imagedata is of type VARIANT because MemoryGetImageData() returns VARIANT type
#my $var = Variant(VT_DATE, $imagedata);
#---------------------
# And here we can process the image:
# This first method doesn't work yet. I can't figure out how to get X,Y
#
for($h=0;$h<$imaging->Imag eHeight(); $h++) {
for($w=0;$w<$imaging->Imag eWidth();$ w++) {
$imagedata->($w,$h) = 255 - $imagedata->($w,$h); # ?????????????????????????? ?????? DONT UNDERSTAND HOW TO USE VARIANT!!!!
#$imagedata->y($w) = 255 - $imagedata->y($w);
}
}
#---------------------
$imaging->MemorySaveImage( "c:\\ocr\\ test.bmp") ;
$imaging->MemoryReleaseIma geData();
So, compare the lines (??????????????) and ('!!!!!!!!!!!!!!!!!!!!!!!! !!). I don't understand how to handle the variant in the testscript (whereas I DO know how to handle it in the VB6 code because of the built in type support for VARIANT).
Can someone please show me the way?
I have been looking at use Win32::OLE::Variant; but I'm not sure how to use. All of the examples are of creating a NEW Variant, whereas I already have an existing variant to mess around with. =confusing to me
Thanks for the help!!
VB6 has great built in support for the Variant type, for example:
Private Sub cmdStart_Click()
Dim ImageData As Variant
Dim x As Integer, y As Integer
ICImagingControl1.MemorySn
ImageData = ICImagingControl1.MemoryGe
For y = 0 To ICImagingControl1.ImageHei
For x = 0 To ICImagingControl1.ImageWid
ImageData(x, y) = 255 - ImageData(x, y) '!!!!!!!!!!!!!!!!!!!!!!!!!
Next x
Next y
ICImagingControl1.MemoryRe
ICImagingControl1.Display
End Sub
I would like to perform the same thing as above (esp. '!!!!!!!!!!!!!!!!!!!!!!!!)
I have a testscript:
#!/usr/bin/perl -w
#use strict;
use Win32::GUI;
use Win32::GUI::DIBitmap;
use Win32::OLE::Variant;
use Win32::OLE;
$imaging = Win32::OLE->new('IC.ICImag
#-------------------------
# Use the Dialog to get settings:
# If we want to change settings we need to use the dialog and and save
# the state so we can load from file.
#$imaging->ShowDeviceSetti
#$imaging->SaveDeviceState
#-------------------------
$imaging->LoadDeviceStateF
$imaging->MemorySnapImage(
$dib=newFromFile Win32::GUI::DIBitmap ("c:\\ocr\\test.bmp");
print "dib is: $dib\n";
print "width / height \n";
print $dib->GetWidth(); print ", ";
print $dib->GetHeight(); print "\n";
$imagedata=$imaging->Memor
#my $var = Variant(VT_DATE, $imagedata);
#---------------------
# And here we can process the image:
# This first method doesn't work yet. I can't figure out how to get X,Y
#
for($h=0;$h<$imaging->Imag
for($w=0;$w<$imaging->Imag
$imagedata->($w,$h) = 255 - $imagedata->($w,$h); # ??????????????????????????
#$imagedata->y($w) = 255 - $imagedata->y($w);
}
}
#---------------------
$imaging->MemorySaveImage(
$imaging->MemoryReleaseIma
So, compare the lines (??????????????) and ('!!!!!!!!!!!!!!!!!!!!!!!!
Can someone please show me the way?
I have been looking at use Win32::OLE::Variant; but I'm not sure how to use. All of the examples are of creating a NEW Variant, whereas I already have an existing variant to mess around with. =confusing to me
Thanks for the help!!
ASKER
clockwatcher,
I get this error message when i try the code example u give
Can't call method "Get" on unblessed reference at testActiveX.pl line 39.
easy fix?
I get this error message when i try the code example u give
Can't call method "Get" on unblessed reference at testActiveX.pl line 39.
easy fix?
ASKER
ok, so I got a reply from the manufacture:
The VARIANT is a multi purpose data structure.
The declarations are as follows:
typedef struct tagSAFEARRAYBOUND {
unsigned long cElements;
long lLbound;
} SAFEARRAYBOUND;
typedef struct tagSAFEARRAY
{
USHORT cDims;
USHORT fFeatures;
USHORT cbElements;
USHORT cLocks;
USHORT handle;
PVOID pvData;
SAFEARRAYBOUND rgsabound[1];
} SAFEARRAY;
typedef struct tagVARIANT {
WORD vt;
unsigned short wReserved1;
unsigned short wReserved2;
unsigned short wReserved3;
SAFEARRAY FAR* parray;
} VARIANT;
This C functions shows how to access the image data:
////////////////////////// ////////// ////////// ////////// ////////// ////////// //
/*! This functions gets the variant data structure from a Visual Basic application.
In the variant structure an imagebuffer is saved.
*/
DWORD WINAPI ProcessImage( long iImageWidth, long iImageHeight, long iBitsPerPixel, VARIANT
*pImageStruct)
{
DWORD dwResult = 0;
BYTE *pImageBytes = (BYTE*)pImageStruct->parra y->pvData; // Cast directly to pointer, that
// points to the image data to get
// an easier access to the bytes of
// of the image.
ChangeFast( iImageWidth, iImageHeight, iBitsPerPixel, pImageBytes);
//AccessSinglePixels( iImageWidth, iImageHeight, iBitsPerPixel, pImageBytes);
//ChangeAllWithIndex( iImageWidth, iImageHeight, iBitsPerPixel, pImageBytes);
return dwResult;
}
And I haven't programmed in C since college. What is this mess? I thought a struct was all a programmer needed for complex data in C? Now they have more craziness?
What I would really like to get is the pointer to the image data. If I could "get my hands" on that from a PERL script I would call this problem solved!
Still not sure how to access data within a Variant from PERL.....
The VARIANT is a multi purpose data structure.
The declarations are as follows:
typedef struct tagSAFEARRAYBOUND {
unsigned long cElements;
long lLbound;
} SAFEARRAYBOUND;
typedef struct tagSAFEARRAY
{
USHORT cDims;
USHORT fFeatures;
USHORT cbElements;
USHORT cLocks;
USHORT handle;
PVOID pvData;
SAFEARRAYBOUND rgsabound[1];
} SAFEARRAY;
typedef struct tagVARIANT {
WORD vt;
unsigned short wReserved1;
unsigned short wReserved2;
unsigned short wReserved3;
SAFEARRAY FAR* parray;
} VARIANT;
This C functions shows how to access the image data:
//////////////////////////
/*! This functions gets the variant data structure from a Visual Basic application.
In the variant structure an imagebuffer is saved.
*/
DWORD WINAPI ProcessImage( long iImageWidth, long iImageHeight, long iBitsPerPixel, VARIANT
*pImageStruct)
{
DWORD dwResult = 0;
BYTE *pImageBytes = (BYTE*)pImageStruct->parra
// points to the image data to get
// an easier access to the bytes of
// of the image.
ChangeFast( iImageWidth, iImageHeight, iBitsPerPixel, pImageBytes);
//AccessSinglePixels( iImageWidth, iImageHeight, iBitsPerPixel, pImageBytes);
//ChangeAllWithIndex( iImageWidth, iImageHeight, iBitsPerPixel, pImageBytes);
return dwResult;
}
And I haven't programmed in C since college. What is this mess? I thought a struct was all a programmer needed for complex data in C? Now they have more craziness?
What I would really like to get is the pointer to the image data. If I could "get my hands" on that from a PERL script I would call this problem solved!
Still not sure how to access data within a Variant from PERL.....
ASKER
Here is my latest attempt:
#!/usr/bin/perl -w
#use strict;
use Win32::GUI;
use Win32::GUI::DIBitmap;
use Win32::OLE::Variant;
use Win32::OLE;
$imaging = Win32::OLE->new('IC.ICImag ingControl ') or die "oops\n";
#------------------------- -------
# Use the Dialog to get settings:
# If we want to change settings we need to use the dialog and and save
# the state so we can load from file.
#$imaging->ShowDeviceSetti ngsDialog( );
#$imaging->SaveDeviceState ToFile("c: \\ocr\\dev ice_state. xml");
#------------------------- -------
$imaging->LoadDeviceStateF romFile("c :\\ocr\\de vice_state .xml",1);
$imaging->MemorySnapImage( );
#------------------------- --------
# Use a DIBsect instread of the image pointer in the VARIANT (crappy patch...)
#$dib=newFromFile Win32::GUI::DIBitmap ("c:\\ocr\\test.bmp");
#print "dib is: $dib\n";
#print "width / height \n";
#print $dib->GetWidth(); print ", ";
#print $dib->GetHeight(); print "\n";
#------------------------- --------
#------------------------- --------
# Use the Variant returned by MemoryGetImageData to gain direct acces to image:
# Unfortunately, PERL doesn't have built-in Variant handling?
#$imagedata=$imaging->Memo ryGetImage Data();
my $Array = Win32::OLE::Variant->new(V T_ARRAY|VT _UI1, $imaging->MemoryGetImageDa ta()); # ^^^^^^^^^^^
for($h=0;$h<$imaging->Imag eHeight(); $h++) {
for($w=0;$w<$imaging->Imag eWidth();$ w++) {
$i=$h*$imaging->ImageWidth ()+$w; # tried with Put($w,$h,DATA) = error.
$Array->Put($i, 255 - $Array->Get($i)); #@@@@@@@@@@@@@@
}
}
#------------------------- ---------
$imaging->MemorySaveImage( "c:\\ocr\\ test.bmp") ;
$imaging->MemoryReleaseIma geData(); # used to free up memory
And you can see that I am trying to use Win32::OLE::Variant. The documentation (http://search.cpan.org/~jdb/Win32-OLE-0.17/lib/Win32/OLE/Variant.pm) demonstrates different ways of creating a NEW variant (my own, from scratch) but now how to make a NEW variant using existing Variant from function return.
Note that I HAVE to instanstiate a variant using Win32::OLE::Variant->new() , otherwise, if I try to use the variant returned by the COM object ($imaging->MemoryGetImageD ata()) I get this error:
>>> Can't call method "Get" on unblessed reference at testActiveX.pl line 39.
However, since I HAVE been instancing a Win32::OLE::Variant type, using the code from line (#^^^^^^^^^^^^), I get a new set of errors:
# using ($w,$h) at (@@@@@@@@@@@) gives:
Win32::OLE(0.1701): Win32::OLE::Variant->Get() : Wrong number of indices; dimension of SafeArray is 1 at testActive
X.pl line 40.
Use of uninitialized value in subtraction (-) at testActiveX.pl line 40.
Win32::OLE(0.1701): Win32::OLE::Variant->Put() : Wrong number of indices; dimension of SafeArray is 1 at testActive
X.pl line 40.
# using ($i) at (@@@@@@@@@@@) gives:
Use of uninitialized value in subtraction (-) at testActiveX.pl line 41.
Win32::OLE(0.1701) error 0x8002000b: "Invalid index" at testActiveX.pl line 41
eval {...} called at testActiveX.pl line 41
Win32::OLE(0.1701) error 0x8002000b: "Invalid index" at testActiveX.pl line 41
eval {...} called at testActiveX.pl line 41
Which basically indicates that I do not know how to access the Variant.
still lost in this problem...
Thanks for any help!!!
#!/usr/bin/perl -w
#use strict;
use Win32::GUI;
use Win32::GUI::DIBitmap;
use Win32::OLE::Variant;
use Win32::OLE;
$imaging = Win32::OLE->new('IC.ICImag
#-------------------------
# Use the Dialog to get settings:
# If we want to change settings we need to use the dialog and and save
# the state so we can load from file.
#$imaging->ShowDeviceSetti
#$imaging->SaveDeviceState
#-------------------------
$imaging->LoadDeviceStateF
$imaging->MemorySnapImage(
#-------------------------
# Use a DIBsect instread of the image pointer in the VARIANT (crappy patch...)
#$dib=newFromFile Win32::GUI::DIBitmap ("c:\\ocr\\test.bmp");
#print "dib is: $dib\n";
#print "width / height \n";
#print $dib->GetWidth(); print ", ";
#print $dib->GetHeight(); print "\n";
#-------------------------
#-------------------------
# Use the Variant returned by MemoryGetImageData to gain direct acces to image:
# Unfortunately, PERL doesn't have built-in Variant handling?
#$imagedata=$imaging->Memo
my $Array = Win32::OLE::Variant->new(V
for($h=0;$h<$imaging->Imag
for($w=0;$w<$imaging->Imag
$i=$h*$imaging->ImageWidth
$Array->Put($i, 255 - $Array->Get($i)); #@@@@@@@@@@@@@@
}
}
#-------------------------
$imaging->MemorySaveImage(
$imaging->MemoryReleaseIma
And you can see that I am trying to use Win32::OLE::Variant. The documentation (http://search.cpan.org/~jdb/Win32-OLE-0.17/lib/Win32/OLE/Variant.pm) demonstrates different ways of creating a NEW variant (my own, from scratch) but now how to make a NEW variant using existing Variant from function return.
Note that I HAVE to instanstiate a variant using Win32::OLE::Variant->new()
>>> Can't call method "Get" on unblessed reference at testActiveX.pl line 39.
However, since I HAVE been instancing a Win32::OLE::Variant type, using the code from line (#^^^^^^^^^^^^), I get a new set of errors:
# using ($w,$h) at (@@@@@@@@@@@) gives:
Win32::OLE(0.1701): Win32::OLE::Variant->Get()
X.pl line 40.
Use of uninitialized value in subtraction (-) at testActiveX.pl line 40.
Win32::OLE(0.1701): Win32::OLE::Variant->Put()
X.pl line 40.
# using ($i) at (@@@@@@@@@@@) gives:
Use of uninitialized value in subtraction (-) at testActiveX.pl line 41.
Win32::OLE(0.1701) error 0x8002000b: "Invalid index" at testActiveX.pl line 41
eval {...} called at testActiveX.pl line 41
Win32::OLE(0.1701) error 0x8002000b: "Invalid index" at testActiveX.pl line 41
eval {...} called at testActiveX.pl line 41
Which basically indicates that I do not know how to access the Variant.
still lost in this problem...
Thanks for any help!!!
Youre trying to pull a manure spreader with a Cadillac.
Or in E! terms, you're trying to get Deline Dion and Eminem to sing a duet.
Even if you can get the combinations to run, the results are not going to be pretty.
Perl was not designed with OLE objects in mind.
OLE was not designed with much of anything in mind.
They share almost no commonality in data structures, calling sequences, basic datatypes, or anything else.
Now in C, Microsoft provides a horrendous slew of macros, inlines, imracks, geegaws, binders, linkers, marshallers, macros, macro-macros, resources, ad-intelligibium. So in the end it's possible, oh just barely, to talk to OLE.
In Perl, it's harder.
In fact, even if you do get this cross-system calling and data passing to work, Perl was never designed for graphics manuipulation, so your explicit 255 - loop is going to run MIGHTY SLOW. Perl is really whizzy on text patterns, mighty slow on graphics.
I suggest you rething your idea, so it uses more compatible pieces.
Or in E! terms, you're trying to get Deline Dion and Eminem to sing a duet.
Even if you can get the combinations to run, the results are not going to be pretty.
Perl was not designed with OLE objects in mind.
OLE was not designed with much of anything in mind.
They share almost no commonality in data structures, calling sequences, basic datatypes, or anything else.
Now in C, Microsoft provides a horrendous slew of macros, inlines, imracks, geegaws, binders, linkers, marshallers, macros, macro-macros, resources, ad-intelligibium. So in the end it's possible, oh just barely, to talk to OLE.
In Perl, it's harder.
In fact, even if you do get this cross-system calling and data passing to work, Perl was never designed for graphics manuipulation, so your explicit 255 - loop is going to run MIGHTY SLOW. Perl is really whizzy on text patterns, mighty slow on graphics.
I suggest you rething your idea, so it uses more compatible pieces.
ASKER
I really am beginning to dislike OLE. and Microsoft.
Couldn't they be more reasonable?
Couldn't they be more reasonable?
ASKER
BTW, which language IS best for explicit graphics processing?
I'd use some compiled language, for the speed. It would also be nice if the language had a OLE interface built-in.
ASKER
That is the trick isn't it. It would seem that OLE is synonymous with $$$. Damn that paradigm.
I downloaded Ecplise IDE, which is Java. I'm not sure what support Java offers for OLE, but they must have better resources then PERL. I'm all about solutions, so if I find a JAVA one I will post the results here.
BTW, anyone else trying to complete a OLE project (that is, you were handed a third-party ActiveX control and now you need to build an app with it), DO NOT USE PERL!!!! This is for a very un-obvious reason. PERL does not have built-in support for the VARIANT data type. OLE objects sometimes return VARIANTs when you call a function or method. PERL just doesn't know how to handle them. If someone tries to tell you that PERL can't handle COM objects - that isn't true - it handles COM objects beautifully, that is, until you find yourself trying to comprehend a VARIANT. Things like manipulating WORD and EXCEL docs works very well from PERL. But wait until you need to get an array reference from a Variant....
grg99, thank you for the discussion. :)
I'm going to leave this open for a little while to see if anyone can clear up this Variant mess.
sapbucket
I downloaded Ecplise IDE, which is Java. I'm not sure what support Java offers for OLE, but they must have better resources then PERL. I'm all about solutions, so if I find a JAVA one I will post the results here.
BTW, anyone else trying to complete a OLE project (that is, you were handed a third-party ActiveX control and now you need to build an app with it), DO NOT USE PERL!!!! This is for a very un-obvious reason. PERL does not have built-in support for the VARIANT data type. OLE objects sometimes return VARIANTs when you call a function or method. PERL just doesn't know how to handle them. If someone tries to tell you that PERL can't handle COM objects - that isn't true - it handles COM objects beautifully, that is, until you find yourself trying to comprehend a VARIANT. Things like manipulating WORD and EXCEL docs works very well from PERL. But wait until you need to get an array reference from a Variant....
grg99, thank you for the discussion. :)
I'm going to leave this open for a little while to see if anyone can clear up this Variant mess.
sapbucket
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Sorry that inner loop should have looked like:
for(my $w=0;$w < $width; $w++) {
my $data = $imagedata->Get($w, $h);
print "($w, $h) = $data\n";
$imagedata->Put($w, $h, 255 - $data);
}
for(my $w=0;$w < $width; $w++) {
my $data = $imagedata->Get($w, $h);
print "($w, $h) = $data\n";
$imagedata->Put($w, $h, 255 - $data);
}
I found a machine that has a WDM device on it. The following works (kinda). Win32::OLE marshalls in the the safearray as a reference to a perl array. So you can deal with it as a perl array or you can override the autoconvert and deal with it as a variant (if for some odd reason you wanted to). Here's a sample that shows both:
use strict;
use Win32::OLE;
use Win32::OLE::Variant;
my $imaging = Win32::OLE->new('IC.ICImag ingControl ') or die "oops\n";
$imaging->ShowDeviceSettin gsDialog() ;
$imaging->MemorySnapImage( );
my $height = $imaging->{ImageHeight};
my $width = $imaging->{ImageWidth};
print "imaging: $imaging\n";
print "height: $height\n";
print "width: $width\n";
my $data;
my $imagedata;
my $AS_VARIANT = 0;
if ($AS_VARIANT)
{
# deal with it as a variant
$imagedata = Variant(VT_EMPTY, undef);
$imaging->Dispatch('Memory GetImageDa ta', $imagedata);
for(my $h=0; $h < $height; $h++) {
for(my $w=0;$w < $width;$ w++) {
my $data = 255 - $imagedata->Get($w, $h);
print "($w, $h) = $data\n";
$imagedata->Put($w, $h, $data);
}
}
}
else
{
# dealing with it marshalled as a perl array -- default way of dealing with it
$imagedata = $imaging->MemoryGetImageDa ta();
for (my $h=0; $h < $height; $h++)
{
for (my $w=0; $w < $width; $w++)
{
$data = 255 - $$imagedata[$w][$h];
print "($w, $h) = $data\n";
$$imagedata[$w][$h] = $data;
}
}
}
$imaging->MemorySaveImage( "c:\\vidca p\\test.bm p");
$imaging->MemoryReleaseIma geData($im agedata);
# ========================== ========== ========== =
Now to the problem... Just a guess, but it looks like Win32::OLE is making a copy of the variant and releasing the original variant reference returned to it. That messes up a couple of related things: the original variant reference returned is released without the call to MemoryReleaseImageData (which screws with your imaging control buffer and you end up with a black buffer on the save image) and you're actually working on a copy of the buffer rather than the buffer itself.
You get the same results as the perl code above with the following VB:
Sub testing()
Dim ImageData As Variant
Dim x As Integer, y As Integer
Dim icimagingcontrol1 As New ICImagingControl.ICImaging Control
icimagingcontrol1.ShowDevi ceSettings Dialog
icimagingcontrol1.MemorySn apImage
ImageData = icimagingcontrol1.MemoryGe tImageData
datacopy = ImageData
Debug.Print "height: " & UBound(datacopy, 2)
Debug.Print "width: " & UBound(datacopy, 1)
ImageData = "" ' improperly release the reference to imagedata
For y = 0 To icimagingcontrol1.ImageHei ght - 1
For x = 0 To icimagingcontrol1.ImageWid th - 1
Debug.Print "(" & x & "," & y & ") = " & 255 - datacopy(x, y)
datacopy(x, y) = 255 - datacopy(x, y)
Next x
Next y
icimagingcontrol1.MemorySa veImage "c:\vidcap\mybmp.bmp"
icimagingcontrol1.MemoryRe leaseImage Data datacopy
End Sub
If all you're concerned with is the image data then you can get to that. But if you want to mess with the actual buffer and have it reflected in the control then it'll take some more digging. I think you might be out of luck with perl.
use strict;
use Win32::OLE;
use Win32::OLE::Variant;
my $imaging = Win32::OLE->new('IC.ICImag
$imaging->ShowDeviceSettin
$imaging->MemorySnapImage(
my $height = $imaging->{ImageHeight};
my $width = $imaging->{ImageWidth};
print "imaging: $imaging\n";
print "height: $height\n";
print "width: $width\n";
my $data;
my $imagedata;
my $AS_VARIANT = 0;
if ($AS_VARIANT)
{
# deal with it as a variant
$imagedata = Variant(VT_EMPTY, undef);
$imaging->Dispatch('Memory
for(my $h=0; $h < $height; $h++) {
for(my $w=0;$w < $width;$ w++) {
my $data = 255 - $imagedata->Get($w, $h);
print "($w, $h) = $data\n";
$imagedata->Put($w, $h, $data);
}
}
}
else
{
# dealing with it marshalled as a perl array -- default way of dealing with it
$imagedata = $imaging->MemoryGetImageDa
for (my $h=0; $h < $height; $h++)
{
for (my $w=0; $w < $width; $w++)
{
$data = 255 - $$imagedata[$w][$h];
print "($w, $h) = $data\n";
$$imagedata[$w][$h] = $data;
}
}
}
$imaging->MemorySaveImage(
$imaging->MemoryReleaseIma
# ==========================
Now to the problem... Just a guess, but it looks like Win32::OLE is making a copy of the variant and releasing the original variant reference returned to it. That messes up a couple of related things: the original variant reference returned is released without the call to MemoryReleaseImageData (which screws with your imaging control buffer and you end up with a black buffer on the save image) and you're actually working on a copy of the buffer rather than the buffer itself.
You get the same results as the perl code above with the following VB:
Sub testing()
Dim ImageData As Variant
Dim x As Integer, y As Integer
Dim icimagingcontrol1 As New ICImagingControl.ICImaging
icimagingcontrol1.ShowDevi
icimagingcontrol1.MemorySn
ImageData = icimagingcontrol1.MemoryGe
datacopy = ImageData
Debug.Print "height: " & UBound(datacopy, 2)
Debug.Print "width: " & UBound(datacopy, 1)
ImageData = "" ' improperly release the reference to imagedata
For y = 0 To icimagingcontrol1.ImageHei
For x = 0 To icimagingcontrol1.ImageWid
Debug.Print "(" & x & "," & y & ") = " & 255 - datacopy(x, y)
datacopy(x, y) = 255 - datacopy(x, y)
Next x
Next y
icimagingcontrol1.MemorySa
icimagingcontrol1.MemoryRe
End Sub
If all you're concerned with is the image data then you can get to that. But if you want to mess with the actual buffer and have it reflected in the control then it'll take some more digging. I think you might be out of luck with perl.
ASKER
Wow, alot to digest clockwatcher.
I am going to try this out:
if ($AS_VARIANT)
{
# deal with it as a variant
$imagedata = Variant(VT_EMPTY, undef); #### THIS IS WHERE I HAVE A PROBLEM ####
$imaging->Dispatch('Memory GetImageDa ta', $imagedata);
for(my $h=0; $h < $height; $h++) {
for(my $w=0;$w < $width;$ w++) {
my $data = 255 - $imagedata->Get($w, $h);
print "($w, $h) = $data\n";
$imagedata->Put($w, $h, $data);
}
}
}
else
{
# dealing with it marshalled as a perl array -- default way of dealing with it
$imagedata = $imaging->MemoryGetImageDa ta();
for (my $h=0; $h < $height; $h++)
{
for (my $w=0; $w < $width; $w++)
{
$data = 255 - $$imagedata[$w][$h];
print "($w, $h) = $data\n";
$$imagedata[$w][$h] = $data;
}
}
}
You can see where I have a problem.
I'll hack for a few hours and see if anything falls through.
Thanks
I am going to try this out:
if ($AS_VARIANT)
{
# deal with it as a variant
$imagedata = Variant(VT_EMPTY, undef); #### THIS IS WHERE I HAVE A PROBLEM ####
$imaging->Dispatch('Memory
for(my $h=0; $h < $height; $h++) {
for(my $w=0;$w < $width;$ w++) {
my $data = 255 - $imagedata->Get($w, $h);
print "($w, $h) = $data\n";
$imagedata->Put($w, $h, $data);
}
}
}
else
{
# dealing with it marshalled as a perl array -- default way of dealing with it
$imagedata = $imaging->MemoryGetImageDa
for (my $h=0; $h < $height; $h++)
{
for (my $w=0; $w < $width; $w++)
{
$data = 255 - $$imagedata[$w][$h];
print "($w, $h) = $data\n";
$$imagedata[$w][$h] = $data;
}
}
}
You can see where I have a problem.
I'll hack for a few hours and see if anything falls through.
Thanks
ASKER
Here is the solution to my problems:
NOTE: PERL does not support a variant (at least not in a useful way). When purchasing an OLE component from a vendor make sure that they offer non-variant functional support so you are not forced into using a VB solution. THAT is what I did here with this solution: I got around the variant and instead accessed the memory directly.
#!/usr/bin/perl -w
#------------------------- -------
# start of profiler:
# start section
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
$t0 = [gettimeofday];
# end section
#------------------------- -------
#------------------------- -------
# instance an imaging control using Win32::OLE:
# start section:
use Win32::OLE;
$imaging = Win32::OLE->new('IC.ICImag ingControl ') or die "oops\n";
# end section
#------------------------- -------
#------------------------- -------
# Use the Dialog to get camera settings:
# start section
# If we want to change settings we need to use the dialog and and save
# the state so we can load from file.
#$imaging->ShowDeviceSetti ngsDialog( );
#$imaging->SaveDeviceState ToFile("c: \\ocr\\dev ice_state. xml");
# end section
#------------------------- -------
#------------------------- --------
# This section is used by all following sections.
# start section
$imaging->LoadDeviceStateF romFile("c :\\ocr\\de vice_state .xml",1);
$imaging->MemorySnapImage( );
$imaging->MemorySaveImage( "c:\\ocr\\ test1.bmp" );
$buffer = $imaging->ImageBuffers->It em(1);
# end section
#------------------------- --------
#------------------------- ---------- --------
# This section tries to use ImageDataPtr() to access image data.
# Hopefully it will not interfere with saving the image.
# start section
$t3 = [gettimeofday];
$ptrData=$buffer->ImageDat aPtr();
print "ptrData prior to muck() is $ptrData\n";
$indexForImage = 640*480*3; # HARDCODED!!!! BEWARE CHANGES TO HARDWARE SETTINGS
for($i=0;$i<$indexForImage ; $i++) {
muck($ptrData); # will print output from muck...
$ptrData++;
}
$imaging->MemorySaveImage( "c:\\ocr\\ test2.bmp" ); # nope! saves great!!!
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t3, [$seconds, $microseconds]);
print "elapsed time is $elapsed s\n";
# end section
#------------------------- ---------- --------
#------------------------- ---------- --------
# second half of profiler:
# start section
print $imaging->ImageWidth();pri nt ", ";
print $imaging->ImageHeight();pr int "\n";
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t0, [$seconds, $microseconds]);
print "elapsed time is $elapsed s\n";
# end section
#------------------------- ---------- --------
use Inline C;
__END__
__C__
void muck(long memory_address) {
// convert using a type cast:
unsigned char* Adr = (unsigned char*)memory_address;
// perform some type of image processing:
*Adr = 255 - (*Adr);
// uncomment the following to see process from command line:
// remember to use %ld, NOT %l!!!!
//printf("Hello long: %ld!\n", memory_address);
//printf("Hello address: %ld\n", Adr);
//printf("Hello address contents: %ld\n", *Adr);
}
NOTE: PERL does not support a variant (at least not in a useful way). When purchasing an OLE component from a vendor make sure that they offer non-variant functional support so you are not forced into using a VB solution. THAT is what I did here with this solution: I got around the variant and instead accessed the memory directly.
#!/usr/bin/perl -w
#-------------------------
# start of profiler:
# start section
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
$t0 = [gettimeofday];
# end section
#-------------------------
#-------------------------
# instance an imaging control using Win32::OLE:
# start section:
use Win32::OLE;
$imaging = Win32::OLE->new('IC.ICImag
# end section
#-------------------------
#-------------------------
# Use the Dialog to get camera settings:
# start section
# If we want to change settings we need to use the dialog and and save
# the state so we can load from file.
#$imaging->ShowDeviceSetti
#$imaging->SaveDeviceState
# end section
#-------------------------
#-------------------------
# This section is used by all following sections.
# start section
$imaging->LoadDeviceStateF
$imaging->MemorySnapImage(
$imaging->MemorySaveImage(
$buffer = $imaging->ImageBuffers->It
# end section
#-------------------------
#-------------------------
# This section tries to use ImageDataPtr() to access image data.
# Hopefully it will not interfere with saving the image.
# start section
$t3 = [gettimeofday];
$ptrData=$buffer->ImageDat
print "ptrData prior to muck() is $ptrData\n";
$indexForImage = 640*480*3; # HARDCODED!!!! BEWARE CHANGES TO HARDWARE SETTINGS
for($i=0;$i<$indexForImage
muck($ptrData); # will print output from muck...
$ptrData++;
}
$imaging->MemorySaveImage(
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t3, [$seconds, $microseconds]);
print "elapsed time is $elapsed s\n";
# end section
#-------------------------
#-------------------------
# second half of profiler:
# start section
print $imaging->ImageWidth();pri
print $imaging->ImageHeight();pr
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t0, [$seconds, $microseconds]);
print "elapsed time is $elapsed s\n";
# end section
#-------------------------
use Inline C;
__END__
__C__
void muck(long memory_address) {
// convert using a type cast:
unsigned char* Adr = (unsigned char*)memory_address;
// perform some type of image processing:
*Adr = 255 - (*Adr);
// uncomment the following to see process from command line:
// remember to use %ld, NOT %l!!!!
//printf("Hello long: %ld!\n", memory_address);
//printf("Hello address: %ld\n", Adr);
//printf("Hello address contents: %ld\n", *Adr);
}
ASKER
If there are no objections I am going to close this question.
clockwatcher deserves points for his hard work, unfortunately his solution did not work for me.
I will leave this open to catch any arguments before closing.
clockwatcher deserves points for his hard work, unfortunately his solution did not work for me.
I will leave this open to catch any arguments before closing.
I suggest a refund of his/her points.
ASKER
I gave the points to clockwatcher
thanks for the help
sorry someone else who expects a solution...
thanks for the help
sorry someone else who expects a solution...
$imagedata->Put($w, $h, 255 - $imagedata->Get($w, $h));