Skip to content

Commit 941aa68

Browse files
authored
Merge pull request #2062 from fschade/fix-issue-1452-respect-canvas-boundaries
fix(thumbnailer): respect image boundaries and text wrappings
2 parents 19a8ff3 + 01b768d commit 941aa68

File tree

1 file changed

+54
-35
lines changed

1 file changed

+54
-35
lines changed

services/thumbnails/pkg/preprocessor/preprocessor.go

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"golang.org/x/image/math/fixed"
2121

2222
"github.com/dhowden/tag"
23+
2324
thumbnailerErrors "github.com/opencloud-eu/opencloud/services/thumbnails/pkg/errors"
2425
)
2526

@@ -156,15 +157,18 @@ Scan: // Label for the scanner loop, so we can break it easily
156157
if canvas.Dot.Y > maxY {
157158
break Scan
158159
}
159-
drawWord(canvas, textResult.Text[initialByte:sRangeSpace], minX, maxX, height, maxY, true)
160+
161+
drawWord(canvas, textResult.Text[initialByte:sRangeSpace], minX, maxX, height, maxY)
160162
initialByte = sRangeSpace
161163
}
164+
162165
if initialByte <= sRange.High {
163166
// some bytes left to be written
164167
if canvas.Dot.Y > maxY {
165168
break Scan
166169
}
167-
drawWord(canvas, textResult.Text[initialByte:sRange.High+1], minX, maxX, height, maxY, len(sRange.Spaces) > 0)
170+
171+
drawWord(canvas, textResult.Text[initialByte:sRange.High+1], minX, maxX, height, maxY)
168172
}
169173
}
170174

@@ -235,43 +239,58 @@ func extractBase64ImageFromGGP(ggp *GGPStruct) (string, error) {
235239
// need to draw the word in a new line
236240
//
237241
// Note that the word will likely start with a white space char
238-
func drawWord(canvas *font.Drawer, word string, minX, maxX, incY, maxY fixed.Int26_6, goToNewLine bool) {
239-
bbox, _ := canvas.BoundString(word)
240-
if bbox.Max.X <= maxX {
241-
// word fits in the current line
242+
func drawWord(canvas *font.Drawer, word string, minX, maxX, incY, maxY fixed.Int26_6) {
243+
// calculate the actual measurement of the string at a given X position
244+
measure := func(s string, dotX fixed.Int26_6) (min, max fixed.Int26_6) {
245+
bbox, _ := canvas.BoundString(s)
246+
return dotX + bbox.Min.X, dotX + bbox.Max.X
247+
}
248+
249+
// first try to draw the whole word
250+
absMin, absMax := measure(word, canvas.Dot.X)
251+
if absMin >= minX && absMax <= maxX {
242252
canvas.DrawString(word)
243-
} else {
244-
// word doesn't fit -> retry in a new line
245-
trimmedWord := strings.TrimSpace(word)
246-
oldDot := canvas.Dot
253+
return
254+
}
247255

248-
canvas.Dot.X = minX
249-
canvas.Dot.Y += incY
250-
bbox2, _ := canvas.BoundString(trimmedWord)
251-
if goToNewLine && bbox2.Max.X <= maxX {
252-
if canvas.Dot.Y > maxY {
253-
// Don't draw if we're over the Y limit
254-
return
255-
}
256-
canvas.DrawString(trimmedWord)
257-
} else {
258-
// word doesn't fit in a new line -> draw as many chars as possible
259-
canvas.Dot = oldDot
260-
for _, char := range trimmedWord {
261-
charBytes := []byte(string(char))
262-
bbox3, _ := canvas.BoundBytes(charBytes)
263-
if bbox3.Max.X > maxX {
264-
canvas.Dot.X = minX
265-
canvas.Dot.Y += incY
266-
if canvas.Dot.Y > maxY {
267-
// Don't draw if we're over the Y limit
268-
return
269-
}
270-
}
271-
canvas.DrawBytes(charBytes)
272-
}
256+
// try to draw the trimmed word in a new line
257+
trimmed := strings.TrimSpace(word)
258+
oldDot := canvas.Dot
259+
canvas.Dot.X = minX
260+
canvas.Dot.Y += incY
261+
262+
if canvas.Dot.Y <= maxY {
263+
tMin, tMax := measure(trimmed, canvas.Dot.X)
264+
if tMin >= minX && tMax <= maxX {
265+
canvas.DrawString(trimmed)
266+
return
273267
}
274268
}
269+
270+
// if the trimmed word is still too big, draw it char by char
271+
canvas.Dot = oldDot
272+
for _, char := range trimmed {
273+
s := string(char)
274+
_, cMax := measure(s, canvas.Dot.X)
275+
276+
if cMax > maxX {
277+
canvas.Dot.X = minX
278+
canvas.Dot.Y += incY
279+
}
280+
281+
// stop drawing if we exceed maxY
282+
if canvas.Dot.Y > maxY {
283+
return
284+
}
285+
286+
// ensure that we don't start drawing before minX
287+
cMin, _ := measure(s, canvas.Dot.X)
288+
if cMin < minX {
289+
canvas.Dot.X += minX - cMin
290+
}
291+
292+
canvas.DrawString(s)
293+
}
275294
}
276295

277296
// ForType returns the converter for the specified mimeType

0 commit comments

Comments
 (0)