Get Image Dimensions

Hello Baltazar
Not that I know of. You have to parse the header (according to the image format, jpeg, png, gif, bmp...) and extract the dimensions from there.
What type of image do you need to have the dimensions for?
++
JC
 

Cringer

ProgressTalk.com Moderator
Staff member
If you're on Windows and on a modern OE version you can probably use the .Net Framework.
 

balta

Member
Found the solution!

Code:
DEFINE VARIABLE vImage AS System.Drawing.Image NO-UNDO.

vImage = System.Drawing.Image:FromFile("s:\imagens_web\1010150005000528_web.jpg") .
MESSAGE "Width: " + string(vImage:Width) + ", Height: " + string(vImage:Height)
        VIEW-AS ALERT-BOX INFO BUTTONS OK.
 
Great! It's a pity the .Net/AVM bridge is only available on Windows (much more now that .Net core has been made available as free software and works e.g. on Linux); cannot use it myself as I'm doing portable code which must work accross OSes.
 

balta

Member
We use Windows, so no problem.

With Leak Memory Fix

Code:
DEFINE VARIABLE vImage AS System.Drawing.Image NO-UNDO.

vImage = System.Drawing.Image:FromFile("s:\imagens_web\1010150005000528_web.jpg") .
MESSAGE "Width: " + string(vImage:Width) + ", Height: " + string(vImage:Height)
        VIEW-AS ALERT-BOX INFO BUTTONS OK.
vImage:Dispose().
 

Cecil

19+ years progress programming and still learning.
I wrote this about 6 years ago. Could do with some Improvements:
It's native non .NET

Source code found here:

Jimbobnz/ABL_Get_Image_Diementions

Code:
FUNCTION progress_jpeg RETURNS INTEGER EXTENT 2 (INPUT imageData AS MEMPTR):
   
    DEFINE VARIABLE in_offset           AS INTEGER  NO-UNDO.
    DEFINE VARIABLE in_marker           AS INTEGER  NO-UNDO.
    DEFINE VARIABLE in_length           AS INTEGER  NO-UNDO.
    DEFINE VARIABLE in_FileSize         AS INTEGER  NO-UNDO.
    DEFINE VARIABLE in_ImageDimensions  AS INTEGER  NO-UNDO INITIAL ? EXTENT 2 .

    /* JPEG files are all big-endian byte order.*/
    SET-BYTE-ORDER(imageData) = BIG-ENDIAN.

    MESSAGE 'JPEG'.

    in_offset   = 3. /** Ignore the first two bytes.**/
    in_FileSize = GET-SIZE(ImageData).

    Byte-Scan:
    DO WHILE in_offset LT in_FileSize:
                   
        in_marker = GET-UNSIGNED-SHORT(ImageData,in_offset).
        in_length = GET-UNSIGNED-SHORT(ImageData,in_offset + 2).

        IF (in_marker EQ 0xFFC0 OR in_marker EQ 0xFFC2) THEN
        DO:
            ASSIGN              
                in_ImageDimensions[2] = GET-UNSIGNED-SHORT(ImageData,in_offset + 5)  /** Width **/
                in_ImageDimensions[1] = GET-UNSIGNED-SHORT(ImageData,in_offset + 7). /** Height **/

            LEAVE Byte-Scan.
        END.
   
        in_offset = in_offset + in_length + 2.
    END.

    RETURN in_ImageDimensions.
END FUNCTION.

FUNCTION progress_png RETURNS INTEGER EXTENT 2 (INPUT imageData AS MEMPTR):

    DEFINE VARIABLE in_ImageDimensions  AS INTEGER   NO-UNDO EXTENT 2 INITIAL ?.

    MESSAGE 'PNG'.

    /* PNG file are in network byte order (big-endian) */
    SET-BYTE-ORDER(imageData) = BIG-ENDIAN.

    ASSIGN
        in_ImageDimensions[1] = GET-UNSIGNED-LONG(imageData,17)  /** Width **/
        in_ImageDimensions[2] = GET-UNSIGNED-LONG(imageData,21). /** Height **/
    SET-SIZE(imageData) = 0 .
    RETURN in_ImageDimensions.
END FUNCTION.

FUNCTION progress_bmp RETURNS INTEGER EXTENT 2 (INPUT imageData AS MEMPTR):
    DEFINE VARIABLE in_ImageDimensions  AS INTEGER   NO-UNDO EXTENT 2 INITIAL ?.
    /** All of the integer values are stored in little-endian format (i.e. least-significant byte first). **/
    SET-BYTE-ORDER(imageData) = LITTLE-ENDIAN.
    MESSAGE 'BMP'.
   
    ASSIGN
        in_ImageDimensions[1] = GET-UNSIGNED-LONG(imageData,19) /** Width **/
        in_ImageDimensions[2] = GET-UNSIGNED-LONG(imageData,23). /** Height **/

    SET-SIZE(imageData) = 0 .
    RETURN in_ImageDimensions.
END FUNCTION.


FUNCTION progress_gif RETURNS INTEGER EXTENT 2 (INPUT imageData AS MEMPTR):
    DEFINE VARIABLE in_ImageDimensions AS INTEGER EXTENT 2 NO-UNDO.
    /** All of the integer values are stored in little-endian format (i.e. least-significant byte first). **/
    SET-BYTE-ORDER(imageData) = LITTLE-ENDIAN.

    MESSAGE 'GIF'.

    ASSIGN
        in_ImageDimensions[1] = GET-SHORT(imageData,7)  /** Width **/
        in_ImageDimensions[2] = GET-SHORT(imageData,9). /** Height **/

    SET-SIZE(imageData) = 0 .
    RETURN in_ImageDimensions.
END FUNCTION.

FUNCTION GetImageDimensions RETURNS INTEGER EXTENT 2 (INPUT ch_filename AS CHARACTER):

    DEFINE VARIABLE imageData           AS MEMPTR    NO-UNDO.
    DEFINE VARIABLE in_ImageDimensions  AS INTEGER   NO-UNDO EXTENT 2 INITIAL ?.
    DEFINE VARIABLE rPNGSignature  AS RAW NO-UNDO.
    DEFINE VARIABLE rBMPSignature  AS RAW NO-UNDO.
    DEFINE VARIABLE rGIFSIGNATURE  AS RAW NO-UNDO.
    DEFINE VARIABLE rJPEGSignature AS RAW NO-UNDO.
   
    rPNGSignature  = HEX-DECODE('89504E470D0A1A0A':U).
    rBMPSignature  = HEX-DECODE('424D':U).
    rGIFSignature  = HEX-DECODE('47494638':U).
    rJPEGSignature = HEX-DECODE('FFD8FF':U).

    ch_filename = SEARCH(ch_filename).

    IF ch_filename EQ ? THEN
        RETURN in_ImageDimensions.

    SET-SIZE(imageData) = 0.    /** Always reset your MEMPTRs **/
    COPY-LOB FROM FILE ch_filename TO OBJECT imageData.

/************************************/
/* DEBUG CODE ***********************/
/************************************/

/*     DEFINE VARIABLE iBYTE   AS INTEGER     NO-UNDO.                              */
/*     DEFINE VARIABLE imageRAW AS RAW       NO-UNDO.                               */
/*                                                                                  */
/*     OUTPUT STREAM sDebug TO 'hex-encoded.txt'.                                  */
/*                                                                                  */
/*     DO iBYTE = 1 TO GET-SIZE(ImageData):                                         */
/*         imagERAW= GET-BYTES(ImageData,iBYTE,1).                                  */
/*         PUT STREAM sDebug UNFORMATTED TRIM(STRING(HEX-ENCODE(imagERAW))) + ' '. */
/*         IF iBYTE MOD 16 EQ 0 THEN                                                */
/*             PUT STREAM sDebug SKIP.                                             */
/*     END.                                                                         */
/*     OUTPUT STREAM sDebug CLOSE.                                                 */

    /** Magic Number for File Tpye Identification..**/
    CASE TRUE:
        WHEN GET-BYTES(imageData,1,3)  EQ rJPEGSignature THEN  /** JPEG **/
            in_ImageDimensions = progress_jpeg(INPUT imageData ).

        WHEN GET-BYTES(imageData,1,8)  EQ rPNGSignature THEN /** PNG **/
            in_ImageDimensions = progress_png(INPUT imageData ).
   
        WHEN GET-BYTES(imageData,1,2)  EQ rBMPSignature THEN /** BMP **/
            in_ImageDimensions = progress_bmp(INPUT imageData ).

        WHEN GET-BYTES(imageData,1,4) EQ rGIFSignature THEN /** GIF **/
            in_ImageDimensions = progress_gif(INPUT imageData ).
    END CASE.

    SET-SIZE(imageData) = 0.  /** Always reset your MEMPTRs **/

    RETURN in_ImageDimensions.
END FUNCTION.


DEFINE STREAM sDebug.  

DEFINE VARIABLE in_ImageDimensions AS INTEGER NO-UNDO EXTENT 2 INITIAL ?.

in_ImageDimensions = GetImageDimensions(INPUT "webspeed\images\pscpbp1.gif").          
/* in_ImageDimensions = GetImageDimensions(INPUT "webspeed\samples\internet\cat00029.jpg"). */
/* in_ImageDimensions = GetImageDimentions(INPUT "netsetup\setup.bmp").  */
/* in_ImageDimensions = GetImageDimentions(INPUT "jdk\jre\lib\servicetag\jdk_header.png"). */

MESSAGE 'Width' in_ImageDimensions[1] SKIP
        'Height' in_ImageDimensions[2]
    VIEW-AS ALERT-BOX INFO.
 
Last edited:

Cecil

19+ years progress programming and still learning.
 
I finally found the method I wrote:

Code:
METHOD STATIC PUBLIC VOID getPictureInfo (
    pImage    AS CHARACTER
   ,OUTPUT opcType   AS CHARACTER
   ,OUTPUT opiWidth  AS INTEGER 
   ,OUTPUT opiHeight AS INTEGER):

    DEFINE VARIABLE mImage  AS MEMPTR      NO-UNDO.
    DEFINE VARIABLE iPos    AS INTEGER     NO-UNDO.
    DEFINE VARIABLE lSkip   AS LOGICAL     NO-UNDO.

    SET-SIZE(mImage) = 32.
    INPUT FROM VALUE(SEARCH(pImage)) BINARY NO-MAP NO-CONVERT NO-ECHO.
    IMPORT mImage.
    INPUT CLOSE.

    IF    GET-BYTE(mImage, 1) = 137
      AND GET-BYTES(mImage, 2, 3) = "PNG"
      AND GET-BYTE(mImage, 5) = 13 AND GET-BYTE(mImage, 6) = 10
      AND GET-BYTE(mImage, 7) = 26 AND GET-BYTE(mImage, 8) = 10 THEN DO:
        ASSIGN
         opcType = "image/png"
         opiWidth  = 16777216 * GET-BYTE(mImage, 17) + 65536 * GET-BYTE(mImage, 18) + 256 * GET-BYTE(mImage, 19) + GET-BYTE(mImage, 20)
         opiHeight = 16777216 * GET-BYTE(mImage, 21) + 65536 * GET-BYTE(mImage, 22) + 256 * GET-BYTE(mImage, 23) + GET-BYTE(mImage, 24).
    END. /* PNG */

    &GLOBAL-DEFINE M_SOF0  192 /* 0xC0 */      /* Start Of Frame N */
    &GLOBAL-DEFINE M_SOF1  193 /* 0xC1 */      /* N indicates which compression process */
    &GLOBAL-DEFINE M_SOF2  194 /* 0xC2 */      /* Only SOF0-SOF2 are now in common use */
    &GLOBAL-DEFINE M_SOF3  195 /* 0xC3 */
    &GLOBAL-DEFINE M_SOF5  197 /* 0xC5 */      /* NB: codes C4 and CC are NOT SOF markers */
    &GLOBAL-DEFINE M_SOF6  198 /* 0xC6 */
    &GLOBAL-DEFINE M_SOF7  199 /* 0xC7 */
    &GLOBAL-DEFINE M_SOF9  201 /* 0xC9 */
    &GLOBAL-DEFINE M_SOF10 202 /* 0xCA */
    &GLOBAL-DEFINE M_SOF11 203 /* 0xCB */
    &GLOBAL-DEFINE M_SOF13 205 /* 0xCD */
    &GLOBAL-DEFINE M_SOF14 206 /* 0xCE */
    &GLOBAL-DEFINE M_SOF15 207 /* 0xCF */
    &GLOBAL-DEFINE M_SOI   216 /* 0xD8 */      /* Start Of Image (beginning of datastream) */
    &GLOBAL-DEFINE M_EOI   217 /* 0xD9 */      /* End Of Image (end of datastream) */
    &GLOBAL-DEFINE M_SOS   218 /* 0xDA */      /* Start Of Scan (begins compressed data) */
    &GLOBAL-DEFINE M_APP0  224 /* 0xE0 */      /* Application-specific marker, type N */
    &GLOBAL-DEFINE M_APP12 236 /* 0xEC */      /* (we don't bother to list all 16 APPn's) */
    &GLOBAL-DEFINE M_APP14 238 /* 0xEE */      /* 13-NOV-2013 jcc: add Adobe APP14 support for CMYK files */
    &GLOBAL-DEFINE M_COM   254 /* 0xFE */      /* Comment */
    &GLOBAL-DEFINE M_MARK  255 /* 0xFF */      /* Marker */
    ELSE IF   GET-BYTE(mImage, 1) = {&M_MARK}
          AND GET-BYTE(mImage, 2) = {&M_SOI} THEN DO: /* might be JPG */
        SET-SIZE(mImage) = 0.
        COPY-LOB FILE pImage TO mImage.
        iPos = 3.
        blkMarkers:
        DO WHILE TRUE:
        /* loop through the markers until we find the one starting with 0xFF,0xC0
           which is the block containing the image information */
            DO WHILE TRUE: /* loop until we find the beginning of the next marker */
                IF   GET-BYTE(mImage, iPos) = {&M_Mark}
                 AND GET-BYTE(mImage, iPos + 1) <> {&M_Mark} THEN
                    LEAVE.
                iPos = iPos + 1.
                IF iPos >= GET-SIZE(mImage) - 10 THEN DO:
                    SET-SIZE(mImage) = 0.
                    RETURN.
                END.
            END.

            ASSIGN
             lSkip = NO
             iPos  = iPos + 1.

            CASE GET-BYTE(mImage, iPos):
                WHEN {&M_SOF0} OR WHEN {&M_SOF1} OR WHEN {&M_SOF2} OR WHEN {&M_SOF3}
                OR WHEN {&M_SOF5} OR WHEN {&M_SOF6} OR WHEN {&M_SOF7} OR WHEN {&M_SOF9}
                OR WHEN {&M_SOF10} OR WHEN {&M_SOF11} OR WHEN {&M_SOF13}
                OR WHEN {&M_SOF14} OR WHEN {&M_SOF15} THEN DO:
                    /* we have found the right block, let's extract the values */
                    ASSIGN
                     opcType        = "image/jpeg"
                     opiHeight      = GET-BYTE(mImage, iPos + 4) * 256 + GET-BYTE(mImage, iPos + 5)
                     opiWidth       = GET-BYTE(mImage, iPos + 6) * 256 + GET-BYTE(mImage, iPos + 7).
                    LEAVE blkMarkers.
                END.
                WHEN {&M_SOS} OR WHEN {&M_EOI} THEN
                    LEAVE blkMarkers.
                OTHERWISE /* keep looking */
                    lSkip = YES.
            END CASE.
            IF lSkip THEN DO:
                iPos = iPos + 256 * GET-BYTE(mImage, iPos + 1) + GET-BYTE(mImage, iPos + 2).
                IF iPos >= GET-SIZE(mImage) - 10 THEN DO:
                    SET-SIZE(mImage) = 0.
                    RETURN.
                END.
            END.
        END. /* blkMarkers: DO WHILE TRUE */
    END. /* JPG */

    ELSE IF GET-BYTES(mImage, 1, 6) MATCHES "GIF..a" /* GIF87a or GIF89a */ THEN DO:
        ASSIGN
         opcType = "image/gif"
         opiWidth  = 256 * GET-BYTE(mImage, 8) + GET-BYTE(mImage, 7)
         opiHeight = 256 * GET-BYTE(mImage, 10) + GET-BYTE(mImage, 9).
    END. /* GIF */

    ELSE IF GET-BYTES(mImage, 1, 2) = "BM" THEN DO:
        ASSIGN
         opcType          = "image/bmp"
         opiWidth         = GET-UNSIGNED-LONG(mImage, 19)
         opiHeight        = GET-UNSIGNED-LONG(mImage, 23).
    END. /* BMP */

    SET-SIZE(mImage) = 0.
END METHOD.
 
Top