Frame
A simple golang library that creates an image.Image compatible object (ideally used with draw.Draw) that can be used for drawing a frame around something else. Think like a window, button, or anything else.
It works by splitting an image into 9 parts:

Parts, 1, 3, 7 and 9 are drawn exactly as is. Then the remaining parts
are repeated or stretched to match the content as required.
Other variants might be created such as ones which are more procedurally generated or allow more interesting
views.
Contributions
This is a simple library I am reusing else where. PRs reviewed and probably accepted. But definitely appreciated.
Doc
There is basic go doc which you can check out here:
https://pkg.go.dev/github.com/arran4/golang-frame
The intended way of using this is:
fr := NewBasicFrame(targetArea)
dst := i.SubImage(targetArea).(draw.Image)
draw.Draw(dst, dst.Bounds(), fr, dst.Bounds().Min, draw.Src)
Usage
Sample 2: Drawing borders
Simplest possible use case; take an image and expand it to fit the
desired size.
base, err := png.Decode(bytes.NewReader(baseImageData))
if err != nil {
log.Panicf("Error with loading base file: %s", err)
}
i := image.NewRGBA(image.Rect(0, 0, 600, 600))
dst := i.SubImage(image.Rect(100, 100, 400, 400)).(draw.Image)
fr := frame.NewFrame(dst.Bounds(), base, image.Rect(48,48,55, 66))
draw.Draw(dst, dst.Bounds(), fr, dst.Bounds().Min, draw.Src)
SaveFile(i)
Which will produce:

From:

Sample 3: Section 5 image
This creates a better window implementation than sample 2. But also it shows that the way the borders
are drawn can be changed. As you can almost see in sample 2 the borders aren't drawn well as it's simply
repeating the contents. You can also use a (simple) stretch version instead of the repeating version.
This is done with the BorderMode options see:
fr := frame.NewFrame(frdst.Bounds(), base.(SubImagable).SubImage(s2), image.Rect(14, 48, 88, 66), frame.Repeating)
fr := frame.NewFrame(frdst.Bounds(), base.(SubImagable).SubImage(s2), image.Rect(14, 48, 88, 66), frame.Stretched)
See the sample for a more detailed look at the code. However, the difference this creates is as follows:

From:

Sample 4
In sample 4 we replace the contents of the window with our own rather than use section 5 of the image.
There are currently 3 variants of this:
- Section5Zeroed - Match section 5 starting position with co-ordinates 0, 0
- Zerod - Match the whole frame's starting position with the co-ordinates 0, 0
- PassThrough - Pass in the parent windows position
fr := frame.NewFrame(frdst.Bounds(), base.(SubImagable).SubImage(s2), image.Rect(14, 48, 88, 66), &frame.Section5{Image: s5i}, frame.Section5Zeroed)
fr := frame.NewFrame(frdst.Bounds(), base.(SubImagable).SubImage(s2), image.Rect(14, 48, 88, 66), &frame.Section5{Image: s5i}, frame.Zerod)
fr := frame.NewFrame(frdst.Bounds(), base.(SubImagable).SubImage(s2), image.Rect(14, 48, 88, 66), &frame.Section5{Image: s5i}, frame.PassThrough)
Which draws:

From the frame:

And with the section 5 image:

Please note, currently there is no support / consideration for an image with a none 0,0 Rectangle.Min
position. This might change so ensure your code will handle this.
Sample 4: Simple static image
func NewBasicFrame(r image.Rectangle) *Frame {
middle := image.Rect(0, 0, 1, 1)
base := image.NewRGBA(image.Rect(-2, -2, 2, 2))
b := base.Bounds()
for y, r := range [][]color.RGBA{
{colornames.Lightgray, colornames.Lightgray, colornames.Lightgray, colornames.Lightgray, colornames.Lightgray},
{colornames.Lightgray, colornames.Darkgrey, colornames.Darkgrey, colornames.Darkgrey, colornames.Lightgray},
{colornames.Lightgray, colornames.Darkgrey, colornames.White, colornames.Darkgrey, colornames.Lightgray},
{colornames.Lightgray, colornames.Darkgrey, colornames.Darkgrey, colornames.Darkgrey, colornames.Lightgray},
{colornames.Lightgray, colornames.Lightgray, colornames.Lightgray, colornames.Lightgray, colornames.Lightgray},
} {
for x, c := range r {
base.Set(b.Min.X + x, b.Min.Y + y, c)
}
}
return NewFrame(r, base, middle)
}
func main() {
i := image.NewRGBA(image.Rect(0, 0, 150, 100))
targetArea := image.Rect(10, 10, 100, 30)
fr := NewBasicFrame(targetArea)
dst := i.SubImage(targetArea).(draw.Image)
draw.Draw(dst, dst.Bounds(), fr, dst.Bounds().Min, draw.Src)
}
Noting really amazing here but no need to have files, if you just want to draw a simple border you can
do it this way, you might be able to wrap image.NewUniform(color goes here).Bounds() with a more restricted version.
Sample 5:
Section5 overlaying the previous image. Section5 now allows you to either replace, or overlay (with alpha and all) the
base image's section 5.
Such as:
fr := frame.NewFrame(frdst.Bounds(), fibase.(SubImagable), image.Rect(11, 11, 111, 97), &frame.Section5{Image: s5i, Replace: false}, frame.Section5Zeroed, frame.Stretched)

From:

and the source image generated by:
s5i := image.NewRGBA(image.Rect(0, 0, 50, 50))
for x := 0; x < 50; x++ {
for y := 0; y < 50; y++ {
if x/10%2 == 0 && x/10 == y/10 {
s5i.SetRGBA(x, y, color.RGBA{0, 0, 127, 127})
}
}
}
Additional Helper functions
Draw.Over()
Draw.Over() is an alpha function for Section5 overlays. (It's also the default if you don't specify one)
Usage:
import "github.com/arran4/golang-frame/draw"
frame.Section5{Image: s5i, Replace: false, AlphaMode: draw.Over}
Included Frames
There is a collection of included frames in the frames package. Each frame comes in standard, _large (2x), and _xlarge (3x) variants for high-DPI screens.
AmigaLike

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.AmigaLike.Image, frames.AmigaLike.Middle)
AmigaLikeLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.AmigaLikeLarge.Image, frames.AmigaLikeLarge.Middle)
AmigaLikeXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.AmigaLikeXlarge.Image, frames.AmigaLikeXlarge.Middle)
BeosLike

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.BeosLike.Image, frames.BeosLike.Middle)
BeosLikeLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.BeosLikeLarge.Image, frames.BeosLikeLarge.Middle)
BeosLikeXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.BeosLikeXlarge.Image, frames.BeosLikeXlarge.Middle)
Chains

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Chains.Image, frames.Chains.Middle)
ChainsLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.ChainsLarge.Image, frames.ChainsLarge.Middle)
ChainsXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.ChainsXlarge.Image, frames.ChainsXlarge.Middle)
Checkers

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Checkers.Image, frames.Checkers.Middle)
CheckersLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.CheckersLarge.Image, frames.CheckersLarge.Middle)
CheckersXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.CheckersXlarge.Image, frames.CheckersXlarge.Middle)
ChinaPattern

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.ChinaPattern.Image, frames.ChinaPattern.Middle)
ChinaPatternLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.ChinaPatternLarge.Image, frames.ChinaPatternLarge.Middle)
ChinaPatternXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.ChinaPatternXlarge.Image, frames.ChinaPatternXlarge.Middle)
Dots

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Dots.Image, frames.Dots.Middle)
DotsLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.DotsLarge.Image, frames.DotsLarge.Middle)
DotsXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.DotsXlarge.Image, frames.DotsXlarge.Middle)
FantasyStone

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.FantasyStone.Image, frames.FantasyStone.Middle)
FantasyStoneLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.FantasyStoneLarge.Image, frames.FantasyStoneLarge.Middle)
FantasyStoneXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.FantasyStoneXlarge.Image, frames.FantasyStoneXlarge.Middle)
Floral

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Floral.Image, frames.Floral.Middle)
FloralLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.FloralLarge.Image, frames.FloralLarge.Middle)
FloralXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.FloralXlarge.Image, frames.FloralXlarge.Middle)
Gold

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Gold.Image, frames.Gold.Middle)
GoldLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.GoldLarge.Image, frames.GoldLarge.Middle)
GoldXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.GoldXlarge.Image, frames.GoldXlarge.Middle)
Hearts

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Hearts.Image, frames.Hearts.Middle)
HeartsLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.HeartsLarge.Image, frames.HeartsLarge.Middle)
HeartsXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.HeartsXlarge.Image, frames.HeartsXlarge.Middle)
MacClassicLike

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MacClassicLike.Image, frames.MacClassicLike.Middle)
MacClassicLikeLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MacClassicLikeLarge.Image, frames.MacClassicLikeLarge.Middle)
MacClassicLikeXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MacClassicLikeXlarge.Image, frames.MacClassicLikeXlarge.Middle)
MacosxLike

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MacosxLike.Image, frames.MacosxLike.Middle)
MacosxLikeLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MacosxLikeLarge.Image, frames.MacosxLikeLarge.Middle)
MacosxLikeXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MacosxLikeXlarge.Image, frames.MacosxLikeXlarge.Middle)

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Metal.Image, frames.Metal.Middle)

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MetalLarge.Image, frames.MetalLarge.Middle)

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MetalXlarge.Image, frames.MetalXlarge.Middle)
MwmLike

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MwmLike.Image, frames.MwmLike.Middle)
MwmLikeLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MwmLikeLarge.Image, frames.MwmLikeLarge.Middle)
MwmLikeXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.MwmLikeXlarge.Image, frames.MwmLikeXlarge.Middle)
NextLike

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.NextLike.Image, frames.NextLike.Middle)
NextLikeLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.NextLikeLarge.Image, frames.NextLikeLarge.Middle)
NextLikeXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.NextLikeXlarge.Image, frames.NextLikeXlarge.Middle)
Rainbow

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Rainbow.Image, frames.Rainbow.Middle)
RainbowLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.RainbowLarge.Image, frames.RainbowLarge.Middle)
RainbowXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.RainbowXlarge.Image, frames.RainbowXlarge.Middle)
Ridge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Ridge.Image, frames.Ridge.Middle)
RidgeLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.RidgeLarge.Image, frames.RidgeLarge.Middle)
RidgeXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.RidgeXlarge.Image, frames.RidgeXlarge.Middle)
ScifiTech

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.ScifiTech.Image, frames.ScifiTech.Middle)
ScifiTechLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.ScifiTechLarge.Image, frames.ScifiTechLarge.Middle)
ScifiTechXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.ScifiTechXlarge.Image, frames.ScifiTechXlarge.Middle)
SignConstruction

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.SignConstruction.Image, frames.SignConstruction.Middle)
SignConstructionLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.SignConstructionLarge.Image, frames.SignConstructionLarge.Middle)
SignConstructionXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.SignConstructionXlarge.Image, frames.SignConstructionXlarge.Middle)
SignStreet

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.SignStreet.Image, frames.SignStreet.Middle)
SignStreetLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.SignStreetLarge.Image, frames.SignStreetLarge.Middle)
SignStreetXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.SignStreetXlarge.Image, frames.SignStreetXlarge.Middle)
SignWarning

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.SignWarning.Image, frames.SignWarning.Middle)
SignWarningLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.SignWarningLarge.Image, frames.SignWarningLarge.Middle)
SignWarningXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.SignWarningXlarge.Image, frames.SignWarningXlarge.Middle)
Waves

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Waves.Image, frames.Waves.Middle)
WavesLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WavesLarge.Image, frames.WavesLarge.Middle)
WavesXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WavesXlarge.Image, frames.WavesXlarge.Middle)
Win31Like

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Win31Like.Image, frames.Win31Like.Middle)
Win31LikeLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Win31LikeLarge.Image, frames.Win31LikeLarge.Middle)
Win31LikeXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Win31LikeXlarge.Image, frames.Win31LikeXlarge.Middle)
Win95Like

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Win95Like.Image, frames.Win95Like.Middle)
Win95LikeLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Win95LikeLarge.Image, frames.Win95LikeLarge.Middle)
Win95LikeXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Win95LikeXlarge.Image, frames.Win95LikeXlarge.Middle)
WindowFuture

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowFuture.Image, frames.WindowFuture.Middle)
WindowFutureLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowFutureLarge.Image, frames.WindowFutureLarge.Middle)
WindowFutureXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowFutureXlarge.Image, frames.WindowFutureXlarge.Middle)
WindowGlass

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowGlass.Image, frames.WindowGlass.Middle)
WindowGlassLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowGlassLarge.Image, frames.WindowGlassLarge.Middle)
WindowGlassXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowGlassXlarge.Image, frames.WindowGlassXlarge.Middle)
WindowPaper

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowPaper.Image, frames.WindowPaper.Middle)
WindowPaperLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowPaperLarge.Image, frames.WindowPaperLarge.Middle)
WindowPaperXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowPaperXlarge.Image, frames.WindowPaperXlarge.Middle)
WindowRetro

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowRetro.Image, frames.WindowRetro.Middle)
WindowRetroLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowRetroLarge.Image, frames.WindowRetroLarge.Middle)
WindowRetroXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WindowRetroXlarge.Image, frames.WindowRetroXlarge.Middle)
Wood

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.Wood.Image, frames.Wood.Middle)
WoodLarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WoodLarge.Image, frames.WoodLarge.Middle)
WoodXlarge

import "github.com/arran4/golang-frame/frames"
// Use it directly
fr := frame.NewFrame(destRect, frames.WoodXlarge.Image, frames.WoodXlarge.Middle)