How to count black pixels from image in MS Access VBA? - vba

I have capture signatures using Msink Obj control from my form and saved them in signature field in my SQL database and datatype for it is image.
I have converted the saved sign data in to .gif and also shown it in image control in my form but now I want to calculate number of black pixels in this image or count of it.
So please suggest how can I go with it?

I have found an windows API for it which can we used for getting pixel count.
It is GetPixel Lib "gdi32" API below is sample code for it :-
Option Compare Database
'Following Two API'S Are Added To Count The Pixles
Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal y As Long) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Public Function GetPixlesTest(pHwnd As Long) As Integer: On Error Resume Next
Dim i As Long, j As Long, nBlack As Long, nWhite As Long, pHdc As Long, tempColor As Long
Dim count As Integer
count = 0 'Initializing count with 0
With Forms!frmTestSign!imgTest 'Getting Form Image Control
pHdc1 = GetWindowDC(pHwnd)
For i = 0 To .Width
For j = 0 To .Height`enter code here`
tempColor = GetPixel(pHdc1, i, j)
If tempColor = vbBlack Then 'Counting for black pixles only.
nBlack = nBlack + 1
End If
Next
Next
End With
TotalBlack = nBlack - 611 'Substracting 611 becuase it has default 611 black pixle on my form
GetPixlesPractical = TotalBlack
End Function
Calling above function :-
gstrpixlecount = GetPixlesPractical(Me.hwnd) 'Call it on same form in which you have image control to get pixles.
Plesae follow below link for more info :-
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144947(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144909(v=vs.85).aspx
http://www.vbdotnetforums.com/graphics-gdi/22565-using-winapi-getpixel.html
Thanks

Related

How to autocrop an image with VBA in PowerPoint?

I am trying to find where the color differs and then crop that part of the image out of it.
Is there any method to get a pixel by pixel image color?
I don't think I can based off of these methods and because it is a bitmap image.
I know there is a set transparent method but the problem is I need to set the widths or heights of logos to be the same height/width and the transparent function doesn't change the size of the picture
If a method does this I would write a function that finds where the image changes from white and then crop from the top middle and bottom.
Example image
As far as I can tell it is impossible to do so within Powerpoint, however there might be a way using outside conditions such as by opening an excel project and using the code from this post VBA Get Colour of Pixel. I'm sorry that I cannot help you in any other way. My main suggestion would be to use normal numbers to crop it. Perhaps if you found a specific thing between the images that was different (Such as one type of image's height was different than the other type of image so you could use that to know how far to crop the image.), however as far as I can tell, No. There is no way to do this with powerpoint unless they added a feature.
I was recently working on a similar problem, and I developed a VBA solution for automatically cropping a white border from an image
In that answer, I am only looking at one side of the image because I assume that the border is uniform all of the way around, so it would not directly work for this case. Also, that example only modifies the slide, and it does not produce an output file
In the below example, each side of the image is examined and cropped according to how much whitespace is found. The resultant slide is then exported back to the original directory with the name croppedFile.
Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare PtrSafe Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare PtrSafe Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare PtrSafe Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long) As Long
Private Function PixelTest(objPict As Object, ByVal X As Long, ByVal Y As Long) As Long
Dim lDC As Variant
lDC = CreateCompatibleDC(0)
SelectObject lDC, objPict.Handle
PixelTest = GetPixel(lDC, X, Y)
DeleteDC lDC
End Function
Sub AutoCropper()
Dim myDocument As Slide, fileSystem As Object, fileFolder As Object
Dim fileItem As Object, objPict As Object, objImage As Object
Dim i As Integer, startingPoint As Integer, endingPoint As Integer
Dim MidPoint As Integer, filePath As String, fileName As String
Dim cropScale As Single, margin As Single, reverseScan As Integer
Dim importHeight As Single, importWidth As Single, resolutionScale As Integer
Dim xlocation As Single, yLocation As Single
Dim restoreLayout As Boolean
filePath = "D:\Pictures"
fileName = "Example.bmp"
Set fileSystem = CreateObject("Scripting.FileSystemObject")
Set fileFolder = fileSystem.GetFolder(filePath)
Set objImage = CreateObject("WIA.ImageFile")
cropScale = 3.4
resolutionScale = 10
importWidth = 330
importHeight = 250
xlocation = 390
yLocation = 200
For Each fileItem In fileFolder.Files
If fileItem.Name = fileName Then
i = i + 1
On Error GoTo insertSlide
Set myDocument = ActivePresentation.Slides(i)
If myDocument.CustomLayout.Name = "Picture with Caption" Then
myDocument.Layout = ppLayoutText
restoreLayout = True
End If
Set preCroppedPic = myDocument.Shapes.AddPicture(fileName:=fileFolder & "\" & _
fileItem.Name, LinkToFile:=msoTrue, SaveWithDocument:=msoTrue, _
Left:=xlocation, Top:=yLocation, Width:=importWidth, Height:=importHeight)
preCroppedPic.Export filePath & "\Temp.bmp", ppShapeFormatBMP, preCroppedPic.Width, preCroppedPic.Height, ppScaleToFit
Set objImage = CreateObject("WIA.ImageFile")
objImage.LoadFile filePath & "\Temp.bmp"
Set objPict = LoadPicture(filePath & "\Temp.BMP")
endingPoint = objImage.Width
MidPoint = (0.5 * objImage.Height)
For marginScan = 1 To endingPoint
On Error Resume Next
If Not (PixelTest(objPict, marginScan, MidPoint) Like "1677*") Then
margin = marginScan * cropScale
preCroppedPic.PictureFormat.CropLeft = margin
Exit For
End If
Next
For marginScan = 1 To endingPoint
reverseScan = endingPoint - marginScan
If Not (PixelTest(objPict, reverseScan, MidPoint) Like "1677*") Then
margin = marginScan * cropScale
preCroppedPic.PictureFormat.CropRight = margin
Exit For
End If
Next
endingPoint = objImage.Height
MidPoint = (0.5 * objImage.Width)
For marginScan = 1 To endingPoint
If Not (PixelTest(objPict, MidPoint, marginScan) Like "1677*") Then
margin = marginScan * cropScale
preCroppedPic.PictureFormat.CropTop = margin
Exit For
End If
Next
For marginScan = 1 To endingPoint
reverseScan = endingPoint - marginScan
If Not (PixelTest(objPict, MidPoint, reverseScan) Like "1677*") Then
margin = marginScan * cropScale
preCroppedPic.PictureFormat.CropBottom = margin
' finalHeight = finalHeight - margin
Exit For
End If
Next
If restoreLayout Then
myDocument.Layout = ppLayoutPictureWithCaption
restoreLayout = False
End If
preCroppedPic.Export filePath & "\CroppedImage.bmp", ppShapeFormatBMP, (resolutionScale * importWidth), (resolutionScale * importHeight), ppScaleToFit
Exit For
End If
Next fileItem
Exit Sub
insertSlide:
Set myDocument = ActivePresentation.Slides.Add(i, ppLayoutText)
Resume Next
End Sub
The preceding code produces the following result with the precropped image on the left and the postcropped image on the right:
Obviously, a correct file path and file name have to be supplied, but here are a few not so obvious things that need to be taken into consideration when working with this script:
• This program has been tested and confirmed to work for BMP, JPEG, GIF, and PNG files, but the file name and extension are case sensitive, so if you run the code and nothing happens, I would check that first.
• I've tested this on multiple systems, and I've found that the pixel analyzer in this program will not work for PNGs. To make this script PNG compatible, because that is what I normally work with, I had to perform an intermediary file conversion that creates a temporary BMP file. Between the different environments I tested this script on, I found that the export size varied quite a bit, but it was always proportional to the original picture. For this reason, there is a cropScale value that can be used to account for this ratio. A cropScale value of 2 for example will crop 2 white pixels from the original photo for every 1 pixel detected in the temporary bmp.
• Also, due to the export descrepencies, I've found that the export file will often have a lower resolution than the original, so a resolutionScale parameter has been added to compensate for this in the output file. This along with the cropScale parameters should make it simple to get this script working on wide variety of systems.
• Finally, this script can be modified to crop any border color or even gradient colors by modifying the If Not Like parameters in the four cropping loops, but the colors returned from the pixel analyzer are not RGB values. Rather they are Long values.
• A list of Long color values can be found here: Long Color Chart
• For more information on scaling picture sizes and resolutions in PowerPoint, I found this excellent resource while researching this solution:Unravelling PowerPoint picture size and resolution

command print button. When I click on the print button,the first page prints twice other pages print single which is what I want

I have 2 concerns, if someone can assist. I am new to VBA. I have a command print button on my excel sheet and I added the code listed below. When I click on the print button, I have the first page print twice but the rest of the pages print single which is what I want. How do I fix the code so it only prints once.
The other thing is when the print manager window opens for me to select a printer, I would like to have the code select single page print and not duplex printing. The printer default settings are set for duplex and I dont want to change that setting through windows but for the code to automatically select single sided prints.
Thank you,
Private Sub PrintAll_Click()
Dim rngOffenders As Range
Set rngOffenders = Worksheets("Names").Range("A2", Worksheets("Names").Range("A2").End(xlDown))
Dim willPrint As Boolean
willPrint = Application.Dialogs(xlDialogPrint).Show
If Not willPrint Then Exit Sub
Dim rng As Range
For Each rng In rngOffenders.Cells
Worksheets("Template").Range("LastName").Value = rng.Value
Calculate
Worksheets("Template").PrintOut
Next rng
End Sub
Regarding the duplicate printing, my guess, without testing, is that by Show the print dialog, you're invoking print against the first/active sheet once you press "OK". Then, as you iterate over rngOffenders.Cells, you're printing that sheet again. So, you could start at the second cell in rngOffenders to avoid that.
Dim i As Long
For i = 2 To rngOffenders.Cells.Count
Worksheets("Template").Range("LastName").Value = rngOffenders.Cells(i).Value
Calculate
Worksheets("Template").PrintOut
Next rng
For the printer settings, that is more complicated. See here:
The best way of doing this is by using API calls. The following article gives you a VB code sample which does this:
Q230743
Only one “problem” with this code: It is written for VB and uses Printer.DeviceName to return the name of the currently selected printer. In Word VBA, you need to substitute this with ActivePrinter. The problem is that the strings returned by these commands are slightly different, even though they both get the name of the printer from the name assigned in Control Panel | Printers. For instance.:
ActivePrinter: HP LaserJet 6L PCL on LPT1:
Printer.DeviceName: HP LaserJet 6L PCL
So you'll need to test and modify the code sample accordingly.
If you don't want to use API calls, however, you can install a duplicate printer driver with the duplex property set and print to that (by changing the ActivePrinter).
The linked KB article demonstrates (at length) how to set the printer to duplex printing. Most of the same code should be used for the inverse operation, you'd just need to figure out what value to pass for that property.
Test Procedure:
Place this in a standard module. Note the possible need to adjust the length of printer string (removing the port component e.g., "HP Ink Jet Fantastico on LP02", etc.)
Option Explicit
Sub test()
Dim pName As String
pName = ActivePrinter
' Note you may need to adjust this value to remove the port string component
pName = Left(pName, (Len(pName) - 9))
SetPrinterDuplex pName, 1 '1 = NOT duplex printing.
'Here you might want to actually print something, for example:
Worksheets("Template").PrintOut
End Sub
In a separate module, place all of the printer-related code. NB: I am on a machine with no printer access, so I am unable to test or further debug this solution.
Option Explicit
Public Type PRINTER_DEFAULTS
pDatatype As Long
pDevmode As Long
DesiredAccess As Long
End Type
Public Type PRINTER_INFO_2
pServerName As Long
pPrinterName As Long
pShareName As Long
pPortName As Long
pDriverName As Long
pComment As Long
pLocation As Long
pDevmode As Long ' Pointer to DEVMODE
pSepFile As Long
pPrintProcessor As Long
pDatatype As Long
pParameters As Long
pSecurityDescriptor As Long ' Pointer to SECURITY_DESCRIPTOR
Attributes As Long
Priority As Long
DefaultPriority As Long
StartTime As Long
UntilTime As Long
Status As Long
cJobs As Long
AveragePPM As Long
End Type
Public Type DEVMODE
dmDeviceName As String * 32
dmSpecVersion As Integer
dmDriverVersion As Integer
dmSize As Integer
dmDriverExtra As Integer
dmFields As Long
dmOrientation As Integer
dmPaperSize As Integer
dmPaperLength As Integer
dmPaperWidth As Integer
dmScale As Integer
dmCopies As Integer
dmDefaultSource As Integer
dmPrintQuality As Integer
dmColor As Integer
dmDuplex As Integer
dmYResolution As Integer
dmTTOption As Integer
dmCollate As Integer
dmFormName As String * 32
dmUnusedPadding As Integer
dmBitsPerPel As Integer
dmPelsWidth As Long
dmPelsHeight As Long
dmDisplayFlags As Long
dmDisplayFrequency As Long
dmICMMethod As Long
dmICMIntent As Long
dmMediaType As Long
dmDitherType As Long
dmReserved1 As Long
dmReserved2 As Long
End Type
Public Const DM_DUPLEX = &H1000&
Public Const DM_IN_BUFFER = 8
Public Const DM_OUT_BUFFER = 2
Public Const PRINTER_ACCESS_ADMINISTER = &H4
Public Const PRINTER_ACCESS_USE = &H8
Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
Public Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _
PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
Public Declare Function ClosePrinter Lib "winspool.drv" _
(ByVal hPrinter As Long) As Long
Public Declare Function DocumentProperties Lib "winspool.drv" _
Alias "DocumentPropertiesA" (ByVal hwnd As Long, _
ByVal hPrinter As Long, ByVal pDeviceName As String, _
ByVal pDevModeOutput As Long, ByVal pDevModeInput As Long, _
ByVal fMode As Long) As Long
Public Declare Function GetPrinter Lib "winspool.drv" Alias _
"GetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, _
pPrinter As Byte, ByVal cbBuf As Long, pcbNeeded As Long) As Long
Public Declare Function OpenPrinter Lib "winspool.drv" Alias _
"OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, _
pDefault As PRINTER_DEFAULTS) As Long
Public Declare Function SetPrinter Lib "winspool.drv" Alias _
"SetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, _
pPrinter As Byte, ByVal Command As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pDest As Any, pSource As Any, ByVal cbLength As Long)
' ==================================================================
' SetPrinterDuplex
'
' Programmatically set the Duplex flag for the specified printer
' driver's default properties.
'
' Returns: True on success, False on error. (An error will also
' display a message box. This is done for informational value
' only. You should modify the code to support better error
' handling in your production application.)
'
' Parameters:
' sPrinterName - The name of the printer to be used.
'
' nDuplexSetting - One of the following standard settings:
' 1 = None
' 2 = Duplex on long edge (book)
' 3 = Duplex on short edge (legal)
'
' ==================================================================
Public Function SetPrinterDuplex(ByVal sPrinterName As String, _
ByVal nDuplexSetting As Long) As Boolean
Dim hPrinter As Long
Dim pd As PRINTER_DEFAULTS
Dim pinfo As PRINTER_INFO_2
Dim dm As DEVMODE
Dim yDevModeData() As Byte
Dim yPInfoMemory() As Byte
Dim nBytesNeeded As Long
Dim nRet As Long, nJunk As Long
On Error GoTo cleanup
'#### I removed this block because it was preventing you from changing the duplex settings
' If (nDuplexSetting < 1) Or (nDuplexSetting > 3) Then
' MsgBox "Error: dwDuplexSetting is incorrect."
' Exit Function
' End If
'####
pd.DesiredAccess = PRINTER_ALL_ACCESS
nRet = OpenPrinter(sPrinterName, hPrinter, pd)
If (nRet = 0) Or (hPrinter = 0) Then
If Err.LastDllError = 5 Then
MsgBox "Access denied -- See the article for more info."
Else
MsgBox "Cannot open the printer specified " & _
"(make sure the printer name is correct)."
End If
Exit Function
End If
nRet = DocumentProperties(0, hPrinter, sPrinterName, 0, 0, 0)
If (nRet < 0) Then
MsgBox "Cannot get the size of the DEVMODE structure."
GoTo cleanup
End If
ReDim yDevModeData(nRet + 100) As Byte
nRet = DocumentProperties(0, hPrinter, sPrinterName, _
VarPtr(yDevModeData(0)), 0, DM_OUT_BUFFER)
If (nRet < 0) Then
MsgBox "Cannot get the DEVMODE structure."
GoTo cleanup
End If
Call CopyMemory(dm, yDevModeData(0), Len(dm))
If Not CBool(dm.dmFields And DM_DUPLEX) Then
MsgBox "You cannot modify the duplex flag for this printer " & _
"because it does not support duplex or the driver " & _
"does not support setting it from the Windows API."
GoTo cleanup
End If
dm.dmDuplex = nDuplexSetting
Call CopyMemory(yDevModeData(0), dm, Len(dm))
nRet = DocumentProperties(0, hPrinter, sPrinterName, _
VarPtr(yDevModeData(0)), VarPtr(yDevModeData(0)), _
DM_IN_BUFFER Or DM_OUT_BUFFER)
If (nRet < 0) Then
MsgBox "Unable to set duplex setting to this printer."
GoTo cleanup
End If
Call GetPrinter(hPrinter, 2, 0, 0, nBytesNeeded)
If (nBytesNeeded = 0) Then GoTo cleanup
ReDim yPInfoMemory(nBytesNeeded + 100) As Byte
nRet = GetPrinter(hPrinter, 2, yPInfoMemory(0), nBytesNeeded, nJunk)
If (nRet = 0) Then
MsgBox "Unable to get shared printer settings."
GoTo cleanup
End If
Call CopyMemory(pinfo, yPInfoMemory(0), Len(pinfo))
pinfo.pDevmode = VarPtr(yDevModeData(0))
pinfo.pSecurityDescriptor = 0
Call CopyMemory(yPInfoMemory(0), pinfo, Len(pinfo))
nRet = SetPrinter(hPrinter, 2, yPInfoMemory(0), 0)
If (nRet = 0) Then
MsgBox "Unable to set shared printer settings."
End If
SetPrinterDuplex = CBool(nRet)
cleanup:
If (hPrinter <> 0) Then Call ClosePrinter(hPrinter)
End Function
You can print the first page twice like this:
Dim i As Long, k As Long
Dim lpc As Long
lpc = ActiveSheet.HPageBreaks.Count
For i = 1 To lpc + 1
If i = 1 Then
k = 2
Else
k = 1
End If
ActiveSheet.PrintOut from:=i, To:=i, Copies:=k
Next

How To I Write Copymem Lib "Kernel32" Alias "Rtlmovememory" In Vb.Net

below is my vb6 code
Private Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Property Let Key(New_Value As String)
Dim i As Long
Dim j As Long
Dim K As Long
Dim dataX As Long
Dim datal As Long
Dim datar As Long
Dim Key() As Byte
Dim KeyLength As Long
'Do nothing if the key is buffered
If (m_KeyValue = New_Value) Then Exit Property
m_KeyValue = New_Value
'Convert the new key into a bytearray
KeyLength = Len(New_Value)
Key() = StrConv(New_Value, vbFromUnicode)
'Create key-dependant p-boxes
j = 0
For i = 0 To (ROUNDS + 1)
dataX = 0
For K = 0 To 3
Call CopyMem(ByVal VarPtr(dataX) + 1, dataX, 3) 'the problem is here
dataX = (dataX Or Key(j))
j = j + 1
If (j >= KeyLength) Then j = 0
Next
m_pBox(i) = m_pBox(i) Xor dataX
Next
End Property
CopyMem sub lib how do i use it in vb.net
now here is my vb.net code for the same
Private Declare Sub CopyMem Lib "KERNEL32" Alias "RtlMoveMemory" (ByVal pDst As Object, ByVal pSrc As Object, ByVal ByteLen As Integer)
Public WriteOnly Property Key() As String
Set(ByVal Value As String)
Dim i As Long
Dim j As Long
Dim K As Long
Dim dataX As Long
Dim datal As Long
Dim datar As Long
Dim Key() As Byte
Dim KeyLength As Long
'Do nothing if the key is buffered
If (m_KeyValue = Value) Then Exit Property
m_KeyValue = Value
'Convert the new key into a bytearray
KeyLength = Len(Value)
Key = System.Text.Encoding.Unicode.GetBytes(Value)
'Create key-dependant p-boxes
j = 0
For i = 0 To (ROUNDS + 1)
dataX = 0
For K = 0 To 3
CopyMem(VarPtr(dataX) + 1, dataX, 3) ' the problem is here
dataX = (dataX Or Key(j))
j = j + 1
If (j >= KeyLength) Then j = 0
Next
m_pBox(i) = m_pBox(i) Xor dataX
Next
End Property
here is code for VarPtr
Public Function VarPtr(ByVal e As Object) As Object
Dim GC As GCHandle = GCHandle.Alloc(e, GCHandleType.Pinned)
Dim GC2 As Integer = GC.AddrOfPinnedObject.ToInt32
GC.Free()
Return GC2
End Function
i have refered to Equivalent of CopyMemory in .NET
but still i am not getting this
please somebody help!!!
If you want to access data using pointers in .NET then you need to keep them pinned during the whole operation. The VarPtr method pins the object while getting the address to it, but then it unpins the object. That means that the object can be moved while you are doing the CopyMem call. Most of the time the object isn't moved, so it would seem to work fine, but when it is moved the CopyMem operation could change some other data. That could make any object in your application behave strangely, or crash the application.
Anyhow, using memory copy is definitely overkill for moving a few bits in an integer. (The Long data type in VB 6 corresponds to the Integer data type in VB.NET by the way.)
You can convert the integer to a byte array, use the Array.Copy method, and then convert it back:
Dim temp As Byte() = BitConverter.GetBytes(dataX)
Array.Copy(temp, 0, temp, 1, 3)
dataX = BitConverter.ToInt32(temp, 0)
You can also do it using bit operations:
dataX = (dataX And &HFF) Or (dataX << 8)
Side note: The Encoding.Unicode is for the UTF-16 encoding. That means that the byte array that GetBytes returns will be twice the length of the string, so you will be using only half of the string.

VBA timer api memory usage

i am developing an app that will be working for days and implements a Timer (From user32 lib) that is running its routine every 500ms. The problem is that every time the routine executes, the memory required by the Excel App is being increased by 8KB.
As i said i will like the app to be running for days so there is a point that it's memory consumptions is too high, and the app starts to be too slow.
I've searched in this and other places for a way to solve but i haven't find a solution. I read about forcing GC but in vba i cant do it. ¿Can anyone give me some advice?
P.d.: Thank you and sorry for my poor english.
Edit:
Hi again, i use the Timer Event to communicate to a PLC and act in consequence. Maybe 0.5 seconds is such a short period of time that the code can't finish the routine and the events are being located in the stack. I think i could extend the time to 1 second without losing performance.
Here is my code:
API DECLARATIONS
Private Declare Function SetTimer Lib "user32" _
(ByVal hWnd As Long, _
ByVal nIDEvent As Long, _
ByVal uElapse As Long, _
ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" _
(ByVal hWnd As Long, _
ByVal nIDEvent As Long) As Long
TIMER EVENT ROUTINE
Private Sub TimerEvent()
On Error Resume Next
Hoja1.cmdFecha.Caption = Format(Now, "dd/mm/yy hh:mm:ss")
Hoja6.Range("I40") = 0
'Zona Lectura PLC
Call readFromPLC
If Hoja6.Range("I40") = 0 Then
Hoja4.Range("c11") = 1
Else
Hoja4.Range("c11") = 0
End If
'Zona alarmas
If Hoja4.Range("C7") <> AlarmaAnterior Then
' Interrupcionpo calculo
AlarmaAnterior = Hoja4.Range("D10")
If Hoja4.Range("c7") = 0 Then
Hoja1.Label1.Visible = False
Else
'Hoja4.Range("d8") = Hoja4.Range("d8") + 1
'Call Control
Call AlarmasNuevo
Hoja1.Label1.Visible = True
End If
End If
'Zona actuacion
If Hoja6.Range("d61") <> Hoja6.Range("d62") Then
Hoja6.Range("d62") = Hoja6.Range("d61")
Hoja6.Range("d66") = Hoja6.Range("d66") + 1
Call ControlArchivos
End If
If Hoja6.Range("d63") <> Hoja6.Range("c63") Then
Hoja6.Range("d63") = Hoja6.Range("c63")
Call ResetContadores
End If
If Hoja6.Range("I50") = 0 Then
ElseIf Hoja6.Range("I49") <> Hoja6.Range("j49") Then
Hoja6.Range("J49") = Hoja6.Range("i49")
If Hoja6.Range("I49") <> 0 Then
Call Medir
Else
Call StopAcq
Sheets("ESCPLC").Range("J58") = 0
Hoja1.cmdAvisos.Visible = False
End If
End If
'Zona escritura PLC
If Hoja6.Range("J57") <> Hoja6.Range("L57") Or Hoja6.Range("J58") <> Hoja6.Range("L58") Or Hoja6.Range("J59") <> Hoja6.Range("L59") Or Hoja6.Range("J60") <> Hoja6.Range("L60") Or Hoja6.Range("J61") <> Hoja6.Range("L61") Then
Hoja6.Range("L57") = Hoja6.Range("J57")
Hoja6.Range("L58") = Hoja6.Range("J58")
Hoja6.Range("L59") = Hoja6.Range("J59")
Hoja6.Range("L60") = Hoja6.Range("J60")
Hoja6.Range("L61") = Hoja6.Range("J61")
Call writeToPLC
End If
End Sub
Thank You very much

How to points Width and Height from LoadImage() in PowerPoint

I am using LoadPicture method in my macro to load an jpg image. I want to know its width and height but the values that I get are not useful. I try to find a solution in some forums and I saw this solution:
Set oBmp = LoadPicture(FileName)
Hght = ScaleX(oBmp.Width, vbHimetric, vbPixels)
Wdth = ScaleY(oBmp.Height, vbHimetric, vbPixels)
The problem is that in powerpoint ScaleX and ScaleY are not working. At least in my powerpoint gives me the compile error: Method or data member not found.
I am also trying with this peace of code:
Dim myPic As IPictureDisp
Set myPic = LoadPicture("C:\dink_template\dinkFile\sizeimage.jpg")
Hght = myPic.height
wid = myPic.width
I check the image and his size in pixels are height = 132px and width= 338px but with that I am getting Height = 2794 and width 7154
How can I use the ScaleX/ScaleY in powerpoint? Or if I cannot use them how can pass the values to pixel?
This was fairly tricky. The dimensions you're receiving from the .Width and .Height property are actually OLE_YSIZE_HMETRIC/OLE_XSIZE_HMETRIC, which from what I can find out, are an increment of measurement representing 0.01mm.
I didn't initially see any easy workaround for this, (formula or at least a WinAPI function that would be helpful).
This should work for most users who have normal/default screen resolution settings
Function uses late-binding/does not require a reference to Publisher, although the library still needs to be available on user's machine.
Option Explicit
Sub Test()
Dim filepath$
filePath = "C:\image_file.JPG"
MsgBox "Height = " & GetImageDimensions(filepath)(0) & vbNewLine & _
"Width = " & GetImageDimensions(filepath)(1), vbOKOnly, "Dimensions"
End Sub
Function GetImageDimensions(filepath) As Variant
'Function returns an array of (Height, Width) from a specific image file path
'
Dim tmp(0 To 1) As Long
Dim oPub As Object
Set oPub = CreateObject("Publisher.Application")
'returning picture.width in OLE_YSIZE_HIMETRIC/OLE_XSIZE_HIMETRIC
' these are representing 0.01 mm
With LoadPicture(filepath)
'Multiply by 0.01 to get dimension in millimeters, then
' use the MS Publisher functions to convert millimeters -> points -> pixels
tmp(0) = 0.01 * oPub.PointsToPixels(oPub.MillimetersToPoints(.Height))
tmp(1) = 0.01 * oPub.PointsToPixels(oPub.MillimetersToPoints(.Width))
End With
GetImageDimensions = tmp
End Function
Here is a test case:
And here are the results:
UPDATE FROM COMMENTS
I get the following dimensions while debugging:
.Height = 3493
.Width = 8943
However, you indicate that you get 2794 and 7154, respectively.
I can replicate your results when I change screen resolution (e.g., 125%). The method below should resolve that discrepancy.
Attempting to use WinAPI to (hopefully) account for whatever discrepancy we're getting (pixel size, perhaps is different on your computer, which could cause this, although I'd expect the Publisher functions would account for this...)
This function with WinAPI call should work for all users, regardless of resolution
Function GetImageDimensions2(filePath As String) As Variant
'Function returns an array of (Height, Width) from a specific image file path
Dim tmp(0 To 1) As Long
'returning picture.width in OLE_YSIZE_HIMETRIC/OLE_XSIZE_HIMETRIC
' these are representing 0.01 mm
With LoadPicture(filePath)
tmp(0) = .Height / 2540 * (1440 / TwipsPerPixelY())
tmp(1) = .Width / 2540 * (1440 / TwipsPerPixelX())
End With
GetImageDimensions2 = tmp
End Function
And include these WinAPI calls in another module:
Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, _
ByVal hdc As Long) As Long
Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, _
ByVal nIndex As Long) As Long
Const HWND_DESKTOP As Long = 0
Const LOGPIXELSX As Long = 88
Const LOGPIXELSY As Long = 90
'--------------------------------------------------
Function TwipsPerPixelX() As Single
'--------------------------------------------------
'Returns the width of a pixel, in twips.
'--------------------------------------------------
Dim lngDC As Long
lngDC = GetDC(HWND_DESKTOP)
TwipsPerPixelX = 1440& / GetDeviceCaps(lngDC, LOGPIXELSX)
ReleaseDC HWND_DESKTOP, lngDC
End Function
'--------------------------------------------------
Function TwipsPerPixelY() As Single
'--------------------------------------------------
'Returns the height of a pixel, in twips.
'--------------------------------------------------
Dim lngDC As Long
lngDC = GetDC(HWND_DESKTOP)
TwipsPerPixelY = 1440& / GetDeviceCaps(lngDC, LOGPIXELSY)
ReleaseDC HWND_DESKTOP, lngDC
End Function