Base64Encoder: Image To Binary (no disk write)

Everything else that doesn't fall into one of the other PB categories.
JHPJHP
Addict
Addict
Posts: 2285
Joined: Sat Oct 09, 2010 3:47 am

Base64Encoder: Image To Binary (no disk write)

Post by JHPJHP »

Hi all,

Is it possible to do the following without writing a file to disk, another way?

*** removed the SaveImage, ReadFile, etc. ***

Code: Select all

Global ScreenWidth = GetSystemMetrics_(#SM_CXSCREEN)
Global ScreenHeight = GetSystemMetrics_(#SM_CYSCREEN)

UsePNGImageEncoder()

Procedure CaptureScreen(Left, Top, Width, Height)
  ScreenDM.DEVMODE
  ScreenDC = CreateDC_("DISPLAY", "", "", ScreenDM)
  TargetDC = CreateCompatibleDC_(ScreenDC)
  ImageHandle = CreateCompatibleBitmap_(ScreenDC, Width, Height)
  SelectObject_(TargetDC, ImageHandle)
  BitBlt_(TargetDC, 0, 0, Width, Height, ScreenDC, Left, Top, #SRCCOPY)
  DeleteDC_(TargetDC)
  ReleaseDC_(ImageHandle, ScreenDC)
  ProcedureReturn ImageHandle
EndProcedure
ScreenCaptureAddress = CaptureScreen(0, 0, ScreenWidth, ScreenHeight)
newImage = CreateImage(#PB_Any, ScreenWidth, ScreenHeight)

If IsImage(newImage)
  If StartDrawing(ImageOutput(newImage))
    DrawImage(ScreenCaptureAddress, 0, 0)
    StopDrawing()
    imageMemory = AllocateMemory(????)
    ????
    encodedImage$ = Space(MemorySize(imageMemory) * 1.5)
    Base64Encoder(imageMemory, MemorySize(imageMemory), @encodedImage$, Len(encodedImage$))
  EndIf
EndIf
FreeImage(newImage)
Thank you for any insite!
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8453
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Base64Encoder: Image To Binary (no disk write)

Post by netmaestro »

You'd be best off to save the image to a named pipe, this way you can encode the image with png or jpg for compression. If you simply save the image to memory it will be uncompressed and your base64 string will be huge. A named pipe won't go out to disk so it's pretty much the same as saving to memory anyway.
BERESHEIT
JHPJHP
Addict
Addict
Posts: 2285
Joined: Sat Oct 09, 2010 3:47 am

Re: Base64Encoder: Image To Binary (no disk write)

Post by JHPJHP »

netmaestro - thank you for showing the way:

http://www.purebasic.fr/english/viewtop ... 13&t=26380

Working on it now...
JHPJHP
Addict
Addict
Posts: 2285
Joined: Sat Oct 09, 2010 3:47 am

Re: Base64Encoder: Image To Binary (no disk write)

Post by JHPJHP »

Hi again,

The following works, but is there a way to get a more accurate imageSize before creating the DataPipe - right now I just make sure the buffer is large enough (imageSize = ScreenWidth * ScreenHeight):

Code: Select all

Global ScreenWidth = GetSystemMetrics_(#SM_CXSCREEN)
Global ScreenHeight = GetSystemMetrics_(#SM_CYSCREEN)

UsePNGImageEncoder()
UsePNGImageDecoder()

Procedure CaptureScreen(Left, Top, Width, Height)
  ScreenDM.DEVMODE
  ScreenDC = CreateDC_("DISPLAY", "", "", ScreenDM)
  TargetDC = CreateCompatibleDC_(ScreenDC)
  ImageHandle = CreateCompatibleBitmap_(ScreenDC, Width, Height)
  SelectObject_(TargetDC, ImageHandle)
  BitBlt_(TargetDC, 0, 0, Width, Height, ScreenDC, Left, Top, #SRCCOPY)
  DeleteDC_(TargetDC)
  ReleaseDC_(ImageHandle, ScreenDC)
  ProcedureReturn ImageHandle
EndProcedure
ScreenCaptureAddress = CaptureScreen(0, 0, ScreenWidth, ScreenHeight)
newImage = CreateImage(#PB_Any, ScreenWidth, ScreenHeight)

If IsImage(newImage)
  If StartDrawing(ImageOutput(newImage))
    DrawImage(ScreenCaptureAddress, 0, 0)
    StopDrawing()
    imageSize = ScreenWidth * ScreenHeight
    imageDataPipe = CreateNamedPipe_("\\.\pipe\ScreenShot", #PIPE_ACCESS_INBOUND, #PIPE_TYPE_BYTE | #PIPE_READMODE_BYTE | #PIPE_NOWAIT, 1, imageSize, imageSize, #NMPWAIT_USE_DEFAULT_WAIT, #Null)

    If imageDataPipe
      SaveImage(newImage, "\\.\pipe\ScreenShot", #PB_ImagePlugin_PNG)
      imageMemory = AllocateMemory(imageSize)
      ReadFile_(imageDataPipe, imageMemory, imageSize, @bytesRead, #Null)
      encodedImage$ = Space(MemorySize(imageMemory) * 1.5)
      Base64Encoder(imageMemory, MemorySize(imageMemory), @encodedImage$, Len(encodedImage$))
      FreeMemory(imageMemory)
      CloseHandle_(imageDataPipe)
    EndIf
  EndIf
  FreeImage(newImage)
EndIf

;Used to test with

*imageMemory = AllocateMemory(Len(encodedImage$) * 1.5)
decodedLength = Base64Decoder(@encodedImage$, Len(encodedImage$), *imageMemory, MemorySize(*imageMemory))
ReAllocateMemory(*imageMemory, decodedLength)
newImage = CatchImage(#PB_Any, *imageMemory)
SaveImage(newImage, "C:\Test.png", #PB_ImagePlugin_PNG)
FreeImage(newImage)
FreeMemory(*imageMemory)
Thank you,
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Base64Encoder: Image To Binary (no disk write)

Post by rsts »

FYI

Code tags e.g. "code" and "/code" inside square brackets[] - (see the post menu) make the code appear much nicer.

Code: Select all

Global ScreenWidth = GetSystemMetrics_(#SM_CXSCREEN)
Global ScreenHeight = GetSystemMetrics_(#SM_CYSCREEN)

UsePNGImageEncoder()
UsePNGImageDecoder()

Procedure CaptureScreen(Left, Top, Width, Height)
ScreenDM.DEVMODE
ScreenDC = CreateDC_("DISPLAY", "", "", ScreenDM)
TargetDC = CreateCompatibleDC_(ScreenDC)
ImageHandle = CreateCompatibleBitmap_(ScreenDC, Width, Height)
SelectObject_(TargetDC, ImageHandle)
cheers
JHPJHP
Addict
Addict
Posts: 2285
Joined: Sat Oct 09, 2010 3:47 am

Re: Base64Encoder: Image To Binary (no disk write)

Post by JHPJHP »

Thanks for the "Know" rsts...

Also,

srod if your reading this - can you please explain the logic behind the following bit of code:

Code: Select all

imageSize = SizeOf(BITMAPFILEHEADER) + SizeOf(BITMAPINFOHEADER)
    imageSize + 4 * ((ScreenWidth * 24 + 31) / 32) * ScreenHeight
Found @ http://www.purebasic.fr/english/viewtop ... 13&t=26380

And srod - thanks for all the leg work, and years of support (in as simple as a Google search).
Last edited by JHPJHP on Sun Jul 21, 2013 10:05 pm, edited 1 time in total.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8453
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Base64Encoder: Image To Binary (no disk write)

Post by netmaestro »

A complete bitmap file consists of a BITMAPFILEHEADER followed by a BITMAPINFO structure which is comprised of a BITMAPINFOHEADER and an array of color bits. The calculation you see is the formula for finding the total number of bytes required for the colorbits in a bitmap of 24 bits depth at <screenwidth> width and <screenheight> height. All of it added together is the complete filesize of a bitmap with no compression.
BERESHEIT
JHPJHP
Addict
Addict
Posts: 2285
Joined: Sat Oct 09, 2010 3:47 am

Re: Base64Encoder: Image To Binary (no disk write)

Post by JHPJHP »

Thank you again netmaestro... the PB community owes you and an elite few a load of thanks for all the great work, past, present, and no doubt future.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4801
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Base64Encoder: Image To Binary (no disk write)

Post by Fangbeast »

I know this is an old post but..is it possible to capture the data from an imagegadget in the same way instead of an entire screen?

I'm playing with a qrcode generator from Dige and modified by Baldrick and want to capture the generated code as a png file.

The image data sits in an imagegadget and i'm not familiar enough with these advanced concepts yet.
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Base64Encoder: Image To Binary (no disk write)

Post by IdeasVacuum »

You could just give the procedure Procedure CaptureScreen(Left, Top, Width, Height) the position + size of the image gadget, in screen ordinates.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4801
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Base64Encoder: Image To Binary (no disk write)

Post by Fangbeast »

IdeasVacuum wrote:You could just give the procedure Procedure CaptureScreen(Left, Top, Width, Height) the position + size of the image gadget, in screen ordinates.
Thank you, I shall try this. Shows you how little I know, graphics are one mystery I never dared try:):)
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4801
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Base64Encoder: Image To Binary (no disk write)

Post by Fangbeast »

Going to look at the sample qrcode generators in the forum to see if there is a mention of the physical image size mentioned and if there is a way to get the image data rather than relying on screen co-ordinates.

#EDIT## Ah yes, the imagegadget size changes with the generated image so all I have to do is get the data from the imagegadget somehow.
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4801
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Base64Encoder: Image To Binary (no disk write)

Post by Fangbeast »

Thank you for the help via PM. You know who you are:):) I am fighting with advanced concepts to expand my tiny mind.
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4801
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Base64Encoder: Image To Binary (no disk write)

Post by Fangbeast »

Nearly had it!! Using Dige's QRCodeGen and trying to save the image data to memory to named pipe, encode it there and debug to show I have something there.

I prettied up the code and variables so that I can follow it (bad eyes) but have trouble in the EncodeAndSave() module as I don't understand why image isn't initialised.

Code: Select all

; MS BITMAP structure
; typedef struct tagBITMAP {
;   LONG   bmType;
;   LONG   bmWidth;
;   LONG   bmHeight;
;   LONG   bmWidthBytes;
;   WORD   bmPlanes;
;   WORD   bmBitsPixel;
;   LPVOID bmBits;
;   } BITMAP, *PBITMAP;

; http://fukuchi.org/works/qrencode/index.en.html; 

UsePNGImageEncoder()
UsePNGImageDecoder()

Enumeration 1
  #Window_QRCodegen
EndEnumeration

#WindowIndex = #PB_Compiler_EnumerationValue

Enumeration 1
  #Gadget_QRCodegen_fTargetText
  #Gadget_QRCodegen_lTargetText
  #Gadget_QRCodegen_TargetText
  #Gadget_QRCodegen_fECLevel
  #Gadget_QRCodegen_lECLevel
  #Gadget_QRCodegen_ECLevel
  #Gadget_QRCodegen_lQRCodeSize
  #Gadget_QRCodegen_QRCodeSize
  #Gadget_QRCodegen_fQRCodeImage
  #Gadget_QRCodegen_QRCodeImage
  #Gadget_QRCodegen_fBase64String
  #Gadget_QRCodegen_eBase64String
  #Gadget_QRCodegen_fControl
  #Gadget_QRCodegen_bSave
  #Gadget_QRCodegen_bExit
EndEnumeration

#GadgetIndex = #PB_Compiler_EnumerationValue

Enumeration 1
  #Image_QRCodegen_QRCodeImage
  #Image_QRCodegen_bSave
  #Image_QRCodegen_bExit
EndEnumeration

#ImageIndex = #PB_Compiler_EnumerationValue

Enumeration
  #QR_ECLEVEL_L = 0 ; lowest
  #QR_ECLEVEL_M
  #QR_ECLEVEL_Q
  #QR_ECLEVEL_H     ; highest
EndEnumeration

Structure QRCode
  Version.l
  Width.l
  pSymbolData.l
EndStructure

ImportC "qrcodelib.lib"
  QRcode_encodeString8bit(Text.p-ascii, Version.l, QRecLevel.l) As "_QRcode_encodeString8bit"
  QRcode_free(*Qrcode.QRCode) As "_QRcode_free"
EndImport

CatchImage(#Image_QRCodegen_QRCodeImage,  ?_OPT_QRCodegen_QRCodeImage)
CatchImage(#Image_QRCodegen_bSave,        ?_OPT_QRCodegen_bSave)
CatchImage(#Image_QRCodegen_bExit,        ?_OPT_QRCodegen_bExit)

DataSection
  _OPT_QRCodegen_QRCodeImage  : IncludeBinary "Images\Blank.png"
  _OPT_QRCodegen_bSave        : IncludeBinary "Images\save32x32.ico"
  _OPT_QRCodegen_bExit        : IncludeBinary "Images\exit32x32.ico"
EndDataSection

Declare   CreateQRCode (content.s, ImageId.i = #PB_Any, EC_Level = #QR_ECLEVEL_L, Size = 4)
Declare   PasteQRCode()
Declare   EncodeAndSave()

Procedure CreateQRCode (content.s, ImageId.i = #PB_Any, EC_Level = #QR_ECLEVEL_L, Size = 4)
  Protected *Qrcode.QRCode, QRImg
  *Qrcode = QRcode_encodeString8bit(content, 0, EC_Level)
  With *Qrcode
    If *Qrcode = 0 Or \Width = 0
      ProcedureReturn #Null
    Else
      *mem = \pSymbolData
      w    = \Width
    EndIf
  EndWith
  QRImg  = CreateImage(ImageId.i, w + 2, w + 2)
  If QRImg
    If ImageId.i = #PB_Any
      ImageId.i = QRImg
    EndIf
  EndIf
  If StartDrawing(ImageOutput(ImageId.i))
    ; White Background
    Box (0, 0, ImageWidth(ImageId.i) + 2, ImageHeight(ImageId.i) + 2, #White) 
    ; Draw Black Dots
    For y = 0 To w - 1
      For x = 0 To w - 1
        b = PeekB(*mem) & $FF
        If b & 1
          Plot( x + 1, y + 1, #Black)
        EndIf
        *mem + 1
      Next
    Next
    StopDrawing()
    w * Size
    ResizeImage(ImageId.i, w + 2, w + 2, #PB_Image_Raw)
    ; Debug "width = " + Str(w)
    ; Debug "height = "+ Str(w)
  EndIf
  QRcode_free(*Qrcode)
  ProcedureReturn ImageId.i
EndProcedure

Procedure PasteQRCode()
  ; Create the image with parameters
  ImageId.i = CreateQRCode(GetGadgetText(#Gadget_QRCodegen_TargetText), #Null, GetGadgetState(#Gadget_QRCodegen_ECLevel), GetGadgetState(#Gadget_QRCodegen_QRCodeSize))
  ; Check if we got an image handle
  If IsImage(ImageId.i)
    ; Resize gadget to image
    ResizeGadget(#Gadget_QRCodegen_QRCodeImage, #PB_Ignore, #PB_Ignore, ImageWidth(ImageId.i), ImageHeight(ImageId.i))
    ; Set the QRCode to the image gadget
    SetGadgetState(#Gadget_QRCodegen_QRCodeImage, ImageID(ImageId.i))
    ; Show gadget is resizing with image
    ;Debug Str(GadgetWidth(3)) + "   ---   " + Str(GadgetHeight(3))
    ; Main routine needs the ImageID for saving
    ProcedureReturn ImageId.i
    ; 
  EndIf
  ; 
EndProcedure

Procedure EncodeAndSave()
  ImageHandle = GetGadgetState(#Gadget_QRCodegen_QRCodeImage)
  GetObject_(ImageHandle, SizeOf(BITMAP), @image.BITMAP)
  ImageSize = image\bmWidth * image\bmHeight
  ImageDataPipe = CreateNamedPipe_("\\.\pipe\ScreenShot", #PIPE_ACCESS_INBOUND, #PIPE_TYPE_BYTE | #PIPE_READMODE_BYTE | #PIPE_NOWAIT, 1, imageSize, imageSize, #NMPWAIT_USE_DEFAULT_WAIT, #Null)
  If ImageDataPipe
    SaveImage(ImageHandle, "\\.\pipe\ScreenShot", #PB_ImagePlugin_PNG)
    ImageMemory = AllocateMemory(ImageSize)
    ReadFile_(ImageDataPipe, ImageMemory, ImageSize, @bytesRead, #Null)
    EncodedImage.s = Space(MemorySize(ImageMemory) * 1.5)
    Base64Encoder(ImageMemory, MemorySize(ImageMemory), @EncodedImage.s, Len(EncodedImage.s))
    FreeMemory(ImageMemory)
    CloseHandle_(ImageDataPipe)
    If EncodedImage.s
      Debug EncodedImage.s
    EndIf
  EndIf
EndProcedure

If OpenWindow(#Window_QRCodegen, 300, 10, 450, 701, "2d QR Code generator and encoder", #WS_OVERLAPPEDWINDOW | #PB_Window_ScreenCentered)
  Frame3DGadget(#Gadget_QRCodegen_fTargetText, 5, 0, 440, 75, "")
  TextGadget(#Gadget_QRCodegen_lTargetText, 10, 15, 430, 25, "Text to be encoded", #PB_Text_Center)
    SetGadgetFont(#Gadget_QRCodegen_lTargetText, LoadFont(#Gadget_QRCodegen_lTargetText, "Comic Sans MS", 11, 0))
  StringGadget(#Gadget_QRCodegen_TargetText, 10, 40, 430, 25, "http://http://forums.whirlpool.net.au/forum-replies.cfm?t=1825264", #PB_String_BorderLess)
    SetGadgetFont(#Gadget_QRCodegen_TargetText, LoadFont(#Gadget_QRCodegen_TargetText, "Comic Sans MS", 11, 0))
  Frame3DGadget(#Gadget_QRCodegen_fECLevel, 5, 75, 440, 75, "")
  TextGadget(#Gadget_QRCodegen_lECLevel, 10, 90, 210, 25, "Error correcting level", #PB_Text_Center)
    SetGadgetFont(#Gadget_QRCodegen_lECLevel, LoadFont(#Gadget_QRCodegen_lECLevel, "Comic Sans MS", 11, 0))
  TrackBarGadget(#Gadget_QRCodegen_ECLevel, 10, 120, 100, 20, #QR_ECLEVEL_L, #QR_ECLEVEL_H, #PB_TrackBar_Ticks)
  TextGadget(#Gadget_QRCodegen_lQRCodeSize, 230, 90, 210, 25, "Physical size", #PB_Text_Center)
    SetGadgetFont(#Gadget_QRCodegen_lQRCodeSize, LoadFont(#Gadget_QRCodegen_lQRCodeSize, "Comic Sans MS", 11, 0))
  TrackBarGadget(#Gadget_QRCodegen_QRCodeSize, 230, 120, 100, 20, 1, 10, #PB_TrackBar_Ticks)
  SetGadgetState(#Gadget_QRCodegen_QRCodeSize, 3)
  Frame3DGadget(#Gadget_QRCodegen_fQRCodeImage, 5, 150, 440, 400, "")
  ImageGadget(#Gadget_QRCodegen_QRCodeImage, 10, 165, 80, 50, ImageID(#Image_QRCodegen_QRCodeImage), #PB_Image_Border)
  ResizeGadget(#Gadget_QRCodegen_QRCodeImage, 10, 165, 80, 50)
  ResizeImage(#Image_QRCodegen_QRCodeImage, 80, 50)
  SetGadgetState(#Gadget_QRCodegen_QRCodeImage, ImageID(#Image_QRCodegen_QRCodeImage))
  Frame3DGadget(#Gadget_QRCodegen_fBase64String, 5, 550, 440, 75, "")
  EditorGadget(#Gadget_QRCodegen_eBase64String, 10, 565, 430, 50)
  Frame3DGadget(#Gadget_QRCodegen_fControl, 5, 625, 440, 70, "")
  ButtonImageGadget(#Gadget_QRCodegen_bSave, 15, 640, 45, 45, ImageID(#Image_QRCodegen_bSave))
  ButtonImageGadget(#Gadget_QRCodegen_bExit, 390, 640, 45, 45, ImageID(#Image_QRCodegen_bExit))
  HideWindow(#Window_QRCodegen, 0)
  
  quitQRCodegen = 0
  
  PasteQRCode()                                                                           ; Generate and paste
  
  Repeat
    EventID  = WaitWindowEvent()
    MenuID   = EventMenu()
    GadgetID = EventGadget()
    WindowID = EventWindow()
    Select EventID
      Case #PB_Event_CloseWindow
        Select WindowID
          Case #Window_QRCodegen                  : quitQRCodegen = 1
        EndSelect
      Case #PB_Event_Gadget
        Select GadgetID
          Case #Gadget_QRCodegen_TargetText       : PasteQRCode()
          Case #Gadget_QRCodegen_ECLevel          : PasteQRCode()
          Case #Gadget_QRCodegen_QRCodeSize       : PasteQRCode()
          Case #Gadget_QRCodegen_bSave            : EncodeAndSave()
          Case #Gadget_QRCodegen_bExit            : quitQRCodegen = 1
        EndSelect
    EndSelect
  Until quitQRCodegen
  CloseWindow(#Window_QRCodegen)
EndIf
End
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
Post Reply