loading
 
SetImage
Kresimir Majdenic from Croatia  [38 posts]
8 year
Have a problem with SetImage from Delphi.

I've managed to "GetImage" from RR (here an example if anyone would ever need):

procedure TForm1.GetJPGImageBClick(Sender: TObject);
var
  Reply: integer;
  img: OleVariant;
  w: OleVariant;
  h: OleVariant;
  j: TJPEGImage;
  m: TMemoryStream;

  procedure VariantToStream (const v : olevariant; Stream : TMemoryStream);
  var
    p : pointer;
  begin
    Stream.Position := 0;
    Stream.Size := VarArrayHighBound (v, 1) - VarArrayLowBound(v,  1) + 1;
    p := VarArrayLock (v);
    Stream.Write (p^, Stream.Size);
    VarArrayUnlock (v);
    Stream.Position := 0;
  end;

begin
  Reply := RoboRealmOLE.GetImage('source',img,w,h,'JPEG');
  if Boolean(Reply) then begin
    m := TMemoryStream.Create;
    j := TJPEGImage.Create;
    try
      VariantToStream(img,m);
      j.LoadFromStream(m);
    finally
      j.Free;
      m.Free;
    end;
  end;
end;




But when I try the "same" for SetImage it does not work (RR does not show any image)

procedure TForm1.SaveImage(j: JPEGImage);
var
  Reply: integer;
  img: OleVariant;
  w: OleVariant;
  h: OleVariant;
  m: TMemoryStream;

  procedure StreamToVariant (Stream : TMemoryStream; var v : OleVariant);
  var
    p : pointer;
  begin
    v := VarArrayCreate ([0, Stream.Size - 1], varByte);
    p := VarArrayLock (v);
    Stream.Position := 0;
    Stream.Read (p^, Stream.Size);
    VarArrayUnlock (v);
  end;

begin
  m := TMemoryStream.Create;
  try
    j.SaveToStream(m);
    StreamToVariant(m,img);
    Reply := RoboRealmOLE.SetImage('ImageToGet',img,j.Width,j.Height,'JPEG');
  finally
    m.Free;
  end;
end;

Any idea what seems to be the problem?
Steven Gentner from United States  [1446 posts] 8 year
The first param in SetImage is the marker name ... i.e. the name of the image. Unless you use 'source' like you did on the GetImage it will store that image as a marker. So unless your robofile shows that marker the image will not appear in RR.

Other than that, did you get any errors?

STeven.
Kresimir Majdenic from Croatia  [38 posts] 8 year
I've tried with "source" as well. In attached [Clipboard01.jpg] you can see what I get in RR. It looks like RR received an image (I've checked IMAGE_WIDTH, HEIGHT and it is of correct value 2592x1944)

In Delphi there is no error (Reply value is 0 ... for other actions like Run('xx') I get reply -1 if it is executed correctly and 0 if it is not executed at all).

 
Kresimir Majdenic from Croatia  [38 posts] 8 year
Just to make sure, I've loaded Start_Image.gif prior to executing SetImage. As you can see in [Clipboard02.jpg] IMAGE_WIDTH, IMAGE_HEIGHT values are correct (2592x1944), RR showed something and as you can see in API Log - there was a communication between Delphi and RR.

 
Kresimir Majdenic from Croatia  [38 posts] 8 year
I've also tried this way

    Reply := RoboRealmOLE.GetImage('source',img,w,h,'JPEG');
    Reply := RoboRealmOLE.SetCamera('off');
    Reply := RoboRealmOLE.SetImage('source',img,w,h,'JPEG');

RR showed the same "problematic" image (see Clipboard02.jpg from previous post).
Steven Gentner from United States  [1446 posts] 8 year
Kresimir,

Thanks for your testing and also including the screenshot. As soon as I saw the image in the background (couple lines of noise followed by black) I knew what the problem was.

Initially the SetImage was used to set pixel formats like RGB (i.e. 3 byte triplets) that contained the image data. It was never adapted to accept 'jpeg' formats like GetImage would return. This was upgraded in the API with the SetCompressedImage function that would accept these file formats. In the case of the COM object, we've now upgraded the exposed SetImage function to determine which one you actually mean and provide a single interface for both API functions.

So, you don't need to change any of your code but do need to download the latest RR version including the updated RR_COM_API.dll file which will have this new check. After the update your code should work as is.

This was testing using the following CSharp code and is not part of the API.zip download. Note that since the file format includes the width and height you don't actually need to set those. (In the straight RGB formats there is NO metadata so those are needed).

---//----

      // result from some COM object functions
      int VARIANT_TRUE = -1;
      int VARIANT_FALSE = 0;

      RR_COM_APILib.API_Wrapper rr = new API_Wrapper();

      Image image = Image.FromFile("c:\temp\test.jpg", true);

      MemoryStream ms = new MemoryStream();
      image.Save(ms, ImageFormat.Jpeg);

      if (rr.Startup() == VARIANT_TRUE)
      {
        rr.SetImage("source", ms.ToArray(), 0, 0, "jpeg");
        rr.Disconnect();
      }

---//---
Steven Gentner from United States  [1446 posts] 8 year
For those working directly with .net bitmaps you can instead use

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr

Bitmap bm = new Bitmap("c:\temp\test.jpg");
IntPtr hBitmap = bm.GetHbitmap();
int res = rr.SetBitmap("source", hBitmap);
DeleteObject(hBitmap);
Kresimir Majdenic from Croatia  [38 posts] 8 year
I've downloaded and installed new version (even though it says it is the same version 2.76.7).
If I try this:

    Reply := RoboRealmOLE.GetImage('source',img,w,h,'JPEG');
    Reply := RoboRealmOLE.SetCamera('off');
    Reply := RoboRealmOLE.SetImage('source',img,w,h,'JPEG');

It works.

But if I try the way it suppose to be in my application. Image I get from RR is JPEG without compression. That file is too large for me [some 9 MB] and is not suitable to be stored in database. That is why it is converted to grayscale and compressed to compression quality 10. Now image has only around 100 kB [Test.jpg]. It turned out that it is still good enough to be read by any human and also still good enough for RR to find and read barcodes, markers and X marks in tables.

So, when I perform compression and SetImage of that file I get an error from RR [SetImage 00.jpg]. After I press OK image is shown within RR [SetImage 01.jpg] and there is an indication of an slient error [SetImage 02.jpg].

I did some analysis of JPEG (inspecting bytes in header part) received from RR and the one that I send back and it seems to me that there is no difference (apart from the fact that my JPEG is compressed and grayscale).

Have you any idea what might be a problem?

    
Steven Gentner from United States  [1446 posts] 8 year
GetImage will request a jpeg image in superb (highest) quality which will not compress the image as much as you'd like. This was to ensure minimal loss when transferring images. To accommodate your issue AFTER downloading the latest version of RR since the COM object was updated to add this:

rr.SetCOMParameter("image_greyscale", 1); // 1 - convert to grayscale
rr.SetCOMParameter("image_quality", 1); // 1-5 with 5 being best
rr.GetImage("source", pixels, width, height, "jpeg");

which includes a new SetCOMParameter function to add more functionality to GetImage without breaking existing function calls. Note that quality 5 is assumed by default.

Let me know if this help to reduce the image size.

STeven.
Kresimir Majdenic from Croatia  [38 posts] 8 year
I've tried but it does not seems to works. I've tried with image_grayscale 1 and 0, I've tried with  image_quality 1 and 5 ... I always get the same image (I've installed new version of RR 2.76.8, unregistered previous RR_COM_API.dll, registered the new one).

As you can see [SetCOMParameter - API.gif] there is no sign of communication when sending SetCOMParameter values.

These a results I see in my application (outcome of calling SetCOMParameter)

17.07.2015 10:03:55.832 Set image grayscale. Reply 0 phase duration 0 ms
17.07.2015 10:03:55.832 Set image quality. Reply 1 phase duration 0 ms
17.07.2015 10:03:55.976 GetImage requested. Reply -1 phase duration 140 ms


 
Steven Gentner from United States  [1446 posts] 8 year
Kresimir,

Sorry about my previous post ... it was too soon. The DLL had not yet been updated. I have verified that the changes are now in the latest version.

Note, the SetCOMParameter will not send out anything itself but just modify the next GetImage call. You should see a flags parameter in the GetImage message now that contains the quality and grayscale information (a single number of ORed values).

Thanks,
STeven.
Kresimir Majdenic from Croatia  [38 posts] 8 year
I've just tested it and it works but in very odd kind of way. It does not matter if I set grayscale or not it is always color (24BPP). When I set quality to 1 returned image really is of low quality but the size is the same as when quality is set to 5).
Furthermore some image viewing applications can show that image but have difficulties reading image information.
Steven Gentner from United States  [1446 posts] 8 year
Kresimir,

I think the issue in part was the lack of knowing how many bytes the jpg data actually takes. The buffer returned is allocated much larger than needed to ensure that the network read has enough room. Thus, I don't think there was anything that would indicate how many bytes the data actually took.

We've updated the GetImage function to return 0 on error and the size in bytes when successful. So in your case it will return the size of the Jpeg image. This update requires both the COM object and RR be updated.

I've verified the difference in return bytes from the full color, grayscale (8 bit) and grayscale+low quality returns different bytes. The grayscale+low quality reduced the size to just 20% of the original image so that seems to work. Thus the method is now (in CSharp)

          object pixels, width, height;
          int res = rr.SetCOMParameter("image_greyscale", 1); // 1 - convert to grayscale
          int res2 = rr.SetCOMParameter("image_quality", 1); // 1-5 with 5 being best
          int numBytes = rr.GetImage("source", out pixels, out width, out height, "jpeg");
          byte[] rgbArray = (byte[])pixels;
          MemoryStream ms = new MemoryStream(rgbArray, 0, numBytes);
          bm = new Bitmap(ms);

Note the numBytes being returned by GetImage and the length limit when creating the memory stream. I then used

         FileStream fs = new FileStream("c:\temp\test_save.jpg", FileMode.Create);
          BinaryWriter w = new BinaryWriter(fs);
          w.Write(rgbArray, 0, numBytes);
          w.Close();
          fs.Close();

to actually save the jpg data to the file system with the appropriate size again using numBytes.

You'll have to download RR again for these changes.

STeven.
Kresimir Majdenic from Croatia  [38 posts] 8 year
Now it works :)

Grayscale and quality level 1 is just what I needed for my purpose. I've tried SetImage - that works too.

Thank you.
Kresimir Majdenic from Croatia  [38 posts] 8 year
I'm afraid I was too early with "SetImage works too". There is still a problem with SetImage reports [SetImage - Error.gif] an error (premature end of JPEG) for every jpeg I send. Even though the image is correctly showed in RR.

It does not report an error only if I send back the same byte stream (which is much larger then actual jpeg image) I receive from GetImage.

I guess there is some "glitch" with buffer size?

 
Steven Gentner from United States  [1446 posts] 8 year
Yes, there was a byte missing in that transmission from the COM object. This has now been corrected too. You can download the most recent version of RR to have this error fixed.

STeven.
Kresimir Majdenic from Croatia  [38 posts] 8 year
It works :)

Thanx.

This forum thread has been closed due to inactivity (more than 4 months) or number of replies (more than 50 messages). Please start a New Post and enter a new forum thread with the appropriate title.

 New Post   Forum Index