Page 1 of 1

VBA: can't access return value of compare method

Posted: 2016-07-15T09:04:09-07:00
by Eeyore
Hi guys,
I am very sorry to bother you.

I am using ImageMagick from within VBA (Excel) for some weeks now. It is a great thing the developers did!

Everything works fine. Except the compare method doesn't work as expected or wished (for that matter).
Here is a short code snippet:

Code: Select all

' Declaration
Dim objIM As Object
Dim strFileC As String
dim strFileR As String
Dim varRetVal As Variant

' Create object(s)
Set objIM = CreateObject("ImageMagickObject.MagickImage.1")

' Path to reference file
strFileR = objWs4.Cells(lngRow, 1).Value
' Path to file to compare
strFileC = objWs4.Cells(lngRow, 2).Value

varRetVal = objIM.Compare("-metric", "AE", strFileR, strFileC, "NULL:")
If the above command would be changed accordingly, entered to the DOS box and sent off
a)
no difference file would be created (because of parameter "NULL:")
b)
a result value is shown (e.g. 4711)

Yes! I did searched the net for a solution and learned that the result value mentioned above is sent to STDERROR and not to STDOUT...
And: yes! I understood that STDERROR can be accessed
a)
from command line
by redirecting it e.g to a file: 2>D:\TestIM\diff.txt (where parameter '2' represents STDERROR) ... or
b)
from within VBA
using a shell object:

Code: Select all

Function execShellCmd(ByVal strCmd As String) As String
	' Declaration
	Dim objExec
	Dim objShell
	Dim objStdErr
	Dim strLineErr As String
	Dim strTextErr As String

	' Create object(s)
	Set objShell = CreateObject("WScript.Shell")
	Set objExec = objShell.Exec(strCmd)
	Set objStdErr = objExec.StdErr

	Do
		' Read from shell
		strLineErr = objStdErr.ReadLine()
		' Build single string
        	If strLineErr <> "" Then
	            strTextErr = strTextErr & strLineErr
        	End If
		' Exit loop
	        If objStdErr.AtEndOfStream Then
        	    Exit Do
	        End If
	Loop

	' Return resutl to caller
	execShellCmd = arrRet
End Function
But... I learned from this site http://www.imagemagick.org/Usage/api/#api-convert that passing commands to the shell (constantly) can cause serious performance issues. And I have to say: it seems very inconvenient to me.

So after trial and error, reading and reading, trial and error, scratching my head... I surrender and post this question:
Is there a way to access the return value of the compare method from within VBA?

Please: help.

Re: VBA: can't access return value of compare method

Posted: 2016-07-15T09:48:01-07:00
by snibgo
On my computer, running convert from a BAT file to do nothing ("convert xc: NULL:") takes about 0.14 seconds (70 per second). This is usually trivial compared to the processing I do within each convert. I don't know if VB is faster or slower.

You might find the .NET interface useful. See https://magick.codeplex.com/documentation

Re: VBA: can't access return value of compare method

Posted: 2016-07-15T13:14:14-07:00
by Eeyore
Hi snibgo,

thank you for your answer.
I want to point out that I was talking of the compare method, not the convert method.

I learned about the compare method that it does make a big difference if the two images are of different size - if the size of the reference image is bigger than the size of the 2nd image. Than the 2nd image is shifted over the reference image (column- and linewise). A compare is done on each position...
To eliminate this possibility I
*
read width x height of each image (I want to compare later)
*
calculate a normalized width and height
*
create a thumbnail of each image (all thumbnails have equal width x height)
*
finally compare all thumbnails

----

I checked Magick.NET - thank you for showing it to me.
The Examples section seemed very promising at first, but when I entered compare into text box 'Search Wiki & Dokumentation' I got zero results

---

Coming back to the original topic I wonder:
If the compare method of ImageMagick works as designed by the developers... wouldn't it be an option to implement a method e.g.
compareR
a)
where parameter "NULL:" is omitted and
b)
the result(s) (corresponding to the selected metric) can be accessed?

Re: VBA: can't access return value of compare method

Posted: 2016-07-15T13:38:02-07:00
by snibgo
You can compare within convert, with text output going to stdout, eg:

Code: Select all

f:\web\im>%IM%convert rose: ( rose: -level 0,99% ) -metric RMSE -compare -format "%[distortion]" info:

0.00454968

Re: VBA: can't access return value of compare method

Posted: 2016-07-18T07:41:46-07:00
by Eeyore
Hi snibgo,

thank you very much for the advice to use convert instead of compare.
I now found the corresponding section on the ImageMagick website:
https://www.imagemagick.org/script/comm ... php#define

After changeing compare to 'convert - compare' everything seemed to work like a charm. At first.
That is: the first 200 to 300 compares were done with incredible speed.
Than it slowed down.
When the 'comparison counter' hits 1030 Excel crashed without even sending a message.

After playing around with VBAs 'DoEvents' command and waiting times I finally watched Windows Taks-Manager when running the macro.
It looks like the RAM is packed completely after a short time.
I terminated execution manually.
Now RAM is freed VERY slowly.

Does 'convert - compare' spawn new threads which cannot be controlled from within VBA?

Re: VBA: can't access return value of compare method

Posted: 2016-07-18T15:37:54-07:00
by snibgo
I know almost nothing about memory management.

When a program releases memory, it may not show up immediately on Task Manager.

When run in an environment such as VBA, the situation is more complicated.

However, a crude test on IM Q16 integer v6.9.2-5 suggests that IM has no significant memory leakage problem.

My test was:

Create a BAT file, called memLeakComp.bat:

Code: Select all

%IM%convert -size 10000x1000 gradient: g.png

set SRC=g.png

%IM%convert ^
  %SRC% ^
  ( +clone -level 0,99%% ) ^
  -metric RMSE ^
  @memLeakComp.scr ^
  @memLeakComp.scr ^
  @memLeakComp.scr ^
  @memLeakComp.scr ^
  @memLeakComp.scr ^
  @memLeakComp.scr ^
  @memLeakComp.scr ^
  @memLeakComp.scr ^
  @memLeakComp.scr ^
  @memLeakComp.scr ^
  NULL:
The file memLeakComp.scr contains 1000 lines, all like this:

Code: Select all

  ( -clone 0-1 -compare -format "%[distortion] " +write info: +delete )
(Note: this usage of scripts isn't really supported under v6, and doesn't work under v7.)

Hence there are 10,000 comparisons, each between two images that are 10,000,000 pixels. Each image takes about 80 MB of memory.

According to Task Manager, memory usage for this process continually fluctuates, initially between 480 MB and 730 MB, apparently with an overall increase to finally fluctuate between 780 MB and 1023 MB, finishing after 56 minutes.

(1023 MB - 730 MB) / 10,000 operations = 29,300 bytes per operation.


I conclude there is no significant memory leakage problem within IM convert for this operation. However, a more sophisticated test with valgrind etc might show problems.

Re: VBA: can't access return value of compare method

Posted: 2016-07-19T00:47:59-07:00
by Eeyore
Hi snibgo,

finally I got an error message of type: partition C: is running out of memory...

This made me curious, because I care about my system and was sure that there is plenty of space on drive C:
I found out that ImageMagick creates thousands of temporary files in folder
C:\Users\<username>\AppData\Local\Temp

To give you some more details about the environment I run ImageMagick on:
*
I installed setup file: ImageMagick-7.0.2-4-Q16-x86-dll.exe
*
OS is: Windows 7 Enterprise 64 bit
*
Office version is: MS-Office 2010 32 bit

Re: VBA: can't access return value of compare method

Posted: 2016-07-19T02:05:39-07:00
by snibgo
When there isn't enough RAM, IM creates temporary files in %TEMP%. If the IM process completes, it deletes those files. But if IM crashes (is killed by the system, or VBA or whatever), it doesn't delete the files because it can't.

Next time IM runs out of RAM, there is less space in %TEMP%, so it crashes again.

The solution is to periodically empty %TEMP%.

Re: VBA: can't access return value of compare method

Posted: 2016-07-19T11:01:46-07:00
by Eeyore
Hi snibgo,

I tried to implement a function that deletes temporary files from corresponding folder (%TEMP%).
Without success.

Files handlers are still 'owned by' Excel.
Files cannot be deleted.

Re: VBA: can't access return value of compare method

Posted: 2016-07-19T11:14:47-07:00
by snibgo
Take ownership of the files, or give yourself permission to delete them, or just login as an administrator.