Using Win32 functions in Visual FoxPro Image Gallery
Code examples:
Converting image file to .ICO file
How to change display settings: screen resolution, screen refresh rate
Capturing keyboard activity of another application with the Raw Input API (VFP9)
Custom GDI+ class
GDI+: copying to the Clipboard (a) image of active FoxPro window/form, (b) image file
How to display Windows On-Screen Keyboard
Mapping and disconnecting network drives
Custom HttpRequest class (WinINet)
Enumerating raw input devices attached to the system (keyboard, mouse, human interface device)
How to prevent users from accessing the Windows Desktop and from switching to other applications
Winsock: sending email messages (SMTP, port 25)
Using Video Capture: displaying on FoxPro form frames and previewing video obtained from a digital camera
Converting Unicode data from the Clipboard to a character string using a given code page
GDI+: custom Clock Control
How to detect if additional monitor is connected and active
How to set Creation Date/Time for a folder (WinNT)
How to convert a bitmap file to monochrome format (1 bpp)
Using WM_COPYDATA for interprocess communication (VFP9)
Reading security permissions for NTFS files and folders
Custom HttpRequest class (WinHTTP)
HOWTO: Use the Win32 API to Access File Dates and Times
Printing Image File, programmatically set print page orientation to landscape
GDI+: how to make VFP controls visually shake and shudder
How to create MD-5 and SHA-1 hash values from a string
GDI+: reading and writing metadata in JPEG and TIFF files

User rating: 0/10 (0 votes)
Rate this code sample:
  • ~
More code examples    Listed functions    Add comment     W32 Constants      Translate this page Printer friendly version of this code sample
Versions:
click to open
Before you begin:
Most of JPEG files contain some metadata, especially files created with digital cameras.
Here is an example:



MIcrosoft SDK includes GdiplusImaging.h header file with definitions of many (not all) PropertyItem IDs. For example:
#define PropertyTagImageDescription 0x010E
#define PropertyTagEquipMake 0x010F
#define PropertyTagEquipModel 0x0110
...
#define PropertyTagExifShutterSpeed 0x9201
#define PropertyTagExifAperture 0x9202
#define PropertyTagExifBrightness 0x9203
#define PropertyTagExifExposureBias 0x9204
#define PropertyTagExifMaxAperture 0x9205
...


The following code shows how to read this data from JPEG and TIFF image files. PNG files have limited support of this functionality. BMP and GIF files, afaik, do not support metadata storage.

The code is based on custom GDI+ class. Download the class module first and save it in gdiplus.prg file.
#DEFINE PropertyTagPropComments     0x9C9C
#DEFINE PropertyTagImageDescription 0x010E

#DEFINE PropertyTagTypeByte  1
#DEFINE PropertyTagTypeASCII 2
#DEFINE PropertyTagTypeShort 3
#DEFINE PropertyTagTypeLong 4
#DEFINE PropertyTagTypeRational 5
#DEFINE PropertyTagTypeUndefined 7
#DEFINE PropertyTagTypeSLONG 9
#DEFINE PropertyTagTypeSRational 10

SET PROCEDURE TO gdiplus ADDITIVE

PRIVATE gdip, src
gdip = CREATEOBJECT("gdiplusinit_")

* load source file into memory
src = CREATEOBJECT("gdiimage_", "c:\temp\img001.jpg")
IF src.errorcode <> 0
    ? "Could not load source image file"
    RETURN
ENDIF

DO ListPropertItems
*= AddMemo("White and Black on Green", "c:\temp\temp.jpg")
* end of main

PROCEDURE ListPropertItems
    LOCAL propertyitem As ImagePropertyItem

    src.GetPropertyItems
    IF src.propertyitems.Count = 0
        ? "The file contains no property items."
    ELSE
        CREATE CURSOR cs (propid C(10), proptype I,;
            proplen I, propvalue M)

        FOR EACH propertyitem IN src.propertyitems
            WITH propertyitem
                INSERT INTO cs VALUES (TRANSFORM(.propid,"@0"),;
                    .proptype, LEN(.propvalue), .propvalue)
            ENDWITH
        ENDFOR
        GO TOP
        BROWSE NORMAL NOWAIT
    ENDIF

PROCEDURE AddMemo(cMemo, cNewFilename)
* adds description to the image object
* and saves it to another file
    LOCAL nPropertyTag, nPropertyType
*    nPropertyTag = PropertyTagImageDescription
    nPropertyTag = PropertyTagPropComments

    nPropertyType = PropertyTagTypeByte
*    nPropertyType = PropertyTagTypeASCII

    * convert to Unicode if PropertyTagTypeByte used
    * no convertion is required for PropertyTagTypeASCII
    IF nPropertyType = PropertyTagTypeByte
        cMemo = STRCONV(cMemo+CHR(0), 5)
    ENDIF

    WITH src
        IF NOT .SetPropertyItem(nPropertyTag, nPropertyType, m.cMemo)
            ? "SetPropertyItem error:", .errorcode
            RETURN .F.
        ENDIF
        IF NOT .SaveToFile(cNewFilename)
            ? "SaveToFile error:", .errorcode
            RETURN .F.
        ENDIF
    ENDWITH
RETURN .T.

DEFINE CLASS gdiplusinit_ As gdiplusinit
* subclassed to add few more DECLARE statements
PROCEDURE declare
    DODEFAULT()
    DECLARE INTEGER GlobalAlloc IN kernel32 INTEGER wFlags, INTEGER dwBytes
    DECLARE INTEGER GlobalFree IN kernel32 INTEGER hMem

    DECLARE INTEGER GdipGetPropertyIdList IN gdiplus;
        INTEGER img, LONG numOfProperty, STRING @lst

    DECLARE INTEGER GdipGetPropertyCount IN gdiplus;
        INTEGER img, LONG @numOfProperty

    DECLARE INTEGER GdipGetPropertyItemSize IN gdiplus;
        INTEGER img, INTEGER propId, LONG @sze

    DECLARE INTEGER GdipGetPropertyItem IN gdiplus;
        INTEGER img, INTEGER propId, LONG propSize, STRING @buffer

    DECLARE INTEGER GdipSetPropertyItem IN gdiplus;
        INTEGER img, STRING @itm

    DECLARE INTEGER GdipRemovePropertyItem IN gdiplus;
        INTEGER img, INTEGER propId
ENDDEFINE

DEFINE CLASS gdiimage_ As gdiimage
* subsclassed to add reading PropertyItems functionality
    propertyitems=0

PROCEDURE RemovePropertyItem(propId)
    IF VARTYPE(m.propId)="O"
        THIS.errorcode =;
            GdipRemovePropertyItem(THIS.himage, propId.propId)
    ELSE
        THIS.errorcode =;
            GdipRemovePropertyItem(THIS.himage, m.propId)
    ENDIF
RETURN (THIS.errorcode=0)

PROCEDURE SetPropertyItem(p1, p2, p3)
    LOCAL propertyitem, cBuffer
    IF VARTYPE(m.p1)="O"
        propertyitem=m.p1
    ELSE
        propertyitem = CREATEOBJECT("ImagePropertyItem", m.p1, m.p2, m.p3)
    ENDIF

    cBuffer = propertyitem.ToString()
    THIS.errorcode = GdipSetPropertyItem(THIS.himage, @cBuffer)
    IF THIS.errorcode=0
        THIS.GetPropertyItems
    ENDIF
RETURN (THIS.errorcode=0)

PROCEDURE GetPropertyItems
* populates collection with existing property items 
    THIS.propertyitems = CREATEOBJECT("Collection")

    LOCAL nCount, nIndex, cIDs, nId, nItemSize, cItemBuffer
    STORE 0 TO nCount
    = GdipGetPropertyCount(THIS.himage, @nCount)

    cIDs = REPLICATE(CHR(0), nCount*4)
    = GdipGetPropertyIdList(THIS.himage, nCount, @cIDs)

    FOR nIndex=0 TO nCount-1
        nId = buf2dword(SUBSTR(cIDs, nIndex*4+1, 4))
        nItemSize=0
        = GdipGetPropertyItemSize(THIS.himage, nId, @nItemSize)
        cItemBuffer = REPLICATE(CHR(0), nItemSize)
        = GdipGetPropertyItem(THIS.himage, nId, nItemSize, @cItemBuffer)

        LOCAL nProplen, PropertyItem As ImagePropertyItem
        nProplen = buf2dword(SUBSTR(cItemBuffer, 5,4))

        PropertyItem = CREATEOBJECT("ImagePropertyItem",;
            buf2dword(SUBSTR(cItemBuffer, 1,4)),;
            buf2dword(SUBSTR(cItemBuffer, 9,4)),;
            SUBSTR(cItemBuffer, 17, nProplen))

        THIS.propertyitems.Add(PropertyItem,;
            TRANSFORM(PropertyItem.propid))
    ENDFOR
ENDDEFINE

DEFINE CLASS ImagePropertyItem As Session
PROTECTED hData
    propid=0
    proptype=0
    propvalue=""

PROCEDURE Init(p1, p2, p3)  && id, type, buffer
    THIS.propid=m.p1
    THIS.proptype=m.p2
    THIS.propvalue=m.p3
    THIS.hData=0

FUNCTION GetPropertyValue
* converts the buffer to appropriate FoxPro data type
    LOCAL vtype
    vtype = VARTYPE(THIS.propvalue)

    DO CASE
    CASE m.vtype <> "C"
        RETURN THIS.propvalue
    CASE m.vtype=PropertyTagTypeShort AND LEN(THIS.propvalue)=2
        RETURN buf2word(THIS.propvalue)
    CASE m.vtype=PropertyTagTypeLong AND LEN(THIS.propvalue)=4
        RETURN buf2dword(THIS.propvalue)
    CASE m.vtype=PropertyTagTypeRational AND LEN(THIS.propvalue)=4
        RETURN float2int(buf2dword(THIS.propvalue))
    CASE m.vtype=PropertyTagTypeSLONG AND LEN(THIS.propvalue)=4
        RETURN buf2dword(THIS.propvalue)
    CASE m.vtype=PropertyTagTypeSRational AND LEN(THIS.propvalue)=4
        RETURN float2int(buf2dword(THIS.propvalue))
    OTHERWISE
    * the value stays in form of string (array of bytes)
        RETURN THIS.propvalue
    ENDCASE

PROCEDURE Destroy
    THIS.ReleaseData

PROTECTED PROCEDURE ReleaseData
    IF THIS.hData <> 0
        = GlobalFree(THIS.hData)
        THIS.hData=0
    ENDIF

PROCEDURE ToString
    THIS.ReleaseData

    LOCAL propvalue, proplen
    propvalue = THIS.propvalue

    IF VARTYPE(m.propvalue) = "N"
        DO CASE
        CASE INLIST(THIS.proptype,;
            PropertyTagTypeRational, PropertyTagTypeSRational)
            propvalue = num2dword(int2float(m.propvalue))
        CASE THIS.proptype = PropertyTagTypeShort
            propvalue = num2word(m.propvalue)
        CASE THIS.proptype = PropertyTagTypeByte
            propvalue = CHR(BITAND(m.propvalue, 0x00ff))
        OTHERWISE
            propvalue = num2dword(m.propvalue)
        ENDCASE
    ENDIF
    proplen = LEN(THIS.propvalue)

    DECLARE RtlMoveMemory IN kernel32 As StrToMem;
        INTEGER Dest, STRING Src, INTEGER nLength

    THIS.hData = GlobalAlloc(0, m.proplen)
    = StrToMem(THIS.hData, m.propvalue, m.proplen)

RETURN num2dword(THIS.propid) + num2dword(m.proplen) +;
        num2dword(THIS.proptype) + num2dword(THIS.hData)
ENDDEFINE


User rating: 0/10 (0 votes)
Rate this code sample:
  • ~
6631 bytes  
Created: 2004-07-28 13:39:30  
Modified: 2011-08-15 20:34:40  
Visits in 7 days: 92  
Listed functions:
GdipGetPropertyCount
GdipRemovePropertyItem
GdipSetPropertyItem
GlobalAlloc
GlobalFree
Printer friendly API declarations
My comment:
There are several PropertyTag IDs not included in GdiplusImaging.h header file:

#DEFINE PropertyTagPropTitle 0x9c9b
#DEFINE PropertyTagPropComments 0x9c9c
#DEFINE PropertyTagPropAuthor 0x9c9d
#DEFINE PropertyTagPropKeywords 0x9c9e
#DEFINE PropertyTagPropSubject 0x9c9f

This picture shows corresponding properties:



So with GDI+ you can scan JPEG and TIFF image files and check, for example, keywords or author name included. As you can see from this particular example, it is possible to add or modify metadata in image files.

Some links I saved for later on:
  • http://www.php-websource.com/php436/source-exif.htm
  • http://www.opensource.apple.com/darwinsource/10.3/apache_mod_php-12/php/ext/exif/exif.c

    And how do you like that:
    /* Olympus specific tags */
    #define TAG_OLYMPUS_SPECIALMODE 0x0200
    #define TAG_OLYMPUS_JPEGQUAL 0x0201
    #define TAG_OLYMPUS_MACRO 0x0202
    #define TAG_OLYMPUS_DIGIZOOM 0x0204
    #define TAG_OLYMPUS_SOFTWARERELEASE 0x0207
    #define TAG_OLYMPUS_PICTINFO 0x0208
    #define TAG_OLYMPUS_CAMERAID 0x0209

    /* end Olympus specific tags */


    * * *
    Naturally you would like to open image file, add or change property, then close the file saving the updates. It does not work this way for current GDI+ version.

    You may create gdiplus image object from a disk file and add new or change existing property item for this object. But you have to save it to another image file to keep this new property. The original file can not be rewritten until this inherited image object is released.

    Save comments and descriptions using either PropertyTagPropComments or PropertyTagImageDescription property ids (some other ids may suit too). For saving Unicode strings use PropertyTagTypeByte type, for regular ASCII the PropertyTagTypeASCII is Ok.

    #kwd: sln_gdiplus.
  • Word Index links for this example:
    Translate this page:
      Spanish    Portuguese    German    French    Italian  
    FreeTranslation.com offers instant, free translations of text or web pages.
    User Contributed Notes:
    There are no notes on this subject.


    Copyright 2001-2014 News2News, Inc. Before reproducing or distributing any data from this site please ask for an approval from its owner. Unless otherwise specified, this page is for your personal and non-commercial use. The information on this page is presented AS IS, meaning that you may use it at your own risk. Microsoft Visual FoxPro and Windows are trade marks of Microsoft Corp. All other trademarks are the property of their respective owners. 

    Privacy policy
    Credits: PHP (4.4.9), an HTML-embedded scripting language, MySQL (5.1.68), the Open Source standard SQL database, AceHTML Freeware Version 4, freeware HTML Editor of choice.   Hosted by Korax Online Inc.
    Last Topics Visited (54.197.218.127)
    16 sec.Example: 'Retrieving the name of the network resource associated with a local device'
    Google
    Advertise here!