Jump to content

View PGM file


alphp
 Share

Recommended Posts

Hello

I am creating a simple CIP3 viewer [http://www.cip4.org/documents/ppf_overview/index.html].

The image comes as a raw that by adding a header becomes a PGM (P5)

[http://en.wikipedia.org/wiki/Portable_graymap]. This image I have in a variable and have not found the efficient way to display it on a control.

This is my code, it works ... but very slow because the PGM is large (1626x1217)

#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <String.au3>
Func _ArrayEnd ($array)
Return $array[UBound($array) -1]
EndFunc
Local $file_ppf = @ScriptDir & '\file_in.ppf'
Local $file_pgm = @ScriptDir & '\file_out.pgm' ;>> For test purposes
Local $handle_ppf = FileOpen($file_ppf, 16)
Local $CIP3Header
Do
Local $line = StringStripWS(FileReadLine($handle_ppf), 3)
$CIP3Header &= $line & @LF
Until $line = 'CIP3PreviewImage'
Local $CIP3AdmJobName = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3AdmJobName\s+\(([^\)]+)\)\s+def\s+', 1))
Local $CIP3AdmSheetName = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3AdmSheetName\s+\(([^\)]+)\)\s+def\s+', 1))
Local $CIP3AdmSheetLay = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3AdmSheetLay\s+/([^\s)]+)\s+def\s+', 1))
Local $CIP3AdmPSExtent = StringRegExp($CIP3Header, '/CIP3AdmPSExtent\s+\[([\d\.]+)\s+([\d\.]+)\]\s+def\s+', 1)
Local $CIP3AdmSeparationNames = StringRegExp(_ArrayEnd(StringRegExp($CIP3Header, '/CIP3AdmSeparationNames\s+\[([^\]]+)\]\s+def\s+', 1)), '\(([^)]+)\)', 3)
Local $CIP3PreviewImageWidth= _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageWidth\s+([\d\.]+)\s+def\s+', 1))
Local $CIP3PreviewImageHeight = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageHeight\s+([\d\.]+)\s+def\s+', 1))
Local $CIP3PreviewImageEncoding = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageEncoding\s+/([^\s]+)\s+def\s+', 1))
Local $CIP3PreviewImageCompression = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageCompression\s+/([^\s]+)\s+def\s+', 1))
Local $CIP3PreviewImageBitsPerComp = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageBitsPerCom(ponent)?\s+(\d+)\s+def\s+', 1))
Local $CIP3PreviewImage = FileRead($handle_ppf, $CIP3PreviewImageWidth * $CIP3PreviewImageHeight)
Local $CIP3PreviewImageMatrix = StringRegExp($CIP3Header, '/CIP3PreviewImageMatrix\s+\[([-\d\.]+)\s+([-\d\.]+)\s+([-\d\.]+)\s+([-\d\.]+)\s+([-\d\.]+)\s+([-\d\.]+)\]\s+def\s+', 1)
FileClose($handle_ppf)
Local $PGMPreviewImage = 'P5' & @LF & $CIP3PreviewImageWidth & ' ' & $CIP3PreviewImageHeight & @LF & ((2 ^ $CIP3PreviewImageBitsPerComp) - 1) & @LF & BinaryToString($CIP3PreviewImage)
Local $handle_pgm = FileOpen($file_pgm, 2)
FileWrite($handle_pgm, $PGMPreviewImage)
FileClose($handle_pgm)
Local $CIP3View = GUICreate('CIP3View', @DesktopWidth / 3, @DesktopHeight / 3, -1, -1, $WS_MAXIMIZEBOX + $WS_SIZEBOX)
Local $CIP3Preview = GUICtrlCreateGraphic (0, 0, $CIP3PreviewImageWidth, $CIP3PreviewImageHeight)
GUICtrlSetBkColor($CIP3Preview, 0xf0fafa)
Local $scale = 3
For $y = 1 To $CIP3PreviewImageHeight Step $scale
Local $line = BinaryMid($CIP3PreviewImage, ($y - 1) * $CIP3PreviewImageWidth, $CIP3PreviewImageWidth)
For $x = 1 To $CIP3PreviewImageWidth Step $scale
  Local $c = BinaryMid($line, $x, 1)
  GUICtrlSetGraphic($CIP3Preview, $GUI_GR_COLOR, $c&$c&$c)
  GUICtrlSetGraphic($CIP3Preview, $GUI_GR_PIXEL, $x / $scale, $y / $scale)
Next
Next
GUISetState(@SW_SHOW, $CIP3View)
Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
GUIDelete($CIP3View)

Several viewers (IrfanView for example) the display is very fast

I attach a PGM file such as 129x129. map128.zip

I tried the _SetImageBinaryToCtrl but do not work.

Can anyone help? thanks

Link to comment
Share on other sites

You could use ImageMagick (search forum), just convert it to some viewable format like png or bmp.

Something like...

$img = ObjCreate("ImageMagickObject.MagickImage.1")
$img.Convert("input.pgm","output.png")

...then just show the output.png.

Maybe GDIPlus can also handle PGM's, not certain though.

Some guy's script + some other guy's script = my script!

Link to comment
Share on other sites

Werty: I try to solve the problem without creating temporary files. Pgm is write to disk for debugging.

UEZ: Ppf files are large, in my case: 1626x1217 Bytes of the preview (1.8 Mb) and a ppf can have several (actually a preview for color separation, typically Cyan, Magenta, Yellow and Black).

I have almost resolved the interpretation of the ppf and the only problem that I have not managed to solve is the display of the preview (which has pgm format), hence the word mark shows a small pgm.

Thanks for your interest

Link to comment
Share on other sites

Finally I decided to convert the PGM to PNG using pnmtopng (http://gnuwin32.sourceforge.net/packages/pngutils.htm):

#include <Constants.au3>
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <String.au3>
#include <GDIPlus.au3>
#include <Memory.au3>
#include <WinAPI.au3>

Func _ArrayEnd ($array)
   Return $array[UBound($array) -1]
EndFunc
 
Local $file_ppf = @ScriptDir & '1_PruebasTinteros_tinteros_C.ppf'
Local $handle_ppf = FileOpen($file_ppf, 16)
 
Local $CIP3Header
Do
    Local $line = StringStripWS(FileReadLine($handle_ppf), 3)
    $CIP3Header &= $line & @LF
Until $line = 'CIP3PreviewImage'
 
Local $CIP3AdmJobName = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3AdmJobNames+(([^)]+))s+defs+', 1))
Local $CIP3AdmSheetName = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3AdmSheetNames+(([^)]+))s+defs+', 1))
Local $CIP3AdmSheetLay = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3AdmSheetLays+/([^s)]+)s+defs+', 1))
Local $CIP3AdmPSExtent = StringRegExp($CIP3Header, '/CIP3AdmPSExtents+[([d.]+)s+([d.]+)]s+defs+', 1)
Local $CIP3AdmSeparationNames = StringRegExp(_ArrayEnd(StringRegExp($CIP3Header, '/CIP3AdmSeparationNamess+[([^]]+)]s+defs+', 1)), '(([^)]+))', 3)
Local $CIP3PreviewImageWidth= _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageWidths+([d.]+)s+defs+', 1))
Local $CIP3PreviewImageHeight = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageHeights+([d.]+)s+defs+', 1))
Local $CIP3PreviewImageEncoding = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageEncodings+/([^s]+)s+defs+', 1))
Local $CIP3PreviewImageCompression = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageCompressions+/([^s]+)s+defs+', 1))
Local $CIP3PreviewImageBitsPerComp = _ArrayEnd(StringRegExp($CIP3Header, '/CIP3PreviewImageBitsPerCom(ponent)?s+(d+)s+defs+', 1))
Local $CIP3PreviewImage = FileRead($handle_ppf, $CIP3PreviewImageWidth * $CIP3PreviewImageHeight)
Local $CIP3PreviewImageMatrix = StringRegExp($CIP3Header, '/CIP3PreviewImageMatrixs+[([-d.]+)s+([-d.]+)s+([-d.]+)s+([-d.]+)s+([-d.]+)s+([-d.]+)]s+defs+', 1)
 
FileClose($handle_ppf)

Local $PGMPreviewImage = 'P5' & @LF & $CIP3PreviewImageWidth & ' ' & $CIP3PreviewImageHeight & @LF & ((2 ^ $CIP3PreviewImageBitsPerComp) - 1) & @LF & BinaryToString($CIP3PreviewImage)

Local $pnmtopng = Run("pnmtopng.exe", @ScriptDir, @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD)
 
StdinWrite($pnmtopng, Binary($PGMPreviewImage))
StdinWrite($pnmtopng)

Local $PNGPreviewImage
Do
    $PNGPreviewImage &= StdoutRead($pnmtopng)
Until @error

_GDIPlus_Startup()
$hImage = Load_BMP_From_Mem($PNGPreviewImage)
$iWidth = _GDIPlus_ImageGetWidth($hImage)
$iHeight = _GDIPlus_ImageGetHeight($hImage)

Local $CIP3View = GUICreate('CIP3View', @DesktopWidth / 3, @DesktopHeight / 3, -1, -1, $WS_MAXIMIZEBOX + $WS_SIZEBOX)
Local $CIP3Preview = GUICtrlCreatePic('', 0, 0, $iWidth / 3, $iHeight / 3)
_SetImageBinaryToCtrl($CIP3Preview, $PNGPreviewImage)
GUISetState(@SW_SHOW, $CIP3View)
 
Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
 
GUIDelete($CIP3View)

;Authors: Prog@ndy, based on code by Zedna
Func _SetImageBinaryToCtrl($CtrlId, ByRef $Binary)
    Local $picdata = Binary($Binary) ; Fetch the Data
    Local $piclength = BinaryLen($picdata) ; Get Length
    Local $picstruct = DllStructCreate("byte[" & $piclength & "]")
    DllStructSetData($picstruct, 1, $picdata)
    Local $picmemory = DllStructGetPtr($picstruct)
    _SetMemoryImageToCtrl($CtrlId, $picmemory, $piclength)
    DllStructSetData($picstruct, 1, 0)
    $picstruct = ""
EndFunc   ;==>_SetImageBinaryToCtrl

; Authors: Zedna, based on code by Prog@ndy
Func _SetMemoryImageToCtrl($CtrlId, $Pointer, $nSize)
    Local $hData, $pData, $pStream, $pBitmap, $hBitmap
    ; use GDI+ for converting to bitmap first
    $hData = _MemGlobalAlloc($nSize, 2)
    $pData = _MemGlobalLock($hData)
    _MemMoveMemory($Pointer, $pData, $nSize)
    _MemGlobalUnlock($hData)
    $pStream = DllCall("ole32.dll", "int", "CreateStreamOnHGlobal", "int", $hData, "long", 1, "Int*", 0)
    $pStream = $pStream[3]
    _GDIPlus_Startup()
    $pBitmap = DllCall($ghGDIPDll, "int", "GdipCreateBitmapFromStream", "ptr", $pStream, "int*", 0)
    $pBitmap = $pBitmap[2]
    $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($pBitmap)
    _SetBitmapToCtrl($CtrlId, $hBitmap)
    If @error Then SetError(3, 0, 0)
    _GDIPlus_BitmapDispose($pBitmap)
    _GDIPlus_Shutdown()
    _WinAPI_DeleteObject($pStream)
    _MemGlobalFree($hData)
EndFunc   ;==>_SetMemoryImageToCtrl

; internal helper function
; Out of resources.au3 :)
Func _SetBitmapToCtrl($CtrlId, $hBitmap)
    Local Const $STM_SETIMAGE = 0x0172
    Local Const $IMAGE_BITMAP = 0
    Local Const $SS_BITMAP = 0xE
    Local Const $GWL_STYLE = -16
    Local $hWnd = GUICtrlGetHandle($CtrlId)
    If $hWnd = 0 Then Return SetError(1, 0, 0)
    ; set SS_BITMAP style to control
    Local $oldStyle = DllCall("user32.dll", "long", "GetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE)
    If @error Then Return SetError(2, 0, 0)
    DllCall("user32.dll", "long", "SetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE, "long", BitOR($oldStyle[0], $SS_BITMAP))
    If @error Then Return SetError(3, 0, 0)
    Local $oldBmp = DllCall("user32.dll", "hwnd", "SendMessage", "hwnd", $hWnd, "int", $STM_SETIMAGE, "int", $IMAGE_BITMAP, "int", $hBitmap)
    If @error Then Return SetError(4, 0, 0)
    If $oldBmp[0] <> 0 Then _WinAPI_DeleteObject($oldBmp[0])
    Return 1
EndFunc   ;==>_SetBitmapToCtrl

;======================================================================================
; Function Name:        Load_BMP_From_Mem
; Description:        Loads a image which is saved as a binary string and converts it to a bitmap or hbitmap
;
; Parameters:          $mem_image:   the binary string which contains any valid image which is supported by GDI+
; Optional:              $hHBITMAP:   if false a bitmap will be created, if true a hbitmap will be created
;
; Remark:                  hbitmap format is used generally for GUI internal images
;
; Requirement(s):      GDIPlus.au3, Memory.au3
; Return Value(s):  Success: handle to bitmap or hbitmap, Error: 0
; Error codes:        1: $mem_image is not a binary string
;
; Author(s):                UEZ
; Additional Code:  thanks to progandy for the MemGlobalAlloc and tVARIANT lines
; Version:                v0.95 Build 2011-06-11 Beta
;=======================================================================================
Func Load_BMP_From_Mem($mem_image, $hHBITMAP = False)
;~  If Not IsBinary($mem_image) Then Return SetError(1, 0, 0) ;not working properly
    Local $declared = True
    If Not $ghGDIPDll Then
        _GDIPlus_Startup()
        $declared = False
    EndIf
    Local Const $memBitmap = Binary($mem_image) ;load image  saved in variable (memory) and convert it to binary
    Local Const $len = BinaryLen($memBitmap) ;get length of image
    Local Const $hData = _MemGlobalAlloc($len, $GMEM_MOVEABLE) ;allocates movable memory  ($GMEM_MOVEABLE = 0x0002)
    Local Const $pData = _MemGlobalLock($hData) ;translate the handle into a pointer
    Local $tMem = DllStructCreate("byte[" & $len & "]", $pData) ;create struct
    DllStructSetData($tMem, 1, $memBitmap) ;fill struct with image data
    _MemGlobalUnlock($hData) ;decrements the lock count  associated with a memory object that was allocated with GMEM_MOVEABLE
    Local $hStream = DllCall("ole32.dll", "int", "CreateStreamOnHGlobal", "handle", $pData, "int", True, "ptr*", 0)
    $hStream = $hStream[3]
    Local $hBitmap = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromStream", "ptr", $hStream, "int*", 0) ;Creates a Bitmap object based on an IStream COM interface
    $hBitmap = $hBitmap[2]
    Local Const $tVARIANT = DllStructCreate("word vt;word r1;word r2;word r3;ptr data; ptr")
    DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $hStream, "dword", 8 + 8 * @AutoItX64, _
                                           "dword", 4, "dword", 23, "dword", 0, "ptr", 0, "ptr", 0, "ptr", DllStructGetPtr($tVARIANT)) ;release memory from $hStream to avoid memory leak
    $tMem = 0
    If $hHBITMAP Then
        Local Const $hHBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
        _GDIPlus_BitmapDispose($hBitmap)
        If Not $declared Then _GDIPlus_Shutdown()
        Return $hHBmp
    EndIf
    If Not $declared Then _GDIPlus_Shutdown()
    Return $hBitmap
EndFunc   ;==>Load_BMP_From_Mem

Thanks for all

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...