Text highlighter using Gdip

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
mct300
Posts: 5
Joined: 10 Dec 2017, 16:38

Text highlighter using Gdip

21 Jan 2018, 23:11

How to make a text highlighter using Gdip in a way that multiple parts of the text can be highlighted after selecting with mouse. I plan to use it to highlight the important part of articles during reading and then take a screenshot shot. is it possible to move the highlighted parts together with mouse scrolling?
User avatar
Exaskryz
Posts: 2882
Joined: 17 Oct 2015, 20:28

Re: Text highlighter using Gdip

21 Jan 2018, 23:52

is it possible to move the highlighted parts together with mouse scrolling?
That's going to get problematic, but not impossible.

I don't think AHK is going to be the right tool for you.

What is your program?

There is a firefox addon called Wired Marker that I use to highlight text in webpages. But I don't know if it's available with the latest version of FIrefox that killed all the good addons.

If you use Adobe Reader for reading PDFs, you could use the highlighter tool in there (and I've used AHK to make a hotkey to automate that*), though it can't highlight images (so pictures of text, like what you see on Twitter to bypass their 280 character limit). You can print web pages to PDF if you need to; I use the "printer" CutePDF Writer.

*The highlighter tool automation I used was to use a hotkey to click on the highlight button, so the text I had selected became persistently highlighted. I don't recall if I needed to capture the mouse position or not and move the mouse back to where it started -- I did that with putting comments in my PDF through Adobe Reader.

---

Maybe someone has such a tool though. I envision being able to image recognition text that was highlighted to put a GUI highlight that is +AlwaysOnTop and +E0x20 style (click through window). You would create an array of the text as images corresponding to highlights, and as the page changes (scrolled) you would re-search for each image on screen to pair it up with the highlight. You'd have to save in memory this array so that as you scroll the text off-screen, and then scroll it back on-screen, the highlight comes back. You'd probably want to save the window title information as well so you can work with multiple documents, whether simultaneously or sequentially, whether you were going to revisit the page or not.

I know the taking a screenshot part should be easy with Gdip, but I've never done it. Heck, if you press Alt+PrintScreen I think it is (could be Shift+PrintScreen or Ctrl+PrintScreen), you get a SS saved to your Pictures\Screenshots folder, at least on Windows 8. Pretty sure it was in 7, could be earlier. And this is without AutoHotkey, it's a native windows feature. You could use AHK to just do the native windows shortcut to save the image I'm sure.
mct300
Posts: 5
Joined: 10 Dec 2017, 16:38

Re: Text highlighter using Gdip

22 Jan 2018, 01:21

Thanks Exaskryz. I want to make it easy to use and very fast for all programs. Using different tools for this purpose isn't convenient for me.

How to draw a rectangle with the size of highlighted text or at least a tiny line as long as the highlighted text?
I will use Joe Glines's screen clipper for taking screenshots.
gregster
Posts: 9021
Joined: 30 Sep 2013, 06:48

Re: Text highlighter using Gdip

22 Jan 2018, 01:35

As long as you don't scroll the text, the highlighting part might be relatively easy to implement as an simple overlay. But if the text still can be edited or is so large that you have to scroll, you will run in all kind of problems, especially if you want to create a fast "one-for-all" application (imagesearch and potentially OCR for some applications can be time critical). Exaskryz gave you some hints about some of the problems you might encounter.
I don't know how much programming experience you have, but I would recommend to start with smaller projects, because this one could be tricky and there is no guarantee that you will end up with a smooth working solution.
mct300
Posts: 5
Joined: 10 Dec 2017, 16:38

Re: Text highlighter using Gdip

22 Jan 2018, 02:21

Scroll calibration for common programs at the very beginning won't solve the problem?
User avatar
Exaskryz
Posts: 2882
Joined: 17 Oct 2015, 20:28

Re: Text highlighter using Gdip

22 Jan 2018, 04:25

If you restrict scrolling input to be one input method, it could work. You could figure out the calibration dynamically in the script, or hard code it depending on the program you're using. Dynamic would be better because you could be working at different zoom levels.

I don't have any example code using Gdip; I haven't used that library.

I recently used this code to highlight the text field of a notepad window:

Code: Select all

#IfWinActive ahk_exe Notepad.exe
!n::
WinGetPos, varx, vary, varw, varh, A
varx+=8
varw-=16
vary+=50
varh-=58
Gui, Color, 0x4488FF
Gui, +LastFound +AlwaysOnTop -Caption +E0x20
WinSet, Transparent, 120
Gui, Show, x%varx% y%vary% w%varw% h%varh% NoActivate, Overlay
return
You can use that as inspiration. I realize I may have been able to use ControlGetPos to capture the location of the Edit control in Notepad to draw my window over that, rather than using hardcoded offsets.

This is code I used years ago for coloring multiple notepads. It's probably disgusting:

Code: Select all

DetectHiddenWindows, On
SetTitleMatchMode, 2

Gui, MyColorPanes:New
;Gui, MyColorPanes:Color, Black, FF0000
Gui, MyColorPanes:Add, Button, w100 y0 gMagicFF0000 vRed, Red
Gui, MyColorPanes:Add, Button, w100 y0 gMagic00FF00 vGreen, Green
Gui, MyColorPanes:Add, Button, w100 y0 gMagic0000FF vBlue, Blue
Gui, MyColorPanes:Add, Button, w100 y0 gMagicFF00FF vMagenta, Magenta
Gui, MyColorPanes:Add, Button, w100 y0 gMagicFFFF00 vYellow, Yellow
Gui, MyColorPanes:Add, Button, w100 y0 gMagic00FFFF vCyan, Cyan
Gui, MyColorPanes:Add, Button, w100 y0 gMagicFFFFFF vWhite, White
Gui, MyColorPanes:Add, Button, w100 y0 gMagic000000 vBlack, Black
Gui, MyColorPanes:Add, Button, w100 y0 gMagicAAAAAA vLightGray, Light Gray
Gui, MyColorPanes:Add, Button, w100 y0 gMagic555555 vDarkGray, Dark Gray
Gui, MyColorPanes:Show, y0 AutoSize XCenter, MyColorPanes
WinSet, Style, -0x800000, MyColorPanes
Gui, MyColorPanes:Hide

ni1:=800080
ni2:=808000
ni3:=008080
ni4:=000080
ni5:=008000
ni6:=800000
ni7:=808080
ni8:=FF00FF
ni9:=FFFF00
ni10:=00FFFF
; This in preparation for a new Gui to select colors for myself.
Return

/*
!y:: ; Experimenting with controls
WinGetPos, PosX, PosY, PosW, PosH, .txt - Notepad
ControlGetPos, TestX, TestY, TestWidth, TestHeight, Edit1, .txt - Notepad
;ControlGetPos, DestX, DestY, DestWidth, DestHeight, Scintilla1, - Notepad++
MestX:=PosX+TestX ; So the Test coordinates are always retrieved relative to the window. I could not set them to be relative to the screen.
MestY:=PosY+TestY
Progress, 1: zh0 X%MestX% Y%MestY% W%TestWidth% H%TestHeight% CWFFFF00 b,,,lol1
;Progress, 2: zh0 X%DestX% Y%DestY% W%DestWidth% H%DestHeight% CWFF00FF b,,,lol2
WinSet, Transparent, 100, lol1
Return 
*/

;So the idea would probably to use a Regex to find "- Notepad" similar to how I'm using iTunes and iMonitor. Once I have that found, life can begin to florish. 


!e:: ; Add a custom color, single window
ToggleV:=!ToggleV
If(ToggleV=1)
	{
	WinGetTitle, TWOB, A
	Gui, MyColorPanes:Show, y0 AutoSize XCenter, MyColorPanes
	WinSet, Style, -0x800000, MyColorPanes
	;MsgBox % TWOB
	}
If(ToggleV=0)
{
Gui, MyColorPanes:Hide
SetTimer, Monitor2, Off
SetTimer, iMonitor, Off
Progress, 10:Off
}
Return

MagicFF0000: ; Red
Magic00FF00: ; Green
Magic0000FF: ; Blue
MagicFF00FF: ; Magenta
MagicFFFF00: ; Yellow
Magic00FFFF: ; Cyan
MagicFFFFFF: ; White
Magic000000: ; Black
MagicAAAAAA: ; Light Gray
Magic555555: ; Dark Gray
ni0 := SubStr(A_ThisLabel, 6)
Gui, MyColorPanes:Hide
WinGetPos, KolorX, KolorY, KolorWidth, KolorHeight, %TWOB%
IfInString, TWOB, iTunes
   {
   iX:=KolorX+130
   iY:=KolorY+11
   iHeight:=KolorHeight-21
   iWidth:=KolorWidth-145
   Progress, 10: CW%ni0% X%iX% Y%iY% W%iWidth% H%iHeight% zh0 b,,,KK10
   ;MsgBox % iY . " " . ix . " " . iHeight . " " . iWidth
   SetTimer, iMonitor, 30000
   }
else
{
Progress, 10: CW%ni0% X%KolorX% Y%KolorY% W%KolorWidth% H%KolorHeight% zh0 b,,,KK10
SetTimer, Monitor2, 5000
}
WinSet, Transparent,100,KK10
WinSet, ExStyle, +0x20, KK10 ; This is for clickthrough
Return

Monitor2:
;I thought I might have to do WinGet, MinMax and if the Variable was -1 (meaning minimized) then I could just make it Return and not redraw the Progress window on top. But the progress window isn't be redrawn with it on top, I guess because the dimensions give it no space to draw.
WinGetPos, KolX, KolY, KolW, KolH, %TWOB%
IfWinNotExist, %TWOB%
{
Progress, 10:Off
;Msgbox % Hyppk
Return ; This was Continue in the original with a loop
}
If((KolX<>KolorX) || (KolY<>KolorY) || (KolW<>KolorWidth) || (KolH<>KolorHeight))
{
Progress, 10: CW%ni0% X%KolX% Y%KolY% W%KolW% H%KolH% zh0 b,,,KK10
;MsgBox % KolX . " - " . KolY . " - " . KolW . " - " . KolH . " `n " . KolorX . " - " . KolorY . " - " . KolorWidth . " - " . KolorHeight
KolorX:=KolX
KolorY:=KolY
KolorHeight:=KolH
KolorWidth:=KolW
WinSet, Transparent,100,KK10
WinSet, ExStyle, +0x20, KK10 ; This is for clickthrough
}
WinSet, AlwaysOnTop, On,KK10
;Consider just using WinSet, Top, KK10. Nah, seems to have been fine.
Return

iMonitor:
IfWinNotExist, %TWOB%
{
Progress, 10:Off
Return
}
WinGetPos, KolX, KolY, KolW, KolH, %TWOB%
If((KolX<>KolorX) || (KolY<>KolorY) || (KolW<>KolorWidth) || (KolH<>KolorHeight))
   {
   iX:=KolorX+130
   iY:=KolorY+11
   iHeight:=KolorHeight-21
   iWidth:=KolorWidth-145
   KolorX:=KolX
   KolorY:=KolY
   KolorHeight:=KolH
   KolorWidth:=KolW
Progress, 10: CW%ni0% X%iX% Y%iY% W%iWidth% H%iHeight% zh0 b,,,KK10
WinSet, Transparent,100,KK10
WinSet, ExStyle, +0x20, KK10
}
WinSet, AlwaysOnTop, On,KK10
Return


;An idea struck me. What if I use a variable that increases until 10 then drops back to 1

^e:: ; Add a window
ColorCount:=0
Bismuth:=0
Loop
{
ColorCount++
Bismuth++
}
Until (OutputVar%ColorCount%="")
WinGetTitle, OutputVar%ColorCount%, A
WinGetPos, ColorX, ColorY, ColorWidth, ColorHeight, % OutputVar%ColorCount%
IfInString, OutputVar%ColorCount%, iTunes
   {
   ColorX+=130
   ColorY+=11
   Colorheight-=21
   ColorWidth-=145
   Progress, 10: CW%ni0% X%iX% Y%iY% W%iWidth% H%iHeight% zh0 b,,,KK10
   }
IfInString,OutputVar%ColorCount%, - Notepad
{
	IfNotInString,OutputVar%ColorCount%, - Notepad++ ; So we want just Notepad here
	{
		ControlGetPos, ConX, ConY, ConW, ConH, Edit1, % OutputVar%ColorCount%
		ColorX+=ConX ; Add instead of replace?
		ColorY+=ConY
		ColorWidth:=ConW
		ColorHeight:=ConH
	}
}
If(ColorCount=1)
Progress, 1: CW%ni1% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC1
If(ColorCount=2)
Progress, 2: CW%ni2% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC2
If(ColorCount=3)
Progress, 3: CW%ni3% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC3
If(ColorCount=4)
Progress, 4: CW%ni4% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC4
If(ColorCount=5)
Progress, 5: CW%ni5% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC5
If(ColorCount=6)
Progress, 6: CW%ni6% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC6
If(ColorCount=7)
Progress, 7: CW%ni7% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC7
If(ColorCount=8)
Progress, 8: CW%ni8% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC8
If(ColorCount=9)
Progress, 9: CW%ni9% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC9
If(ColorCount=10)
Progress, 10: CW%ni10% X%ColorX% Y%ColorY% W%ColorWidth% H%ColorHeight% zh0 b,,,CC10
Title%ColorCount%:=OutputVar%ColorCount%
ColorX%ColorCount%:=ColorX
ColorY%ColorCount%:=ColorY
ColorHeight%ColorCount%:=ColorHeight
ColorWidth%ColorCount%:=ColorWidth
WinSet, Transparent,100,CC%ColorCount%
WinSet, ExStyle, +0x20, CC%ColorCount%
SetTimer, Monitor, 5000
/*
IfInString, OutputVar%ColorCount%, - Notepad ;;; This isn't the best because it Draws first, then looks to update the Notepad windows. I should put this in front.
{
IfNotInString, OutputVar%ColorCount%, - Notepad++ ; So we want just Notepad here
ColorX%ColorCount%:=1920
Goto Monitor
}
*/
Return

Monitor:
Loop, %Bismuth% ; Can this just be 10? Or 9?
{
WinGetPos, ColX, ColY, ColW, ColH, % Title%A_Index%
IfWinNotExist, % Title%A_Index%
{
Progress, %A_Index%:Off
OutputVar%A_Index%:=""
Hyppk:=A_Index-1
;Msgbox % Hyppk
ColorCount:=Hyppk
Continue
}
If((ColX<>ColorX%A_Index%) || (ColY<>ColorY%A_Index%) || (ColW<>ColorWidth%A_Index%) || (ColH<>ColorHeight%A_Index%))
{
IfInString, Title%A_Index%, - Notepad
{
	IfNotInString, Title%A_Index%, - Notepad++ ; So we want just Notepad here
	{
		ControlGetPos, ConX, ConY, ConW, ConH, Edit1, % Title%A_Index%
		MolX:=ConX+ColX
		MolY:=ConY+ColY
		Progress, % A_Index . ": CW" . ni%A_Index% . " X" . MolX . " Y" . MolY . " W" . ConW . " H" . ConH . " zh0 b",,,CC%A_Index%
	}
	else
	{
		Progress, % A_Index . ": CW" . ni%A_Index% . " X" . ColX . " Y" . ColY . " W" . ColW . " H" . ColH . " zh0 b",,,CC%A_Index%
	}
}
else IfInString, Title%A_Index%, iTunes
   {
   ColX+=130
   ColY+=11
   ColH-=21
   ColW-=145
   Progress, % A_Index . ": CW" . ni%A_Index% . " X" . ColX . " Y" . ColY . " W" . ColW . " H" . ColH . " zh0 b",,,CC%A_Index%
   }
else
{
;Progress, %A_Index%: CW808000 X%ColX% Y%ColY% W%ColW% H%ColH% zh0 b,,,CC%A_Index%
Progress, % A_Index . ": CW" . ni%A_Index% . " X" . ColX . " Y" . ColY . " W" . ColW . " H" . ColH . " zh0 b",,,CC%A_Index%
;MsgBox % ColX . " - " . ColY . " - " . ColW . " - " . ColH . " `n " . ColorX%A_Index% . " - " . ColorY%A_Index% . " - " . ColorWidth%A_Index% . " - " . ColorHeight%A_Index%
}
ColorX%A_Index%:=ColX
ColorY%A_Index%:=ColY
ColorHeight%A_Index%:=ColH
ColorWidth%A_Index%:=ColW
WinSet, Transparent,100,CC%A_Index%
WinSet, ExStyle, +0x20, CC%A_Index% ; This is for clickthrough
}
WinSet, AlwaysOnTop, On,CC%A_Index%
}
Return

^+e:: ; Remove windows
WinGetTitle, OutputVarClose, A
If(OutputVarClose=Title1) ; used to be =OutputVar1
{
Progress, 1: Off
OutputVar1:=""
SetTimer, Monitor, Off
}
If(OutputVarClose=Title2)
{
Progress, 2: Off
OutputVar2:=""
}
If(OutputVarClose=Title3)
{
Progress, 3: Off
OutputVar3:=""
}
If(OutputVarClose=Title4)
{
Progress, 4: Off
OutputVar4:=""
}
If(OutputVarClose=Title5)
{
Progress, 5: Off
OutputVar5:=""
}
If(OutputVarClose=Title6)
{
Progress, 6: Off
OutputVar6:=""
}
If(OutputVarClose=Title7)
{
Progress, 7: Off
OutputVar7:=""
}
If(OutputVarClose=Title8)
{
Progress, 8: Off
OutputVar8:=""
}
If(OutputVarClose=Title9)
{
Progress, 9: Off
OutputVar9:=""
}
If(OutputVarClose=Title10)
{
Progress, 10: Off
OutputVar10:=""
}
Return

^w:: ; Chance color
InputBox, WN,, What number are you changing?
InputBox, ni%WN%,, % "What color would you like? HEX it! `n It is currently `n" . ni%WN%
ColorX%WN%:=1920
Return

^+w:: ; Round corners
RoundCorners:=!RoundCorners
If(RoundCorners=1)
Loop, %Bismuth%
{
WinGetPos,,,Wilk,Hilk,CC%A_Index%
WinSet, Region, 0-0 w%Wilk% h%Hilk% r20-20,CC%A_Index%
}
If(RoundCorners=0)
Loop, %Bismuth%
{
WinGetPos,,,Wilk,Hilk,CC%A_Index%
WinSet, Region, 0-0 w%Wilk% h%Hilk% r0-0, CC%A_Index%
}
Return

^q:: ; Change transparency
InputBox, QN,,What number are you changing?
InputBox, Qtrans,,How transparent should it be?
WinSet, Transparent,%Qtrans%,CC%QN%
Return

^+q:: ; Minimize all Highlighted windows
Loop, %Bismuth%
{
  WinMinimize, % Title%A_Index%
}
Return

~^+m:: ; iTunes ^!z
Sleep 2000
IfWinActive, iTunes
{
WinGetPos,,,,Heightjillian,A
If(Heightjillian<200) ; This may or may not be tall enough
	{
	WinSet, AlwaysOnTop,,A
	Send #-
	}
}
Return
Anyhow, you need to figure out how you want to draw your highlights. Simple rectangles would be easiest. You may be able to do polygons. It is possible to trade out a window shape using WinSet, Region. I am pretty sure I have seen in the past, probably under "Scripts & Functions" as completed scripts or proof-of-concept scripts about drawing shapes on your screen and rendering that as a GUI image. I would consider using a hotkey like +LButton:: -- shift and left click -- to capture coordinates with every click. You may want a separate hotkey like ^+LButton:: -- ctrl and shift and left click -- to signal the start and end of capturing coordinates.

Scroll offset would be achieved by taking those saved coordinates and then ±'ing them depending on if you use ~WheelDown:: or ~WheelUp::.

Let's say your Mouse Wheel scrolls by 50 pixels. And you have a rectangle at coordinates 250,300 (Top left) and 450,400 (bottom right); in AHK we treat the top-left corner of the screen or window as the origin and the y-axis is positive in the down direction (and x-axis is positive in the right direction). You would need to translate those to 250,250 and 450,350 if you scroll down once -- the text moves up. And if you scroll another 7 times, the bottom corner would be at pixel height 0. I don't know how WinSet or a Gui is going to handle drawing things off screen. Hypothetically it would be fine because you can WinMove a window offscreen. But you may have to save those coordinates for later and decide not to draw the highlight if the bottom/right sides are ≤0, and also the same if the left is ≥A_ScreenWidth and the top is ≥A_ScreenHeight.

The way that I would do a scroll calibration on a document/program is activate a hotkey and click on something in the document at a known pixel. Scroll, and then move the mouse to find that known pixel again, clicking to finish the calibration. But that requires pixel level precision -- if you're off by 1 pixel, after 100 scrolls you're going to be off by 100 pixels. You might be able to set up a way to "create an object" and move it to the right location and then save it. I believe this is where the Gdip library would come in handy. I think you could save a small screen clipping (Like what you get natively with Windows Snipping Tool) and display it in a GUI like with code from above. Make it somewhat transparent. Then click and drag it to line it up with where the content has been scrolled to.

I hope all that made sense or is at least useful -- even to just outline the scale of this project -- because it's 4:30am for me and I should get to bed.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: jeves, mikeyww, septrinus and 287 guests