2007-01-29

Send Images to the Clipboard with GdiPlus-X REVISITED

Some days ago I posted a solution based on Alexander Golovlev's GpImage Gdi+ class showing how to send an image to the clipboard.

We agreed that although this function is not present originally on the "system.drawing" namespace from .net, it could represent a good addiction to the gdiplus-x livrary for vfp. so, the function "toClipboard()" was added to the bitmap class.

From now on, I mean from gdiplus-X release 0.07 and forward, we can send any Gdi+ compatible image to the clipboard using the new "toClipboard()" function just added to the bitmap class using the simple code below:

 

** the following code example demonstrates how to send an
** image to the clipboard
do locfile("system.app")
local lobmp as xfcbitmap
lobmp = _screen.system.drawing.
bitmap.new(getpict())
lobmp.toClipboard()

 

 

2007-01-24

IMPORTANT FIX FOR SAMPLES USING GRADIENTS

A strange error occured for some people when using some of the samples for the creation of gradients that I've been providing in this blog.

Some people reported that the original code was creating a black image instead of a gradient. in other cases, the error "cannot load 32-bit dll gdiplus" occured.

This happened because vfp was using different versions of gdiplus.dll installed on the machine. one version to draw the gradient and another version to draw just the gradients. if the machine had only one version of gdiplus.dll installed, even with more than one copy, all went ok. but some applications need a specific version of this library, and ms has already released more than 5 versions till this moment. after a long time testing i detected this using a simple "display dlls" command.

Special thanks to all people that reported this error, tested and helped to find the origin, specially to: Andrew Mcneill, Emerson Reed, Sergey Berezniker, Rui Nogueira, Randy Pearson, Sacchi. I can't forget the more than 70 people from my home, the brazilian foxbrasil community that very kindly tested many codes in different environments.

the fix:
we were using:
declare gdip..... in gdiplus etc etc

The correct is to change from "in gdiplus" to "in gdiplus.dll". on certain machines, this is causing some confusions, and makes vfp use more than one version, specially if the user already uses _gdiplus.vcx or the reportlistener.

Note that vfp declares gdiplus using ".dll" for its internal commands, and also in _gdiplus.vcx

In vfp9's help we can find:
"to ensure that you use the correct copy of gdiplus.dll, use the syntax in gdiplus.dll with no explicit path in your declare dll statements."
http://msdn2.microsoft.com/en-us/library/ms978941(vs.80).aspx

gradobjects class
I've just published the newest version of the class, that can be downloaded from this link. http://weblogs.foxite.com/files/vfpimaging/gradobjects/gradobjects.zip
i also hope to publish a new post explaining all the new features, fixes and samples, but for the moment, this version will help to eliminate the bug.

old posts
I've also updated all previous posts

gradient objects with gdi+ revisited

gradient backgrounds in your forms with gdi+ part2

gradient backgrounds in your forms with gdi+

outlook bar 2003:
The same problem could occur using this tremendous class. to fix it, please open the file outlook2003bar.vcx, select the class "outlook2003bar". sorry emerson !

In method "creategradientimage", please add a ".dll" in the declaration of the gradient gdi+ function, like this:

* declare api
declare long gdipcreatelinebrushi in gdiplus.dll ;
   string point1, string point2, ;
   long color1, long color2, ;
   long wrapmode, long @linegradient


Gdiplusx library
The whole library will receive this update too.
Hopefully, on the next release - 0.07 alpha we'll add this fix and some other features and cool new samples.
http://www.codeplex.com/vfpx/workitem/view.aspx?workitemid=7358

 

All gdiplus declarations:
Craig Boyd has a fantastic post in which he brings all 603 gdi+ declarations.
http://www.sweetpotatosoftware.com/spsblog/permalink,guid,d06cf377-c9ba-4eeb-93aa-b98ac115e895.aspx
They work perfectly, but take care to add a ".dll" after each declaration if you plan to use gdi+ using direct api calls.

2007-01-17

Capture Screens with GdiPlus-X

To capture a screen with Gdiplus-X is a very easy task too.
basically, all we need to do is to call the fromscreen() method from the bitmap class. To ease this task, this method brings some different overloads.

 

important:

All samples below use the Gdiplus-x library from VFPX. Download the latest stable release from codeplex:
http://www.codeplex.com/wiki/view.aspx?projectname=vfpx&title=gdiplusx

 

1 - capture a form screen sending the hwnd of the form or the form as an object 
do locfile("system.app") 

local locapturebmp as xfcbitmap
with _screen.system.drawing
locapturebmp = .bitmap.fromscreen(thisform.hwnd)
* could be also:
* locapturebmp = _screen.system.drawing.bitmap.fromscreen(thisform)
locapturebmp.save("c:\captured.png", .imaging.imageformat.png)
endwith

 2 - capture the whole screen
in this case, no parameter is needed to be passed
do locfile("system.app")

local locapturebmp as xfcbitmap
with _screen.system.drawing
locapturebmp = .bitmap.fromscreen()
locapturebmp.save("c:\capturedscreen.png", .imaging.imageformat.png)
endwith

 

3 - capture the screen of a form cutting off its borders and title.
for this task we use the sysmetric() function to obtain the measure of the screen elements, such as the title height, top and left borders. then we use another overload, sending the hwnd, and the coordinates of the form to be captured.

 
do locfile("system.app")

local lntitleheight, lnleftborder, lntopborder
lntitleheight = sysmetric(9)
lnleftborder = sysmetric(3)
lntopborder = sysmetric(4)

local locapturebmp as xfcbitmap

with _screen.system.drawing
locapturebmp = .bitmap.fromscreen(;
thisform.hwnd, ;
lnleftborder, ;
lntitleheight + lntopborder, ;
thisform.width, ;
thisform.height)

locapturebmp.save("c:\captured.png", .imaging.imageformat.png)
endwith




 

4 - capture all forms in the screen.
this is very simple too. just create a loop through all _screen forms and capture each of them, sending the form.hwnd as a parameter.

 
do locfile("system.app")

local locapturebmp as xfcbitmap
local n
local loform as form
n = 1

with _screen.system.drawing

for each loform in _screen.forms
locapturebmp = .bitmap.fromscreen(loform.hwnd)
locapturebmp.save("c:\capturedform" + transform(n) + ".png", ;
.imaging.imageformat.png)
n = n + 1
endfor

endwith

Print Individual Images Revisited

Referring to a previous post, from may 2006 entitled "Print individual images", Naomi Nosonovsky asks for the possibility to obtain a better control over the image.

That's really easy, and the original code needed a very simple modification, in a first moment clearing and then sending the desired information to the expr field of the report table.

The EXPR, TAG, and TAG2 columns in the header record are used for printer setup attributes.

In some limited cases, we may edit the values in the expr column and, if these values are reasonable for the associated attributes, they will be recognized by the designer, and used by the report engine at run time.

For example, if a report definition includes in the expr field : orientation=1, copies=3 and color=1, we will obtain a landscape report, three printed copies and an image printed in greyscale.

For the case related, we need to pass these information as parameters for the udf printimage(), eg.

=PrintImage(getpict(), "orientation=1" + chr(13) + "copies=3"

Notice that I added a CHR(13) to separate each configuration. That's very important, and VFP needs this to recognize the settings.

 

Here are some of the available settings:

driver=winspool
device=ms publisher imagesetter
output=file:
orientation=0 (0 = portrait ; 1 = landscape)
papersize=1
scale=100
ascii=100
copies=1
defaultsource=15
printquality=600
color=1 (0 = color ; 1 = greyscale)
yresolution=600
ttoption=2
collate=1


We can find precious information about these settings in vfp's help for prtinfo(): http://msdn2.microsoft.com/en-us/library/7h4yx3sf(vs.80).aspx

 

Here's the code - save it as PRINTIMAGE.PRG and call it like this:

 

= PrintImage (getpict(),"copies = 2" + chr(13) + "orientation = 1" + chr(13) + "color = 1")

* program: printimage.prg
function P
rintImage(tcimage, tcprintsettings)
*--------------------------------------------------------
* vfp code that shows how to print image files.
* code adapted from microsoft knowledge base article
* 895602.
http://support.microsoft.com/kb/895602/en-us/
*
* most of the codes and comments below come from
* trevor hancock, from ms
*--------------------------------------------------------
*--------------------------------------------------------
* parameters accepted:
* tcimage = image file name
* tcprintsettings = special printing settings, that allow to choose orientation, copies, etc
* eg. "copies = 2" + chr(13) + "orientation = 1"
* will print 2 copies with orientation set as landscape
* more printer settings can be found at vfp help for prtinfo()
* below is an example with some of the parameters allowed:
* driver=winspool
* device=ms publisher imagesetter
* output=file:
* orientation=0
* papersize=1
* scale=100
* ascii=100
* copies=1
* defaultsource=15
* printquality=600
* color=1
* yresolution=600
* ttoption=2
* collate=1
* if no parameter is passed, will print using the default printer settings
*--------------------------------------------------------
* related links
* msdn - prtinfo()
*
http://msdn2.microsoft.com/en-us/library/7h4yx3sf(vs.80).aspx
* pete sass : the visual foxpro report writer
* http://www.foxite.com/articles/read.aspx?id=24&document=the-visual-foxpro-report-writer

local
lnarea
lnarea =
select()
create cursor
reporttemp (imagefile c(150))
insert into
reporttemp values (tcimage)
*-- this calls a function that makes a report programmatically.
*-- this is included here to make sure that this sample can be run
*-- as-is, without asking the developer to manually create a report.

makereport(tcprintsettings)

*-- make sure that the cursor is selected,
*-- and then run the report to preview using
*-- the instance of our report listener.

select
reporttemp
report form
___imagereport preview
delete file
"___imagereport.fr*"
select
(lnarea)
return


 

*--------------------------------
*-- this function programmatically creates a report
*-- with an ole bound control and other fields. this is included
*-- only for demonstration purposes so this article code can stand-alone.
*-- typically, you would create your own report manually by using
*-- the report designer.

function
makereport(tcprintsettings)

if vartype(tcprintsettings) <> "c"
tcprintsettings = ""

endif

tcprintsettings =
strtran(tcprintsettings, " ", "")

create report ___imagereport from reporttemp

*-- open the report file (frx) as a table.
use
___imagereport.frx in 0 alias thereport exclusive
select
thereport

*-- remove from the frx the auto generated fields and labels
delete from
thereport where objtype = 5 and objcode = 0 && remove the labels
delete from
thereport where objtype = 8 and objcode = 0 && remove the fields

*-- find the header record (normally the first one, but who knows)
locate for
objtype = 1 and objcode = 53
if found
()
replace tag with "",; && clears the tag, tag2
tag2 with "",;
expr with tcprintsettings && stores the new expr
endif

*-- add a picture/ole bound control to the report by inserting a
*-- record with appropriate values. using an object that is based on the empty
*-- class here and the gather name class later to insert the record makes it easier to
*-- see which values line up to which fields (when compared to a large
*-- sql-insert command).

local
lonewrecobj as empty
lonewrecobj =
newobject( 'empty' )
addproperty
( lonewrecobj, 'platform', 'windows' )
addproperty
( lonewrecobj, 'uniqueid', sys(2015) )
addproperty
( lonewrecobj, 'objtype', 17 ) && "picture/ole bound control"
addproperty
( lonewrecobj, 'name', 'reporttemp.imagefile' ) && the object ref to the image object.
addproperty
( lonewrecobj, 'hpos', 100)
addproperty
( lonewrecobj, 'vpos', 600)
addproperty
( lonewrecobj, 'height', 100000)
addproperty
( lonewrecobj, 'width', 100000)
addproperty
( lonewrecobj, 'double', .t. ) && picture is centered in the "picture/ole bound control"
addproperty
( lonewrecobj, 'supalways', .t. )
*-- for the picture/ole bound control, the contents of the offset field specify whether
*-- filename (0), general field name (1), or expression (2) is the source.

addproperty
( lonewrecobj, 'offset', 2 )
*-- add the picture/ole bound control record to the report.

append blank in
thereport
gather name
lonewrecobj memo
*-- clean up and then close the report table.

pack
use in select
('thereport')
endfunc

2007-01-09

Send Images to the Clipboard with GdiPlus-X

Important: THIS IS AN OLD SAMPLE, KEPT HERE ONLY FOR A SAMPLE CODE. SEE THE METHOD 'TOCLIPBOARD()' IN GDIPLUSX

All samples below use the new GdiPlus-X library, from VFPX
http://www.codeplex.com/wiki/view.aspx?projectname=vfpx&title=gdiplusx

 

 
** the following code example demonstrates how to send an
** image to the clipboard
** sample totally based on the method "toclipboard" from gpimage gdi+ class
** from alexander golovlev

DO LOCFILE("system.app")
WITH _SCREEN.SYSTEM.drawing
LOCAL lobmp AS xfcbitmap
lobmp = .BITMAP.new(GETPICT())
LOCAL lhbitmap, hbmp, hndl
lhbitmap = lobmp.gethbitmap(.COLOR.lightgray)

#DEFINE err_clipnotopen "cannot open the clipboard"
#DEFINE err_clipnodata "no bitmap data found on the clipboard"
#DEFINE err_clipsetdata "cannot place data on the clipboard"

*-- predefined clipboard formats
#DEFINE cf_bitmap 2
#DEFINE cf_palette 9
#DEFINE obj_bitmap 7

DECLARE LONG openclipboard IN win32api LONG HWND
DECLARE LONG closeclipboard IN win32api
DECLARE LONG emptyclipboard IN win32api
*declare long getclipboarddata in win32api long uformat
DECLARE LONG setclipboarddata IN win32api LONG uformat, LONG HMEM
DECLARE LONG copyimage IN win32api LONG himage, LONG utype, LONG cx, LONG cy, LONG uflags
DECLARE LONG deleteobject IN win32api LONG hobject

hbmp = copyimage(lhbitmap, 0, 0, 0, 0)
deleteobject(lhbitmap)

IF openclipboard(0) != 0
emptyclipboard()
hndl = setclipboarddata(cf_bitmap, hbmp)
closeclipboard()
IF hndl = 0
ERROR err_clipsetdata
ENDIF
ELSE
ERROR err_clipnotopen
ENDIF

ENDWITH
RETURN