2022-02-24 NOTE: This does not run on latest v2-beta. Runs fine on AutoHotkey v1.
This project has been superseded by ImagePut for image processing, and TextRender for subtitles and text/image rendering.
❧ [Download] ☙
If your script doesn't work you need to:
Add #Persistent to the top of your script or a hotkey.
Assign a := RenderText() to a variable or include a time parameter RenderText("✿", "time:8s")
Possible Applications:
Rendering text and images to screen
Converting images to other file formats (jpg, png) and other encodings (base64)
I've been working on this on and off for a long time... It seems there's always new improvements and new issues to address. I'd rather push it out in an incomplete state than wait for completeness. Thanks!
As always suggestions, improvements, and importantly your example scripts are welcome. (Rainmeter widget anyone?)
Last edited by iseahound on 26 Feb 2022, 13:06, edited 7 times in total.
#include <Graphics>
#Persistent
g := new Graphics.TextRenderer
g := new Graphics.INTERACTIVE(g) ; Not really needed other than for fun! :D
; Draw backing rectangles.
g.Draw(, "c:33FAB4 x:27.5vw w:15vw h:160")
g.Draw(, "c:FBDDB5 x:42.5vw w:15vw h:160")
g.Draw(, "c:F77563 x:57.5vw w:15vw h:160")
; Draw Text
g.Draw("Graphics", "c:Off", "s:120pt f:(Avenir LT Pro 55 Roman) c:C1BCA6")
; Draw Outline Glow. This is a unique method, because the font color is set to "off" which makes the text transparent.
; Additionally, the outline fill method would normally be used instead of the draw text method contributing to a mismatch in the two font fills.
; In other words when the outline parameter is set, the graphics engine uses a different method to draw the text.
; In this case we use the normal method of drawing text and proceed to use the outline engine to draw the text glow.
; If these two lines were combined the outline engine would both draw the text and draw the text glow.
g.Draw("Graphics", "c:Off", "s:120pt f:(Avenir LT Pro 55 Roman) c:Off outline:(stroke:0px color:#070707 glow:2px tint:#070707)")
g.Render()
g.Save("hi2.png")
Syntax
Units All syntax is based on or similar to CSS. As such it should be intuitive to use.
px - pixels
vh - defined as 1% of the viewport height. A_ScreenHeight * 0.01
vw - definded as 1% of the viewport width. A_ScreenWidth * 0.01
vmin - defined as 1% of which ever is smaller, the viewport width or the viewport height. Smaller of vh and vw.
% - relative to something. For example:dropshadow's size:2% is relative to the font size * 0.01.
pt - point. Equal to pixels.
You can omit units. Most will default to pixels.
Background Style
t, time - Set the amount of milliseconds to display text on the screen. Examples: 3000
a, anchor - Set the x, y origin point. The default is topleft. Examples: bottomright, and centercenter.
x, left - Set x coordinate. Examples: 500px, Right, 12%, 33vw
y, top - Set y coordinate. Examples: 200, 200px, bottom, 75vh
w, width - Set width. Examples: 12px, 67%, 10vmin
h, height - Set height. Examples: 10vh, 10%, 10vw, 10vmin
r, radius - Set radius of rounded corners. (percentage is defined as a percentage of the smaller background width/height.) Examples: 8, 8px, 8%, 8vmin
c, color - Set color. Examples: 0xFFFFFF, #ABCABC, FF545454
m, margin - Set margins. This will extend the box. (% of A_ScreenWidth/A_ScreenHeight) 5vmin, 20px
Additional Margins: margin:(25px 50px) - top and bottom margins are 25px right and left margins are 50px. margin:(25px 50px 75px) - top margin is 25px. right and left margins are 50px. bottom margin is 75px. margin:(25px 50px 75px 100px) - top margin is 25px. right margin is 50px. bottom margin is 75px. left margin is 100px. margin:(top:25px right:50px bottom:75px left:100px) - top margin is 25px. right margin is 50px. bottom margin is 75px. left margin is 100px.
Please see: https://www.w3schools.com/css/css_margin.asp
Text Style
t, time - Set the amount of milliseconds to display text on the screen. Examples: 3000
a, anchor - Set the anchor point of the text field. "topleft" I'm not sure if this works correctly.
x, left - Set x coordinate (% of background width) left, center, right, 10vw
y, top - Set y coordinate (% of background height) top, center, bottom, 10vh
w, width - Set width (% of background width)
h, height - Set height (% of background height)
m, margin - Set margin of text (% of background width) 2vw, 2%
f, font - Set font. f:(avant garde itc)
s, size - Set font size. (% of A_ScreenHeight) 12pt
q, quality - Set Rendering Hint. (0-5, 4 is Anti-Alias recommended, 5 is cleartype and will cause issues with autosizing.)
n, noWrap - Disable text wrapping. noWrap, n:owrap, n1, n:true, neqyehujbdawaw
Some syntax for drop shadow:
horizontal:50px - denotes the horizontal offset.
vertical:50px - denotes the vertical offset.
blur:5px - blurs by 5 pixels (radius)
color:Black - changes color to black.
opacity:0.5 - opacity is at 50%. you might want to do 50% if you like integers.
size:10px - extends the edges by 10 pixels.
So dropshadow:(h:50px v:50px b:5px c:Black o:50% s:10px) would be used. Based on: https://www.w3schools.com/css/css3_shadows.aspdropshadow:(50px 50px 5px Black 50% 10px) will work but position of elements matter.
Syntax for outline:
stroke:1px - a one pixel outline does wonders to increase the readability of text without changing the font size.
color:Blue - outline color.
glow:7px - extends the edge (counting from the end of the outline) and creates a glow of 7pixels. Try to use a value less than 4 pixels if you want fast rendering.
tint:Purple - specifies the glow tint. This will give the glow a unique color.
So outline:(stroke:1px color:Blue glow:7px tint:purple) would be used.
Tips and Tricks
You can call a.Draw("hi", "xCenter") multiple times, then call a.Render() with blank parameters to render all those draws on screen.
If you need to display text on screen temporarily, take advantage of the time syntax - Subtitle.Render("Au revoir.", "time:3000") - this will display "Au revoir." for 3 seconds, or 3000 milliseconds!
You can call Subtitle.Render(text, backgroundstyles, textstyles) by itself. Or you can make it into an object: a := Subtitle.Render(text, backgroundstyles, textstyles) Use this one-line format to save time and space!
If you are memory-conscious, be sure to call a.FreeMemory() immediately after, since you only want to display static text.
Avoid using the glow parameter (3rd parameter in outline) it's very slow and will delay your render time. If you must use it, choose an small number less than 5px. Anything more will slow down your script.
If your text looks too small and you don't want to increase the font size, set the outline width to 1, and the outline color to your text color. Not only will this increase readability, but it will also decrease space between letters, saving your on-screen real estate! Example: o(1px) or outline:(stroke:1px)
You can speed up text rendering by setting quality (in the text parameter) to 0. This will disable anti-aliasing. You can create a cool stencil effect with q0 cNone o(1 Black) or quality:0 color:None outline:(stroke:1px color:Black)
If you want to set the background to be transparent, you can use cNone, cOff, cClear, or cTransparent. Don't use w0 or h0. Even though they work - they act weird changing your x and y positions.
If you want to make the text transparent, you should try color:Delete or color:Erase. This only works in textstyles, making the text "eat" through the background.
Recycle! Avoid Subtitle instances like Subtitle.Render("x") and set them to an object. a := Subtitle.Render("x") Now reuse object a as many times as you can in your script.
A note on Save() and Render(). Once something is rendered, it can still be saved. But the second you draw something new, by calling Draw() or Render() after an initial Render() - Save() will forget your first drawing and only save what was drawn after the last Render() call.
Take advantage of string notation. It's extremely concise, and just as fast as object notation. It's perfect for one-liners of the form Subtitle.Render(text, backgroundstyles, textstyles)
Once you start reusing your Subtitle Object, it's time to switch to Object Notation for easier accessibility.
When using Object notation, try to avoid using one letter abbreviations such as text.c. Instead use text.color as it's easier to remember.
You can forget about a Subtitle Object if it has the time parameter set - it will self delete on expiry.
Use the toggles .AlwaysOnTop(), .ClickThrough() and .ToggleVisible() to change properties of the window.
If you want to activate the window send .Show(1). By default .Show() will not activate the window.
Grab the unique window id by calling a.hwnd
If you want to name the window title, use the new constructor. a := new Subtitle("Window Title")
Chaining properties is very useful. Subtitle.Render("hi!", "color:Pink", "color:White").AlwaysOnTop().FreeMemory() will make a window that is not always on top, and cannot be edited since its Bitmap memory has been cleared.
[/list]
List Of Methods
There are 2 recommended ways of creating a Subtitle Object. a := new Subtitle(windowTitle) - Specify an optional title for the window. b := Subtitle.Render("Hello", "cBlue")
2 Important Methods a.Draw(text, backgroundstyles, textstyles, pGraphics) - Use this to Draw without rendering anything on screen. 4th parameter specifies a custom pGraphics different from the internal pGraphics. a.Render(text, backgroundstyles, textstyles, drawToScreen) - Calls the Draw() function and renders the text on the screen, including all previous draw functions. 4th parameter is optional and defaults to true.
If both backgroundstyles and textstyles are omitted, it will draw the text using the previous set of styles. Only works when both styles are omitted.
If text is omitted, no text will be drawn. You can still paint boxes though.
Saving the Image a.Save(filename, quality := 92) - Saves the image to a file. If you omit the file extension, it will default to PNG. If you enter a JPG extension, you can specify a quality parameter between 1 and 100. If the filename is omitted, it will use the window title which by default is in the form of "Subtitle_0xXXXXX" a.Screenshot(filename, quality := 92) - Saves the image to a file but takes a screenshot instead. a.Bitmap() Parameters are: (x,y,w,h). Returns a bitmap object. Does not crop the image. x,y,w,h values will crop the image. a.hBitmap() Parameters are: (alpha). Returns a hBitmap. Transparency is converted to alpha. Alpha transparency cannot be kept. a.RenderToBitmap() Parameters are: (text, backgroundstyles, textstyles). Renders the image to an hBitmap and does not display it on screen. If you did not create a Subtitle Object beforehand and called a:= Subtitle.RenderToHBitmap() a will be your hBitmap. a.RenderToHBitmap() Parameters are: (text, backgroundstyles, textstyles). Renders the image to an hBitmap and does not display it on screen. If you did not create a Subtitle Object beforehand and called a:= Subtitle.RenderToHBitmap() a will be your hBitmap.
Positions a.x1() - Returns the x position. a.x2() - Returns the x2 position. a.y1() - Returns the y position. a.y2() - Returns the y2 position. a.width() - Returns the width. a.height() - Returns the height.
Window Methods a.AlwaysOnTop() - Toggles the Always on top flag. a.Bottom() - Sends the window to the Botton of the z-order, below all other windows. a.ClickThrough() - Toggles the click through flag. a.Desktop() - Draws behind the desktop icons, basically on your desktop wallpaper. Windows 8/10 only. a.Normal() - Disable the AlwaysOnTop flag. a.Destroy() - Destroys the Subtitle Object and destroys the window. a.Hide() - Hides the window. a.Show() - Shows the window. a.ToggleVisible() Hide the window if visible, show the window if hidden. a.isVisible() Returns 1 if Visible, 0 if hidden.
It's useful to chain these object properties like so: a := new Subtitle().AlwaysOnTop() to create a subtitle that is not always on top.
Memory a.FreeMemory() - Releases all GDI+ objects, freeing at least 6MB of RAM. You will not be able to Draw() or Render() anymore. The only methods you can call will be Save(), Screenshot(), and Destroy(). Plus all window and position methods.
If you call Gdip_Shutdown(pToken) afterwards you will release an additional 3MB of RAM. If you do so, you will not be able to call Save() or Screenshot() anymore. But your image on screen will remain unaffected.
Thanks for the inspiration random person on the internet!
Last edited by iseahound on 04 Aug 2019, 15:20, edited 2 times in total.
This looks very useful. I might suggest that since it is v1 compatible, you might want to also post this in the main section of Scripts and Functions since people who only use v1 will rarely if ever check out the v2 subforum, and there are potentially a lot more people there who would make use of this.
I was not aware of an updated version of Gdip_all.
I would recommend any ahk script that requires #include to add a link to that required file in the opening post. This would insure that all files (and correct versions) are available to run the script.
That way I don't have to search for the latest or at least a compatible version of the #include files.
Hello, I'm reading the source of your lib and I could see that only the text supports outline and dropShadow
I'm writing a similar lib: viewtopic.php?f=76&t=100779
I wonder if you could help adapt these parameters to be also supported by the background.
My Gaussian Blur function isn't great, but the outline part should be straightforward. You''ll have to draw a rectangle/circle path, then call GdipDrawPath. Also if you intend to use GDI+ to perform a Gaussian Blur - don't. It's broken and has been replaced by https://docs.microsoft.com/en-us/windows/win32/direct2d/gaussian-blur. I probably say this a lot, but malcev (a user on our forum) is the expert at calling these advanced APIs.
My Gaussian Blur function isn't great, but the outline part should be straightforward. You''ll have to draw a rectangle/circle path, then call GdipDrawPath. Also if you intend to use GDI+ to perform a Gaussian Blur - don't. It's broken and has been replaced by https://docs.microsoft.com/en-us/windows/win32/direct2d/gaussian-blur. I probably say this a lot, but malcev (a user on our forum) is the expert at calling these advanced APIs.
Thank you so much for the function! Yours is waay good enough for my use case (image composition).