Jump to content

Recommended Posts

Posted

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

Posted

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!

Posted

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

Posted

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

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
×
×
  • Create New...