×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Open a jpg, mod jpg, close and save jpg
2

Open a jpg, mod jpg, close and save jpg

Open a jpg, mod jpg, close and save jpg

(OP)
I have a Topaz signature pad. It captures the customer's signature at the end of a sale. It can save the signature to a string (it is a very long string), a sig file which I guess would be Topaz proprietary, bmp, jpg, png, tiff and wmf and emf. I have it saving the signatures as an jpg image file. It works. I can print the jpg on the receipt (a VFP9 report). My problem is the signature is very small. I can't find a way via Topaz commands to make the signature larger. The jpg file contains a lot of whitespace aroung the actual signature. If I could somehow (from VFP), open the jpg, find the 1st instance of a black dot in the jpg (that would be where the actual signature starts), maybe I could automatically crop the jpg and resave it ending up with an image that ONLY contains the actual signature (so leaving out all the whitespace around the actual signature). I've looked at using the VFP GDIPlus library and maybe the GDIPlus X library on github (i really don't understand how to download that library from github).

Can anyone tell me the easiest way to get from point a to b on this?

Thanks,
John

RE: Open a jpg, mod jpg, close and save jpg

I think you may be over analysing this.

If the image is AWAYS small, and has this white space around it, does it EVER creep into the top left or bottom right?

If not, surely you could zoom in by a factor and/or crop it to suit.

Me, I would use Viscomsoft ImageViewer to do the work.

Why, because I bought a licence years ago, and it still works!


Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Open a jpg, mod jpg, close and save jpg

(OP)
Griff, You may very well be correct about over analyzing. Been on this for days. I am a bit frustrated.

You said to zoom. I do not recall anything about how to zoom. Can you elaborate?

Thanks, John

RE: Open a jpg, mod jpg, close and save jpg

John,

Can we assume that the amount of white space around the signature is constant? In other words, is the actual signature always in the same place relative to the edges of the image?

If so, it should be possible to do this by sizing the image control to fit the actual signature, and setting its Stretch property to 1.

However, the fact that you mention having to find the first dot suggests that the above assumption is wrong. In that case, you will indeed have to resort to GDI Plus. Have you looked at the base _GDIPLUS.vcx class library that comes with VFP? There might well be something there that will help. There is more information in the VFP Help file, starting at the topic, "GDI Plus API Wrapper Foundation Classes".

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads

RE: Open a jpg, mod jpg, close and save jpg

Keeping in mind that I am definitely not an expert on GDI Plus ....

But glancing at the documentation for the GDI Plus Bitmap Foundation Class, it appears that you could call its CreateFromFile() method to get a bitmap object from your JPG file. Then use its GetPixel() method to loop through the pixels to find where the signature actually starts and ends.

Actually, it's probably more complicated than that. But at least it's a starting point. No doubt there are people in the forum who can give you more detailed advice.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads

RE: Open a jpg, mod jpg, close and save jpg

(OP)
Mike,
Yes, the amount of whitespace aroung the signature IS constant.

I have attached a screenprint showing the settings for the picture control on my report. I have tried all 3 settings, clip contents prints nothing, scale contents (both of them) prints the very small signature. I can make the control taller in which case I do get a bigger sihnature but it still prints the whitespace so it consumes a lot more receipt paper.

I will see if I can understand how to use the GDI library.

Thanks,
John

RE: Open a jpg, mod jpg, close and save jpg

I think we would all profit from a real world example. What if you use such a pad, scribble something on it (doesn't need to be your or anybodies real signature) and post an image here. Make it two examples, please.

I wonder whether all images have the same size, for example, no matter how small or large the actual scribble is. If so, that would even make zooming questionable, you would just need a report image object with fixed size that prints the sccanned image as is, the size would just vary by how large the customer or whatever person signs on the pad and there's no more detail to be gained from zooming in, really.

From your description, I think the only reason to program cropping is to save space in storing the image, In case of JPEG the image compression will already take care compressing vast regions of whitespace, only raw BMP would have a fixed file size.

I understand for you its about the readability of the printed signature. I just guess if a customer only makes a little x or dot, you don't get more detail out of it by zooming that. Instead, you just need a larger size of the image control on the report, than you think.

And I really wonder why images sizes of such signatures would differ, if so, then only when the pad itself would crop the image. As far as you tell this isn't the case, though, so I assume they all have the same standard size. And then I would simply try to make the report control for the image full page width, aspect ratio the same as the images have and then the signature should come out with a reasonable size at whatever position the cutomer signed within that rectangle.

And then, it mainly becomes an instruction to whoever gives this pad to the people signing to ask them to make use of the whole area, to improve the quality.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

@John

The 'zoom' is not a function of VFP, but I believe it is in the imageviewer, if not an actual zoom it lets you save a file in a given size.

Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Open a jpg, mod jpg, close and save jpg

Sorry, I wasn't aware your attachment is an example.

Seems to me it is always 2000x700, right? Is the problem, that you don't print on letter size? Because I think this would come out fine, if the report would be lettersize and the image control width would be paper width. The position and size of the signature would then just be as was used writing on the pad.

I don't have any idea how large the pads are, but the way the image is I assume the pad area is way larger than necessary to sign, is it? So signatures are only made on a small portion of the available area. That would explain it.

I can understand you'd like to treat a signature image as mainly containing the signature (cropped) and then only need to place a control on the report as large as you want the signature, but the way it is it only makes sense to print full width, which prints the signature in reasonable size. Do you have problems with the white being opaque, hiding report content, if you do that? Or is the receipt you print just much narrower than the pad?

Chriss

RE: Open a jpg, mod jpg, close and save jpg

(OP)
I tried adding an attachment that is a screenprint (also a jpg) to show my report with the control, but for some odd reason, after editing my reply twice and adding the attachment twice, the Tek-Tips site did not add the attachment. I will try again to add it to this reply.

I am printing on a Epson TM-T88V receipt printer like most convenience stores use. As I said earlier, I can make the control bigger and get desirable results but because it still prints the entire image (whitespace included), that consumes a lot more receipt paper (not desirable).

As for is it "always 2000x700", I suspect it would always be the same size as the Topaz pad saves the signature as everything inside the signing area of the pad.
I did a signature where 1. I drew a box that is basically the entire signing area on the Topaz pad then 2. I signed filling the entire area. It is attached.
John



RE: Open a jpg, mod jpg, close and save jpg

2
Do I get this right?

The screenshot of the receipt with the "John Cook" signature in a box is the image you made using the full pad size?
The image on your report layout is much higher than the aspect ratio of the image, so you just need to reduce the height of the report image control. The aspect ratio of your layout does not reflect 2000:700, that would looks slimmer. Roughly, 2000:700 means the height should be a third of the width, as 3x700=2100 is about 2000.

Well, and you know better than us, whether all pad images have that resolution. I think so.

You can also move the image control to the back usging the menu "Format" and the option "Send to back" (CTRL+J). That way you would not need to care about the image being mostly white, your other report controls simply print over that white area. Let the image overalap with other report controls.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

Genius, not thinking outside the box, making the box outside the other thing

Well done Olaf

Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Open a jpg, mod jpg, close and save jpg

(OP)
Chriss, Olaf is correct. Sometimes I can't see the forest for the trees. I modified the height and width ratio so it is 3 x as wide as it is tall and I move the control to background and VOILA! Success!

Thank you so much,
John

RE: Open a jpg, mod jpg, close and save jpg

If you want I can provide you a DLL that will open the file, and give you commands to manipulate it. Something like this:

CODE --> VFP9

DECLARE INTEGER bmp_open_file       IN image.dll STRING cPathname
DECLARE INTEGER bmp_crop_to_content IN image.dll INTEGER nHandle
DECLARE INTEGER bmp_get_dimensions  IN image.dll INTEGER nHandle, STRING@ cWidthOutInches8, STRING@ cHeightOutInches8
DECLARE INTEGER bmp_resize          IN image.dll INTEGER nHandle, FLOAT nNewWidthInches, FLOAT nNewHeightInches
DECLARE INTEGER bmp_save_file       IN image.dll INTEGER nHandle, STRING cNewBmpPathname
DECLARE INTEGER bmp_close           IN image.dll INTEGER nHandle

* In your code:
LOCAL lnHandle, lcWidth, lcHeight, lnNewWidth, lnNewHeight
lnHandle = bmp_open_file("c:\path\to\whatever.jpg")
bmp_crop_to_content(lnHandle)
lcWidth = SPACE(8)
lcHeight = SPACE(8)
bmp_get_dimensions(lnHandle, @lcWidth, @lcHeight)

* Compute your scale factor, and generate the new height / width you want
lnNewWidth = ...
lnNewHeight = ...
bmp_resize(lnHandle, lnNewWidth, lnNewHeight)
bmp_save_file(lnHandle, "c:\temp\sig_img.bmp")
bmp_close(lnHandle) 

Something like that. If interested, let me know.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

(OP)
Hi Rick and thanks for the offer. As I will have hundreds of these image files generated daily, I believe it would be a good idea to do whatever I can that would reduce the size of the files. Your tool sounds like it could help me accomplish that so Yes, I am interested.
Thanks,
John

RE: Open a jpg, mod jpg, close and save jpg

I apologize for not getting back to you sooner. I was injured yesterday playing softball and am in a bit of pain today. I'll try to get you the DLL and source code by the end of this weekend.

Again, my apologies, John.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

(OP)
Not a problem. Hope your injury is not too bad. Take your time,
John

RE: Open a jpg, mod jpg, close and save jpg

Quote (cfsjohn)

GDIPlus X library on github (i really don't understand how to download that library from github).

Regarding that, the simplest way is to get everything, by clicking code and then Download zip.



There's a further detail to tackle before you can use the download to compile a system.app that works as the gdiplus library. Like many projects the pjx/pjt files are converted using foxbin2prg - https://github.com/fdbozzo/foxbin2prg

The perhaps simplest way to get the project files back is to simply run the system.pj2 file, it is a PRG. While its header tells its not intended for execution, it works to get the system.pjx necessary to build the system.app from it:

CODE --> system.pj2

*--------------------------------------------------------------------------------------------------------------------------------------------------------
* (ES) AUTOGENERADO - ¡¡ATENCIÓN!! - ¡¡NO PENSADO PARA EJECUTAR!! USAR SOLAMENTE PARA INTEGRAR CAMBIOS Y ALMACENAR CON HERRAMIENTAS SCM!!
* (EN) AUTOGENERATED - ATTENTION!! - NOT INTENDED FOR EXECUTION!! USE ONLY FOR MERGING CHANGES AND STORING WITH SCM TOOLS!!
*--------------------------------------------------------------------------------------------------------------------------------------------------------
*< FOXBIN2PRG: Version="1.19" SourceFile="system.pjx" /> (Solo para binarios VFP 9 / Only for VFP 9 binaries)
*
... 

The "official" way is to run

CODE

DO FOXBIN2PRG.PRG WITH "<path>\system.pj2" 

Well, or actually use source control integration in VFP. It's a topic in itself, though, and I won't even try to explain it here.

When you open the resulting system.pjx in VFP9, use Build and select "Application (app)" in the build options, not the default Win32 executable / COM server (exe).

And then, finally, to use gdiplusx you Do system.app and have it available in _screen.system. Which means you can run code examples. Later you just need to provide the system.app file with your EXE, too.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

The easiest way is using Alexander Golovlev's gpiImage class ( a wrapper for GDI+);
It's available upgraded and documented by Cesar Chalom at
https://vfpimaging.blogspot.com/p/gpimage2.html

CODE -->

** using gpiImage 

Set Procedure To gpimage additive

gpinit 	= Createobject('gpInit')
gpimage = Createobject('gpImage')

With gpimage
	.Load(locfile('00598942.jpg'))
	.crop(100,280,1700,300)
        .resize(int(1700/6),int(300/6)) && was too big!
	.saveaspng('test.png')
Endwith

run test.png 



Marco Plaza
https://www.github.com/nfoxdev

RE: Open a jpg, mod jpg, close and save jpg

I know this, I used it before GDIPlusX existed, but as far as I know Cesar Chalom then contributed much to GDIPlusX and that makes it the successor of gpimage to me. I don't see how this is easier used than DO system.app, anyway, just my 2c. And there also is a System_Lean.app

Chriss

RE: Open a jpg, mod jpg, close and save jpg

Here, by the way, is a method to crop the image in Y direction and reduce the height.

The idea is to use LockBits, which gives you the raw image data. Assuming the first line of the image is empty, the data is scanned until the first line that differs from top and bottom. To not fail on JPEG artifacts having very light gray pixels within the empty areas, the raw image analized is turned into 1bit per pixel black and white only.

The same idea could then be applied to the image rotated 90 degrees to also determine minx ans maxx, I spared myself to do that.

CODE

Do Locfile("system.app")

Local loBitmap As xfcbitmap
Local loCropped As xfcbitmap
Local loRect As xfcrectangle
Local lnMinY, nMaxY

With _Screen.System.drawing

   loBitmap = .Bitmap.FromFile("00598934.jpg") && adapt with path to file 
   m.lnwidth  = m.loBitmap.Width
   m.lnheight = m.loBitmap.Height

   lnMinY = 0
   lnMaxY = lnheight

   loRect = .rectangle.new(0, 0, m.lnwidth, m.lnheight)
   loBits = loBitmap.LockBits(m.lorect, .Imaging.ImageLockMode.ReadOnly, .Imaging.PixelFormat.Format1bppIndexed)

   lnMinY = 0
   lcEmptyLine = Sys(2600,loBits.Scan0,loBits.Stride)
   lnAdr = loBits.Scan0
   For lnI = 1 To loBits.Height
      lcLine = Sys(2600,lnAdr,loBits.Stride)
      If lcLine==lcEmptyLine
         lnMinY = lnMinY + 1
      Else
         Exit
      Endif
      lnAdr = lnAdr + loBits.Stride
   Endfor lnI

   lnMaxY = loBits.Height-1
   lnAdr = loBits.Scan0+lnMaxY*loBits.Stride
   For lnI = 1 To loBits.Height
      lcLine = Sys(2600,lnAdr,loBits.Stride)
      If lcLine == lcEmptyLine
         lnMaxY = lnMaxY - 1
      Else
         Exit
      Endif
      lnAdr = lnAdr - loBits.Stride
   Endfor lnI

   loBitmap.UnlockBits(loBits)

   lorect = .rectangle.new(0, m.lnMinY, m.lnwidth, m.lnMaxY-m.lnMinY)
   loCropped = m.loBitmap.Clone(m.lorect)
   loCropped.Save("00598934Cropped.jpg") && adapt with path

Endwith 

But just to get an impression of what you get from this. IT works fast, too.

Quote (cfsjohn)

reduce the size of the file

JPEG is pretty good at compression, so you will not save bytes by cropping only, you need to play with details of the JPG encoder and its parameters about the JPEG quality and other settings, PNG would perhaps work better. In default settings the cropped image is even larger than with all the whitespace.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

Here is the image.dll function list:

CODE --> VFP9

* Load the DLL functions
* Returns a handle for accessing the bitmap in future operations
DECLARE INTEGER bmp_open_file           IN image.dll STRING cPathname
DECLARE INTEGER bmp_crop_to_content     IN image.dll INTEGER nHandle
DECLARE INTEGER bmp_get_attributes      IN image.dll INTEGER nHandle, STRING@ cWidthOutInches8, STRING@ cHeightOutInches8, STRING@ cBitsPerPixel8, STRING@ cPixelsPerInchX8, STRING@ cPixelsPerInchY8
DECLARE INTEGER bmp_save_file           IN image.dll INTEGER nHandle, STRING@ cNewBmpPathname
DECLARE INTEGER bmp_close               IN image.dll INTEGER nHandle

* Returns a handle for accessing the bitmap in future operations
DECLARE INTEGER bmp_resize              IN image.dll INTEGER nHandle, FLOAT fScaleFactor 

I have it all written, but will need to debug it. There are many other functions which can be exposed as well through the API.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg


Hello Chris, I was referring to the fact that you need to recreate the pjx using foxbin,
then build system.app and redistribute system.app + include a support vcx in your project ,
vs just download a prg based class..

But like you show, of course GDI+X has much more to offer!





Marco Plaza
@nfoxProject
https://www.github.com/nfoxdev

RE: Open a jpg, mod jpg, close and save jpg

Quote (Marco plaza)

+ include a support vcx in your project
I don't see that need. What VCX? All I know is that instead of redistributing system.app you can decide to include all necessary components of GDIPlusX into your own project to not need the System.APP, I don't think that's improving the usage, though. I might be missing something you know better, but so far I never added a VCX to my project.

I find it very simple also with FoxyPreviewer to only need to DO an app. It has become quite a standard, hasn't it? In case of GDIPlusX did you notice you also get intellisense? I don't just mean because of the existance of the _screen.system object after DOing system.app. If you use LOCAL loBitmap as xfcbitmap you get intellisense about the Bitmap GDI+ class when typing loBitmap, not only when typing _screen.System.Drawing.Bitmap.

Chriss

PS: Providing an already built system.app would indeed be nice. I know they had that when codeplex still existed and the project was there. There's nothing hindering to provide the single download on GitHub, too. I don't know why it's not provided, it wouldn't even have a VFP runtime dependency unless there is code only working in VFP9.

RE: Open a jpg, mod jpg, close and save jpg


Indeed GDIX is a fantastic project.. About the vcx.. the page says under distribution files: "GDIPlusX.vcx - This visual class library contains the imgCanvas class and will need to be compiled into your application for distribution, if you utilize this class." - I see it's not needed here so ok.. just skip it.

I'll fork the project and make a pull request to include a bin folder with system.app + system_lean.app for vfp9.








Marco Plaza
@nfoxProject
https://www.github.com/nfoxdev

RE: Open a jpg, mod jpg, close and save jpg

To add control about the image quality (lower quality = higher compression rate) I added:

CODE -->

Local myencoderparameter As xfcencoderparameter
   Local myencoderparameters As xfcencoderparameters
   myencoderparameters = .imaging.encoderparameters.new(1)

   myencoderparameter = .imaging.encoderparameter.new(.imaging.encoder.quality, 10)
   myencoderparameters.param.add(myencoderparameter)
   loCropped.Save("00598934Cropped.jpg", .imaging.imageformat.jpeg, myencoderparameters) 

And it turned out that the cropped image only gets smaller than your original pad JPG if using a very low 10% quality. And the quality of the signature drastically degrades with that setting.

The only benefit would be that you could adapt the report layout, though sending the image to the back already solved that problem. And actually, by having differtly sized cropped images, you would not get same results, even if you manage to set stretching of the images without aspect ratio distortion.

So, in very short: I doubt you will save disk space by cropping the images and keep a sensible image quality at the same time. Your pad already does a great job in choosing the jpg compression parameters to create small files. And just think of the different lengths of names: The cropped signature images just pose a new problem of where and how large to position an image control in your report layout to print the cropped signatures with varying widths. It's an advantage the pad images are all the same resolution of 2000x700 pixels.

Let's see how Rick manages with his DLL, maybe he has a better way than what I managed to get out of gdiplusx.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

Quote (Marco Plaza)

I'll fork the project and make a pull request to include a bin folder with system.app + system_lean.app for vfp9

Thank you.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

Last not least, I compared what an image software like Gimp manages to do.

The result of Gimp saving its perfectly cropped image ("crop to content") with same quality settings as it finds in the original JPG is a file with 87% size. So it performs better than GDI+ encoders. But I don't think you get a much better result with anything else.

With Ricks' DLL you'll only need a few lines of code to save about 10% disk space - not bad but surely less than you expected.

What you could do with the cropped signatures is keep your current report design with the full width image sent to back, but draw this cropped signature centered on a white 2000x700 pixel image you create on the fly. That at least centers all signatures, no matter where they were originally positioned, that's a slight layout advantage I would suggest.

Recomposing the image you can also decide to position the signature into the right bottom quarter, whatever, but you can be sure it has enough room as it came from 2000x700 pixels, originally. And in saved with the data it uses up perhaps 10% less space.

Still quite some effort just for that.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

Something to consider is that the signature doesn't have to be perfect. It's displaying on a receipt printer, so it can be a little pixelated. If you drop the resolution down to 100dpi, and you're printing a receipt printer, you'll only need maybe 400 pixels max, probably more like 300 horizontally, and then scaled down proportionately. That would greatly save on space even if you kept it in a PNG lossless format.

There's also a new lossless format (called QOI) that has gotten good compression on certain types of files. It's a very simple algorithm, which is why it's gotten some attention. If there were a strong contrast between the white background and the actual signature portion it would compress nicely in that format due to its encoding scheme.

Keeping everything in its raw format isn't necessary in my thinking.

I wrote the crop to content algorithm last night, and have had the scale algorithm since the 00s. If there are other / better algorithms they can be implemented. Plus, the source code will be there to tweak as needed. The crop to content is looking for the first non-white pixels to find the content's inner edge, but I think something like GIMP's "Threshold" value would be more desirable, so something like this would allow you to pass in 15.0 which would allow some pixelation / dithering on the image to be ignored, and crop down to decent color contrasts. Colors of RGB(255,255,255) and RGB(254,255,255), etc. would be ignored in those cases as "white background" and ignored. Another would be to either sample the outer bands and derive the background color, or to pass in a reference color to use that as the background.

CODE --> VFP9

DECLARE INTEGER bmp_crop_to_content IN image.dll INTEGER nHandle, ;
FLOAT fThreshold   && Add this parameter to make it work with dithered coloring, ;
INTEGER nRgb       && Add this parameter to use a known background color, ;
INTEGER lAutoRgb   && Add this parameter to pass in non-0 to have it auto-detect the background color 

I almost wrote a GIMP competing product at one point. I had tried to work with the GIMP developers to add some features. They were very receptive at first, but as they researched about me online they mocked me for my faith. They stopped answering my questions and responding to my posts, so I moved on. I had wanted to create a non-committal operator stack that allowed you to go back to some operation in the history of operations on the image, tweak the adjustments and have it filter through and affect all later applied operations. I also wanted to create a new type of image format I called floan, which related to the original pixel dimensions in the source bitmap, processed down to the target. But rather than losing bits in scaling it would retain its original bit density, and simply apply the floans onto the projected image. I would've called it Wonder. It would've done all the things I use GIMP for plus several more. I would've added a programming language to allow image objects to be created and operated on.

If only there were time.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

Yes, other formats than JPG were on my mind already, too. I mentioned PNG. But how I know compression in PNG from GIMP, there are only 9 compression levels and PNGs got quite large in my test, astonishingly, as they are the successor of GIF which already was best for images with a small palette of colors, i.e. graphical images like these signature scribbles.

You're right that the image quality isn't important, I just also saw thermo printers better at greyscales. You're right about the dpi, I didn't think about that. So you could even reduce the density.

The threshold becomes less necessary if you do as I did with Lockbits and use the image converted to 1bpp pure black/white, that automatically makes very light gray pixels white. To find the content that's the easiest way, also less bytes to scan through. And you could also only scan every second line, you don't have to ccrop perfectly. But even within VFP using SYS(2600) it's fast, so there are no performance issues.

Otherwise, I know, you get more ideas than you have time to follow up all of them, that's one of the unsolvable problems. And then you get more ideas by starting with some of them.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

I don't know if this helps but I've needed to display image files on a number of occasions when developing software.

I store the path and filename of the image in a table text field. When I want to view it I make this call:

llRetVal=(WinShellExecute(lcFileName)>31)

That executes the following function that invokes whatever application is setup in Windows to display the image file:

FUNCTION WinShellExecute
LPARAMETER tcFileName,tcWorkingDirectory,tcOperation,tcParameters
LOCAL lnRetVal,lcFileName,lcWorkingDirectory,lcOperation,lcParameters
DECLARE INTEGER ShellExecute IN SHELL32.DLL ;
INTEGER nWinHandle,;
STRING cOperation,;
STRING cFileName,;
STRING cParameters,;
STRING cDirectory,;
INTEGER nShowWindow
lcFileName=ALLTRIM(tcFileName)
lcOperation=IIF(VARTYPE(tcOperation)<>"C","Open",ALLTRIM(tcOperation))
lcParameters=IIF(VARTYPE(tcParameters)<>"C","",ALLTRIM(tcParameters))
lcWorkingDirectory=IIF(VARTYPE(tcWorkingDirectory)<>"C","",ALLTRIM(tcWorkingDirectory))
lnRetVal=ShellExecute(0,lcOperation,lcFileName,lcParameters,lcWorkingDirectory,1)
RETURN (lnRetVal)

Once you have the image on the screen you can use the application's own functions to zoom in to the image.

It's pretty old program code but it still works.

Regards
Gary

RE: Open a jpg, mod jpg, close and save jpg

I continued experimenting. My idea to also determine MinX and MaxX after rotating turned out to be harder than I thought. Because, after Bitmap.RotateFlip() the LockBits method doesn't work, I get memory access violations. But I managed to make it work, when first establishing a square image extended to 2000x2000 pixels.

And then, finally I get a 4KB GIF out of GDIPlusX. Opening the result GIF image with Gimp shows that the GDI+ gif encoder still uses an oversized 216 color palette, though, and it can be reduced to a 1bit per pixel monochrome GIF with only 2.5 KB. PNG slightly larger, astonishingly. I'm speaking of the sample "Hook" signature you attached, cfsjohn. Original file size was 13KB.

There are ways to create color palettes, it's not that straight forward, though. I found an example that also describes what's so complicated about it here: https://ftp.zx.net.nz/pub/archive/ftp.microsoft.co.... I didn't apply this, but it all gets quite messy, lengthy code, if I add this to my crop rectangle determination code. And though any lenghty code can be put into a function to finally only become one line, I look forward to Rick's DLL now.

Chriss

PS: For comparison: By just changing the pixel format to monochrome GIMP also manages to turn the JPEG uncropped into a 5 KB GIF and 4 KB PNG, respectively. Which means the main savings are already gained from converting to purely monochrome (not 256 tones grayscale, just black/white).

RE: Open a jpg, mod jpg, close and save jpg

I have it all coded, but I haven't had a chance to debug it. Will do so hopefully tomorrow.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

I apologize. It'll be this weekend before I can get it debugged. Life things.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

Attached is my first attempt at it. It has some example code. It should be relatively straight-forward to expand. Please report any issues.

See the full source code on GitHub. It's a Visual Studio 2003 project, so you'll have to upgrade it possibly through a few steps. I developed it on a Windows 2000 Professional virtual machine.

CODE --> VFP9

LOCAL img AS ImageBitmap

img = CREATEOBJECT("ImageBitmap")
img.open("trig_series.png")   && Uses GDI+, so anything the machine supports can be loaded and saved
img.crop()                    && Will crop to the first non-white character, see other parameters for options
img.get_attributes()

* See the actual image.prg source code.
* There are several properties that are populated with img.get_attributes().
* These can be used to determine how much to resize an image, for example

* Resize to 80% of its current size
img.resize(0.80)
img.save("trig_series_resized.jpg")
img.save("trig_series_resized.png")

* The image remains in memory until explicitly .close()'d, even if img goes out of scope.
img.close() 

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

1st error I see is in your VFP code, the open method does not open tcImagePathname but hardcoded "_trig_series.png"

I don't get crop to actually crop the image, neither the _trig_series.png is cropped, there still is white border in the resized images, nor does it crop the hook signature cfsjohn attached as 00598934.jpg (reattached here).

I used nrgb=RGB(253,253,253)=16645629 as tnRGB parameter (that is the background color the jpg found out with GIMP. And 2 as tnType (use tnRGB). I also tried lower and higher values as I assume that's a threshold, not the exact color. The jpg of cfsjohns device isn't using exact white and it has JPEG artifacts, but crop should nevertheless cut off most of that image and instead does not crop at all.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

Quote (Chris Miller)

open method does not open tcImagePathname but hardcoded "_trig_series.png"

True. Corrected. I originally had it as a top-down procedural program and refactored it into the class. I missed some things. I apologize. This past week has been difficult.

Quote (Chris Miller)

I don't get crop to actually crop the image

True. Corrected. The returned lnResult was the new this.nHandle that needed to be set. In my procedural code I used it, but in the class refactoring I forgot it.

Quote (Chris Miller)

The jpg of cfsjohns device isn't using exact white and it has JPEG artifacts, but crop should nevertheless cut off most of that image and instead does not crop at all.

I didn't try it on cfsjohns image. I'll try that now. Will post the code updates here in a bit. I need to add another parameter to specify the threshold for the indicated color.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

Update to source code is posted.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

Thanks, now it works.

The savings are low, as I already saw myself. You get more from changing to 1bpp monochrome than from resizing to 80% image dimensions. But most important the cropping works, so that pixel format conversion can also be done separately.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

If the high resolution isn't important, I could make an option to decrease the DPI so it stores the same size, but with fewer pixels. But I really don't see how size would be an issue. It looks like its 10s of KB per signature anyway.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

No, sorry that I was perhaps not clear enough. Your code crops and keeps the pixelformat. For cfsjohns case it would be best to convert to monochrome.

I saw gdiplusx has a GetMonochrome() method. You can get a 4KB GIF from the Hook signature even without cropping at all, just changing the pixelformat, not dpi, just converting from the 8bpp indexed JPG the device saves to 1bppindexed with black/white palette:

CODE

Do system.app

loBitmap = _screen.system.Drawing.Bitmap.FromFile("00598934.jpg")
loMono = loBitmap.GetMonochrome()
loMono.Save("00598934converted.gif") 
I attached the result of that.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

I can expose any ability that's available and/or required. If you save as a .TIF file does that save as monochrome?

Also, I think it should have some kind of softening algorithm applied before converted to monochrome, so it would lose dithering / speckles from pixels that are within some color range. I think the threshold value like what GIMP uses to select an area by color would again work for that.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

If I take the quality of the original images for granted by the "Hook" example, then there are no speckles in the images that would cause single black pixels where the original has just a grey pixel artifact. In short, that conversion is working very well and the signature quality actually is better than the original. Just view it zoomed large.

As the signatures finally are printed on thermo paper, I think, the quality aspect is less of a concern, I just point out that converion to monochromes has a better effect on the file size than lowering the resolution and sticking to the greyscale palette. Maybe, Rick, I should point out that the major concern of cropping has become just a secondary concern as sending the image to the back of the report also solved the initial problem. Indeed this also has an advantage of a fixed size and position of the image in the report.

From a post of May, 30th:

Quote (cfsjohn)

As I will have hundreds of these image files generated daily, I believe it would be a good idea to do whatever I can that would reduce the size of the files

So that's become the major concern: File size. I just repeatedly point out that while your DLL now crops fine, it is besides the point, if its result files are not also shortening the files as much as they could. And I think it would be a shame to not use your perfect and simple cropping, Rick.

In the end cfsjohn will have to decide what's important and best for him, I'm just making my recommendations. I think I'll just stop here and leave it up to you both to finish this thread, have a good time, Rick! And all the best for your VFP clone project, too.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

Just one more suggestion to let the image.dll be usable for the most general case: Offer a method to change the color mode of the image as a functionality separate to cropping. If I understand you correctly this class is part of your VFP clone project. It's nothing VFP itself offers with its image control, it just displays an image as is and offers no manipulation other than is done by stretch to fit, which is certainly the reason your dll has the resize functionality. It would add to the capabilities to offer color mode change, but there's no harm to compatibility whhen your clone offers additional functionalities.

The monochrome preprocessing step is easily done with GDIPlusX, just a 4-liner as I showed, but you know cfsjohn has trouble getting GDIPlusX to work for him. Besides cropping is neither a feature of GDI+ nor GDIPlusX nor VFP image control, too.

By the way, I recently came across a bug (or is it by design?) of the VFP image control stretch. If you design a PNG image with a vertical color gradient from a color to transparency and make it 1 pixel wide only as you can stretch it to any width needed by the image control, VFP will cause a horizontal color gradient by stretching the width. The bug could be how GDI+ resizes, but that is annoying.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

If you look at bitmap1.h beginning at line 531, you can see the functions that are currently available to be exposed. I don't have any that will move it to a monochrome bitmap, but that shouldn't be too hard to add.

See if there are any other functions you'd like to see exposed. I've been extending this library for use with my upcoming x86 assembly tutorial as well, so I have added some text drawing functions, and layering functions which allow things to be changed on any layer, then merged into the visible layer for rendering. It allows special effects to be used, animations, layers to be turned on and off. Should make a nice addition for future tutorials as well.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

I added the conversion to mono. Something's not right though, the last 26 bytes of the file are showing all black. I don't know what's causing it yet. Will sort it out when I have time.

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

Thinking to use the DLL in the context of the image control the ones making sense would be
iBmp_grayscale
iiBmp_setPixel
iBmp_extractColorAtPoint
and the drawing functions for lines and text.

Get/set pixel is not that useful as slow as VFP is, but that could change with how you compile VFrP code.

If I think of what I'd use now in VFP it's either GDIPlusX to actually work on images with all GDI+ flat API functions available. Or workaraound using what VFP has itself. I'd not introduce GDIPlusX for simple purposes like adding text on an image, because that can also be done by a label control on top with background transparent instead of GDI+ text drawing on the image bitmap itself. And lines and shapes can be done with shape controls, too, even when that's a bit more tedious.

It would be nice to have support for vector graphic formats, if I could only pick one, SVG. But that would be more of a topic of bringing up a webbrowser control that could host a Chrome or FireFox render engine instead of IE, I'd not bother if I can also use the Edge engine. With any of them SVG is just one of so many more features made available by a webbrowser.

Chriss

RE: Open a jpg, mod jpg, close and save jpg

Here are the functions I'm adding. I have the ones at the top completed, the ones at the bottom I still need to code:

CODE

* These have been coded
DECLARE INTEGER bmp_grayscale               IN image.dll INTEGER nHandle, SINGLE fAlpha
DECLARE INTEGER bmp_set_pixel               IN image.dll INTEGER nHandle, INTEGER nX, INTEGER nY, INTEGER nRgb
DECLARE INTEGER bmp_get_pixel               IN image.dll INTEGER nHandle, INTEGER nX, INTEGER nY
DECLARE INTEGER bmp_colorize                IN image.dll INTEGER nHandle, INTEGER nULX, INTEGER nULY, INTEGER nLRX, INTEGER nLRY, INTEGER colorTemplate, SINGLE fAlpha
DECLARE INTEGER bmp_swap_colors             IN image.dll INTEGER nHandle, INTEGER colorOld, INTEGER colorNew
DECLARE INTEGER bmp_wavy_line               IN image.dll INTEGER nHandle, INTEGER nULX, INTEGER nULY, INTEGER nLRX, INTEGER nLRY, INTEGER colorLine
DECLARE INTEGER bmp_dapple                  IN image.dll INTEGER nHandle, INTEGER nHandleDapple, SINGLE fInfluence
DECLARE INTEGER bmp_draw_font               IN image.dll INTEGER nHandle, STRING cFontName, INTEGER nPointSize, INTEGER lBold, INTEGER lItalic, INTEGER lUnderline, INTEGER lStrikethru, STRING cText, INTEGER nX, INTEGER nY, INTEGER textColor
DECLARE INTEGER bmp_draw_font_fixed_point   IN image.dll INTEGER nHandle, INTEGER fontPixelsX, INTEGER fontPixelsY, STRING cText, INTEGER nTextLength, INTEGER nX, INTEGER nY, INTEGER foreColor, INTEGER backColor
DECLARE INTEGER bmp_draw_bullet             IN image.dll INTEGER nHandle, INTEGER nX, INTEGER nY, INTEGER colorBullet
* The rectangles are pixel coordinates from upper-left X,Y (nULX,nULY), to lower-right X,Y (nLRX,nLRY), the clipping rectangle
DECLARE INTEGER bmp_fill_rect               IN image.dll INTEGER nHandle, INTEGER nULX, INTEGER nULY, INTEGER nLRX, INTEGER nLRY, INTEGER nColorNW, INTEGER nColorNE, INTEGER nColorSW, INTEGER nColorSE, INTEGER lUseGradient
DECLARE INTEGER bmp_frame_rect              IN image.dll INTEGER nHandle, INTEGER nULX, INTEGER nULY, INTEGER nLRX, INTEGER nLRY, INTEGER nColorNW, INTEGER nColorNE, INTEGER nColorSW, INTEGER nColorSE, INTEGER lUseGradient
DECLARE INTEGER bmp_colorize_rect           IN image.dll INTEGER nHandle, INTEGER nULX, INTEGER nULY, INTEGER nLRX, INTEGER nLRY, INTEGER nColorNW, INTEGER nColorNE, INTEGER nColorSW, INTEGER nColorSE, INTEGER lUseGradient, SINGLE fAlpha
DECLARE INTEGER bmp_frame_in_nine_parts     IN image.dll INTEGER nHandle, INTEGER nULX, INTEGER nULY, INTEGER nLRX, INTEGER nLRY, INTEGER nHandleSrc
DECLARE INTEGER bmp_draw_line               IN image.dll INTEGER nHandle, INTEGER nX1, INTEGER nY1, INTEGER nX2, INTEGER nY2, INTEGER color
DECLARE INTEGER bmp_draw_quad               IN image.dll INTEGER nHandle, INTEGER nX1, INTEGER nY1, INTEGER nX2, INTEGER nY2, INTEGER nWidth, INTEGER lDrawEnds, INTEGER colorLine

* Still need to code these
DECLARE INTEGER bmp_colorize_line           IN image.dll INTEGER nHandle, INTEGER nX1, INTEGER nY1, INTEGER nX2, INTEGER nY2, INTEGER colorLine, SINGLE fAlpha
DECLARE INTEGER bmp_draw_line_gradient      IN image.dll INTEGER nHandle, INTEGER nX1, INTEGER nY1, INTEGER nX2, INTEGER nY2, SINGLE fRed, SINGLE fGrn, SINGLE fBlu, SINGLE fRedInc, SINGLE fGrnInc, SINGLE fBluInc
DECLARE INTEGER bmp_colorize_line_gradient  IN image.dll INTEGER nHandle, INTEGER nX1, INTEGER nY1, INTEGER nX2, INTEGER nY2, SINGLE fRed, SINGLE fGrn, SINGLE fBlu, SINGLE fRedInc, SINGLE fGrnInc, SINGLE fBluInc, SINGLE fAlpha 

--
Rick C. Hodgin

RE: Open a jpg, mod jpg, close and save jpg

I believe I have most everything tested here. Take a look at it and report any issues.

If you uncomment the various portions of code you can see how those parts work. I used image.prg for the class definition and for my algorithm testing. It can be extracted out to your apps however's needed. Will push the changes to GitHub this weekend if there are no bugs.

The convert to mono still isn't working properly, but it's close. I'll figure that out at a later date. I've been working on a scalable server app the past couple of weeks. It's taken most of my time.

Please see attached for image.zip, which contains image.prg and image.dll plus the source images used for some of the testing.

--
Rick C. Hodgin

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login


Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close