A few thoughts, which probably go against a bit of what people have suggested so far:
1) To read the width and height of a PNG you don't need any big library or other JScript files from other scripts. That's extreme overkill, especially if you're going to use something like the GDI+ lib from ScreenShot Sender, for just reading image sizes.
a) So, you can do this using GDI+. This is actually not so super hard once you get the basics. So you certainly do not need the full blown library (like the one from the otherwise excellent Screenshot Sender script). All you need is:
jscript code:
function GetImageWidthHeight(sFilePath) {
var lGdiplusToken = Interop.Allocate(4);
var lGdiplusStartupInput = Interop.Allocate(16);
lGdiplusStartupInput.WriteDWORD(0, 1); // Set GDI version 1
var lReturn = Interop.Call('GDIPLUS.DLL', 'GdiplusStartup', lGdiplusToken, lGdiplusStartupInput, null);
if (lReturn === 0) {
var hFile = Interop.Allocate(4);
var PNGwidth = Interop.Allocate(4);
var PNGheight = Interop.Allocate(4);
if (Interop.Call('GDIPLUS.DLL', 'GdipLoadImageFromFile', sFilePath, hFile) === 0) {
Interop.Call('GDIPLUS.DLL', 'GdipGetImageWidth', hFile.ReadDWORD(0), PNGwidth);
Interop.Call('GDIPLUS.DLL', 'GdipGetImageHeight', hFile.ReadDWORD(0), PNGheight);
Interop.Call('KERNEL32.DLL', 'CloseHandle', hFile.ReadDWORD(0));
}
Interop.Call('GDIPLUS.DLL', 'GdiplusShutdown', lGdiplusToken.ReadDWORD(0));
PNGwidth = PNGwidth.ReadDWORD(0);
PNGheight = PNGheight.ReadDWORD(0);
Debug.Trace('The image size is: ' + PNGwidth + 'x' + PNGheight);
}
}
b) Or do it even more simpler. Simply read the proper bytes from the file directly. This is very possible for PNGs since the IHDR chunk (containing the image specs) must always be the first chunk in the PNG so you don't need to bother about parsing chunks and a whole big set of functions to handle a PNG.
The width and height will always be at offset 16 and 20 (and they are both 4 bytes long = DWORD, and they are in Big Endian order):
jscript code:
function GetPNGWidthHeight(sFilePath) {
var hFile = Interop.Call('kernel32.dll', 'CreateFileW', sFilePath, 0x80000000 /* GENERIC_READ */, 1 /* FILE_SHARE_READ */, 0, 3 /* OPEN_EXISTING */, 0, 0);
if (hFile !== -1) {
var lpBuffer = Interop.Allocate(24);
var lpBytesRead = Interop.Allocate(4);
var lReturn = Interop.Call('KERNEL32.DLL', 'ReadFile', hFile, lpBuffer, 24, lpBytesRead, 0);
Interop.Call('KERNEL32.DLL', 'CloseHandle', hFile);
if (lReturn !== 0 && lpBytesRead.ReadDWORD(0) === 24) {
// Important: PNGs have a Big Endian byte order
var PNGwidth = lpBuffer.GetAt(16) << 24 | lpBuffer.GetAt(17) << 16 | lpBuffer.GetAt(18) << 8 | lpBuffer.GetAt(19)
var PNGheight = lpBuffer.GetAt(20) << 24 | lpBuffer.GetAt(21) << 16 | lpBuffer.GetAt(22) << 8 | lpBuffer.GetAt(23);
Debug.Trace('The image size is: ' + PNGwidth + 'x' + PNGheight);
}
lpBytesRead.Size = 0;
lpBuffer.Size = 0;
}
}
Of course, this function is specific for PNGs.
c) PS: If you're going to use the script only on your own computer. Or at least on a computer which doesn't have some special DBCS encoding needs (like Japanese, etc) you could use an even simpler and very short method to read the binary data from a file. But since that will not work for everyone, it is not so trustable...
-------------------------
2) You need to take into consideration that multiple people can send you multiple Latex strings at the same time.
So you do need to have a system where the current loaded image is unique. As you already noticed, when a file is loaded it is locked and can't be overwritten.
Matti's suggestion is the best one and the only one which is always going to work in every situation.
Matty's suggestion of copying the PNG to JPG is not going to work because of the same reason why you get the 'access denied' error in the first place. You can't copy over a locked file either. Second, I really do not recommend converting a PNG to a JPG as that will reduce the quality.
-------------------------
3) If you don't want multiple windows pop up each time, maybe you could create a kind of history in that window, where the user can click a button and go back to the previous (or next) image. Upon closing the window, you delete all the used files from disk (again by using the method from Matti - that is with an I, not a Y - god, this is confusing
).
-------------------------
EDIT: don't create a black image and a white image underneath the graphic to have borders. You will have stretching problems when you resize the window/images. Instead draw a real border (with a fix thickness so it does not stretch) around the graphic you're showing. And/or take a look at the 'FigureElement' in the Plus! Scripting Documentation for this (you can assign a border to it, it can show an image, and you could even define (white) margins).
Plus! Scripting Documentation > Contents > XML Schemas Reference > Interface Windows > Schema Documentation > FigureElement