Author Topic: Scale and Rotate Text Strings  (Read 3941 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Scale and Rotate Text Strings
« on: March 17, 2019, 07:18:23 pm »
Here's one for your toolbox.

Code: QB64: [Select]
  1. _TITLE "Scale and rotate (default font) text strings." 'B+ started 2019-03-17
  2.  
  3. ' The following CONSTants or TYPES are for the demo and NOT needed for the 2 main subs
  4.  
  5. CONST xmax = 1200
  6. CONST ymax = 700
  7. CONST x0 = 600
  8. CONST y0 = 350
  9. CONST radius = 240
  10. CONST r2 = 20
  11.  
  12. TYPE vectorType
  13.     x AS SINGLE
  14.     y AS SINGLE
  15.  
  16. SCREEN _NEWIMAGE(xmax, ymax, 32)
  17. _SCREENMOVE 100, 40
  18.  
  19.  
  20. a = 1: dir = 1: dir2 = 1
  21. ca = _PI(2 / 20)
  22. DIM vdigit(0 TO 19) AS vectorType
  23. DIM outer(0 TO 19) AS vectorType
  24. FOR i = 0 TO 19
  25.     vdigit(i).x = x0 + radius * COS(ca * i - 4.5 * ca)
  26.     vdigit(i).y = y0 + radius * SIN(ca * i - 4.5 * ca)
  27. t$ = "Scale and rotate text strings"
  28. WHILE _KEYDOWN(27) = 0
  29.     CLS
  30.  
  31.     'this demos putting double sized numbers around a circle angled so the circle is the bottom of number
  32.     CIRCLE (x0, y0), radius
  33.     FOR i = 0 TO 19
  34.         CIRCLE (vdigit(i).x, vdigit(i).y), 2
  35.         x = x0 + (radius + 18) * COS(ca * i - 4.5 * ca)
  36.         y = y0 + (radius + 18) * SIN(ca * i - 4.5 * ca)
  37.         drwString LTRIM$(STR$(i)), &HFFFFFFFF, x, y, 2, 2, ca * i - 4.5 * ca + _PI(.5)
  38.     NEXT
  39.  
  40.     'this demos stretching and shrinking the xScale while the text string is turned + and - Pi/2 or 90 degrees
  41.     'left side red
  42.     drwString t$, &HFF552200, 300, ymax / 2, 50 * ABS(rot), 3, _PI(-.5)
  43.     'right side green
  44.     drwString t$, &HFF004400, xmax - 300, ymax / 2, 50 * ABS(rot), 3, _PI(.5)
  45.  
  46.     'this demos rotaing a text string about the x axis at 3 times default font scale, rot range -1 to 1
  47.     drwString t$, &HFF0000FF, xmax / 2, 32, 3, 3 * rot, 0
  48.  
  49.     'this demos rotaing a text string about the y axis at 3 times default font scale, rot range -1 to 1
  50.     drwString t$, &HFF00FF00, xmax / 2, ymax - 32, 3 * rot, 3, 0
  51.  
  52.     'this demos rotating a text string from 0 to 2 Pi radians and reverse 0 to -2 Pi
  53.     'and shrinking both the xScale and yScale at same time and amount
  54.     drwString t$, &HFFFF0000, xmax / 2, ymax / 2, ABS(rot) * 4, ABS(rot) * 4, a
  55.  
  56.     rot = rot + .1 * dir
  57.     IF rot > 1 THEN dir = -dir: rot = .9
  58.     IF rot < -1 THEN dir = -dir: rot = -.9
  59.     a = a + _PI(1 / 45) * dir2
  60.     IF a > _PI(2) THEN dir2 = -dir2: a = _PI(2)
  61.     IF a < _PI(-2) THEN dir2 = -dir2: a = _PI(-2)
  62.  
  63.     _DISPLAY
  64.     _LIMIT 10
  65.  
  66. 'drwString needs sub RotoZoom2, intended for graphics screens using the default font.
  67. 'S$ is the string to display
  68. 'c is the color (will have a transparent background)
  69. 'midX and midY is the center of where you want to display the string
  70. 'xScale would multiply 8 pixel width of default font
  71. 'yScale would multiply the 16 pixel height of the default font
  72. 'Rotation is in Radian units, use _D2R to convert Degree units to Radian units
  73. SUB drwString (S$, c AS _UNSIGNED LONG, midX, midY, xScale, yScale, Rotation)
  74.     I& = _NEWIMAGE(8 * LEN(S$), 16, 32)
  75.     _DEST I&
  76.     COLOR c, _RGBA32(0, 0, 0, 0)
  77.     _PRINTSTRING (0, 0), S$
  78.     _DEST 0
  79.     RotoZoom2 midX, midY, I&, xScale, yScale, Rotation
  80.     _FREEIMAGE I&
  81.  
  82. 'This sub gives really nice control over displaying an Image.
  83. SUB RotoZoom2 (centerX AS LONG, centerY AS LONG, Image AS LONG, xScale AS SINGLE, yScale AS SINGLE, Rotation AS SINGLE)
  84.     DIM px(3) AS SINGLE: DIM py(3) AS SINGLE
  85.     W& = _WIDTH(Image&): H& = _HEIGHT(Image&)
  86.     px(0) = -W& / 2: py(0) = -H& / 2: px(1) = -W& / 2: py(1) = H& / 2
  87.     px(2) = W& / 2: py(2) = H& / 2: px(3) = W& / 2: py(3) = -H& / 2
  88.     sinr! = SIN(-Rotation): cosr! = COS(-Rotation)
  89.     FOR i& = 0 TO 3
  90.         x2& = (px(i&) * cosr! + sinr! * py(i&)) * xScale + centerX: y2& = (py(i&) * cosr! - px(i&) * sinr!) * yScale + centerY
  91.         px(i&) = x2&: py(i&) = y2&
  92.     NEXT
  93.     _MAPTRIANGLE (0, 0)-(0, H& - 1)-(W& - 1, H& - 1), Image& TO(px(0), py(0))-(px(1), py(1))-(px(2), py(2))
  94.     _MAPTRIANGLE (0, 0)-(W& - 1, 0)-(W& - 1, H& - 1), Image& TO(px(0), py(0))-(px(3), py(3))-(px(2), py(2))
  95.  
  96.  
« Last Edit: March 18, 2019, 12:01:34 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Scale and Rotate Text Strings
« Reply #1 on: March 18, 2019, 12:06:26 pm »
I have updated the code in the original post with more comments, descriptive variable names... in attempts to make it easier to pickup and use the 2 main subroutines. I had forgotten to mention, drwString works with default font in a graphics screen.
A font that is 8x16 pixels should also work.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Scale and Rotate Text Strings
« Reply #2 on: March 18, 2019, 05:13:13 pm »
Here I have created a 16x16 Font from the default 8x16 with the help of the subs featured above and then some subs that function the same as PRINT, LOCATE and INPUT, their name is same with f prefix. So you could use the 16x16 font as you would the default 8x16 for locating and printing on the screen.

Code: QB64: [Select]
  1. _TITLE "Font procedures using default font squared 16x16" 'b+ started 2019-03-18
  2. 'from font procedures originally written to handle different fonts
  3. '2018-09-03 started to duplicate subs I used to do large printing with Print, Locate, Input
  4. '2018-09-04 post testing different fonts
  5.  
  6. ' 2019-03-18 test with print double wide default font
  7.  
  8. SCREEN _NEWIMAGE(800, 600, 32)
  9. _SCREENMOVE (1280 - _WIDTH) / 2 + 30, (760 - _HEIGHT) / 2
  10.  
  11. DIM SHARED curCol AS INTEGER, curRow AS INTEGER, CW AS INTEGER, CH AS INTEGER, MAXCOL AS INTEGER, MAXROW AS INTEGER
  12. CH = 16: CW = 16
  13. MAXCOL = INT(_WIDTH / CW): MAXROW = INT(_HEIGHT / CH): curCol = 1: curRow = 1
  14.  
  15.  
  16. fLP 1, 1, "max (row, col) = (" + LTRIM$(STR$(MAXCOL)) + "," + LTRIM$(STR$(MAXROW)) + ")"
  17. fPRINT "     ;"
  18. fPRINT "max (row, col) = (" + LTRIM$(STR$(MAXCOL)) + "," + LTRIM$(STR$(MAXROW)) + ")"
  19. fPRINT "This is another row."
  20. fLOCATE 10, 10
  21. fPRINT "This is a located (10, 10) print line."
  22. FOR i = 4 TO 10
  23.     IF i = 9 THEN 'can't print over an area and deleted its
  24.         FOR j = 1 TO MAXCOL
  25.             fPRINT RIGHT$(STR$(j), 1) + ";"
  26.         NEXT
  27.     END IF
  28.     fLOCATE i, 1: fPRINT LTRIM$(STR$(i))
  29. fCP "Center this text in the line."
  30. fPRINT "This follows the centered text on the next line."
  31. COLOR _RGB32(0, 0, 128), _RGB32(200, 200, 255)
  32. fCP "How about some color?"
  33. COLOR _RGB32(200, 200, 0), _RGB32(0, 0, 0)
  34. fINPUT "Can you answer y for yes or n for no ?", ans$
  35. fPRINT "Ah! you answered, *" + ans$ + "*"
  36. fLOCATE MAXROW, MAXCOL
  37. fPRINT "B" + ";"
  38. fLOCATE 25, 1
  39. COLOR _RGB32(255, 0, 0)
  40. fPRINT "Let's try fPRINT with a string that won't fit on one line, what will it do?"
  41. fPRINT "And how does fPRINT handle the next line?"
  42. fLOCATE 35, 1
  43. COLOR _RGB32(0, 128, 0)
  44. fCP "This is a demo of a 16x16 pixel font"
  45. fCP " created from the default 8x16 font."
  46.  
  47. 'the f for font subs
  48. SUB fLOCATE (row, col) 'locate xColumnCell, yRowCell for printing
  49.     IF 0 < col AND col <= MAXCOL AND 0 < row AND row <= MAXROW THEN
  50.         curCol = col: curRow = row
  51.     ELSE
  52.         BEEP
  53.     END IF
  54.  
  55. 'font Print should work same as PRINT for default font, nope lines too long are dropped
  56. SUB fPRINT (s$) 'print line (feed)
  57.     IF RIGHT$(s$, 1) = ";" THEN LFTF = 0: mess$ = LEFT$(s$, LEN(s$) - 1) ELSE LFTF = -1: mess$ = s$
  58.     IF curCol + LEN(mess$) > MAXCOL + 1 THEN
  59.         WHILE curCol + LEN(mess$) > MAXCOL + 1
  60.             diff = curCol + LEN(mess$) - (MAXCOL + 1)
  61.             printString (curCol - 1) * CW, (curRow - 1) * CH, MID$(mess$, 1, LEN(mess$) - diff)
  62.             curCol = 1
  63.             curRow = curRow + 1
  64.             mess$ = MID$(mess$, LEN(mess$) - diff + 1)
  65.         WEND
  66.         printString (curCol - 1) * CW, (curRow - 1) * CH, mess$
  67.     ELSE
  68.         printString (curCol - 1) * CW, (curRow - 1) * CH, mess$
  69.     END IF
  70.     IF LFTF THEN
  71.         curCol = 1
  72.         curRow = curRow + 1
  73.         IF curRow > MAXROW THEN curRow = MAXROW 'yuck!
  74.     ELSE
  75.         curCol = curCol + LEN(mess$)
  76.     END IF
  77.  
  78. 'font Locate and Print
  79. SUB fLP (row, col, mess$) 'locate x, y : print mess$ lp = locate and print assume LF
  80.     'if locate = x col and y row then and top left corner locates as 1, 1
  81.     IF 0 < col AND col <= MAXCOL AND 0 < row AND row <= MAXROW THEN
  82.         printString (col - 1) * CW, (row - 1) * CH, mess$
  83.         curCol = 1
  84.         curRow = curRow + 1
  85.         IF curRow > MAXROW THEN curRow = MAXROW 'yuck!
  86.     END IF
  87.  
  88. 'font Center Print
  89. SUB fCP (s$) 'cp Center Print on line y the cpText$
  90.     col = (MAXCOL - LEN(s$)) / 2
  91.     fLP curRow, col, s$
  92.  
  93. SUB fINPUT (prompt$, var$) 'input
  94.     DIM pRow AS INTEGER, pCol AS INTEGER, done AS _BYTE
  95.     'save current location
  96.     pRow = curRow: pCol = curCol 'save these for redrawing var
  97.     fLOCATE pRow, pCol
  98.     fPRINT prompt$ + " {} ;"
  99.     OK$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"
  100.     OK$ = OK$ + CHR$(8) + CHR$(27) + CHR$(13) + "1234567890!@#$%^&*()_-+={}[]|\:;'<,>.?/"
  101.     DO
  102.         k$ = INKEY$
  103.         IF INSTR(OK$, k$) THEN
  104.             IF k$ = CHR$(8) THEN
  105.                 IF t$ <> "" THEN
  106.                     IF LEN(t$) = 1 THEN t$ = "" ELSE t$ = LEFT$(t$, LEN(t$) - 1)
  107.                 END IF
  108.             ELSE
  109.                 IF k$ = CHR$(13) OR k$ = CHR$(27) THEN
  110.                     IF k$ = CHR$(27) THEN t$ = ""
  111.                     EXIT DO
  112.                 ELSE
  113.                     t$ = t$ + k$
  114.                 END IF
  115.             END IF
  116.             fLOCATE pRow, pCol
  117.             LINE (pCol * CW - CW, (pRow - 1) * CH)-(MAXCOL * CW, pRow * CH), _BACKGROUNDCOLOR, BF
  118.             fPRINT prompt$ + " {" + t$ + "} ;"
  119.             k$ = ""
  120.         END IF
  121.         _DISPLAY
  122.         _LIMIT 60
  123.     LOOP UNTIL done
  124.     curCol = 1: curRow = pRow + 1 'update the next print location
  125.     var$ = t$ 'return the sub's var$ with desired entered or escape string.
  126.  
  127. SUB printString (x, y, mess$) 'convert printstring to drwString
  128.     midX = x + (LEN(mess$) * CW) / 2
  129.     midY = y + 8
  130.     drwString mess$, _DEFAULTCOLOR, midX, midY, 2, 1, 0
  131.  
  132.  
  133. 'drwString needs sub RotoZoom2, intended for graphics screens using the default font.
  134. 'S$ is the string to display
  135. 'c is the color (will have a transparent background)
  136. 'midX and midY is the center of where you want to display the string
  137. 'xScale would multiply 8 pixel width of default font
  138. 'yScale would multiply the 16 pixel height of the default font
  139. 'Rotation is in Radian units, use _D2R to convert Degree units to Radian units
  140. SUB drwString (S$, c AS _UNSIGNED LONG, midX, midY, xScale, yScale, Rotation)
  141.     I& = _NEWIMAGE(8 * LEN(S$), 16, 32)
  142.     _DEST I&
  143.     COLOR c
  144.     _PRINTSTRING (0, 0), S$
  145.     _DEST 0
  146.     RotoZoom2 midX, midY, I&, xScale, yScale, Rotation
  147.     _FREEIMAGE I&
  148.  
  149. 'This sub gives really nice control over displaying an Image.
  150. SUB RotoZoom2 (centerX AS LONG, centerY AS LONG, Image AS LONG, xScale AS SINGLE, yScale AS SINGLE, Rotation AS SINGLE)
  151.     DIM px(3) AS SINGLE: DIM py(3) AS SINGLE
  152.     W& = _WIDTH(Image&): H& = _HEIGHT(Image&)
  153.     px(0) = -W& / 2: py(0) = -H& / 2: px(1) = -W& / 2: py(1) = H& / 2
  154.     px(2) = W& / 2: py(2) = H& / 2: px(3) = W& / 2: py(3) = -H& / 2
  155.     sinr! = SIN(-Rotation): cosr! = COS(-Rotation)
  156.     FOR i& = 0 TO 3
  157.         x2& = (px(i&) * cosr! + sinr! * py(i&)) * xScale + centerX: y2& = (py(i&) * cosr! - px(i&) * sinr!) * yScale + centerY
  158.         px(i&) = x2&: py(i&) = y2&
  159.     NEXT
  160.     _MAPTRIANGLE (0, 0)-(0, H& - 1)-(W& - 1, H& - 1), Image& TO(px(0), py(0))-(px(1), py(1))-(px(2), py(2))
  161.     _MAPTRIANGLE (0, 0)-(W& - 1, 0)-(W& - 1, H& - 1), Image& TO(px(0), py(0))-(px(3), py(3))-(px(2), py(2))
  162.  
  163.  
16x16 font created from 8x16.PNG


Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Scale and Rotate Text Strings
« Reply #3 on: March 18, 2019, 05:57:36 pm »
Here's how I generally scale and rotate text:

Code: QB64: [Select]
  1. DIM TI(4) AS LONG
  2.  
  3. SCREEN _NEWIMAGE(800, 600, 32)
  4. FOR i = 1 TO 4
  5.     TI(i) = TextToImage("Here's some text for you.", 16, &HFFFF0000, 0, i)
  6.     'print forward, backward, up to down, down to up
  7. DisplayImage TI(1), 100, 100, 0, 1
  8. DisplayImage TI(2), 100, 510, 0, 1
  9. DisplayImage TI(3), 100, 110, 0, 1
  10. DisplayImage TI(4), 300, 110, 0, 1
  11.  
  12. a$ = INPUT$(1)
  13.  
  14. 'And now to scale these fonts
  15.  
  16. Scaled1 = ScaleImage(TI(1), 2, 2) 'double width, double height
  17. DisplayImage Scaled1, 100, 100, 0, 1
  18. Scaled2 = ScaleImage(TI(1), 2, 1) 'double width, normal height
  19. DisplayImage Scaled2, 100, 150, 0, 1
  20. Scaled3 = ScaleImage(TI(1), 1, 2) 'normal width, double height
  21. DisplayImage Scaled3, 100, 200, 0, 1
  22. Scaled4 = ScaleImage(TI(1), 1.5, 1.5) '1.5 times as  wide, 1.5 times as high
  23. DisplayImage Scaled4, 100, 250, -45, 1 'rotated at -45 degrees
  24.  
  25. a$ = INPUT$(1)
  26.     _LIMIT 60
  27.     CLS
  28.     DisplayImage Scaled4, 400, 300, angle, 0 'and just to show how we can rotate with the displayimage routine
  29.     angle = angle - 3
  30.     _DISPLAY
  31. LOOP UNTIL _KEYDOWN(27) 'ESC to end
  32.  
  33.  
  34.  
  35.  
  36.  
  37. SUB DisplayImage (Image AS LONG, x AS INTEGER, y AS INTEGER, angle AS SINGLE, mode AS _BYTE)
  38.     'Image is the image handle which we use to reference our image.
  39.     'x,y is the X/Y coordinates where we want the image to be at on the screen.
  40.     'angle is the angle which we wish to rotate the image.
  41.     'mode determines HOW we place the image at point X,Y.
  42.     'Mode 0 we center the image at point X,Y
  43.     'Mode 1 we place the Top Left corner of oour image at point X,Y
  44.     'Mode 2 is Bottom Left
  45.     'Mode 3 is Top Right
  46.     'Mode 4 is Bottom Right
  47.  
  48.  
  49.     DIM px(3) AS INTEGER, py(3) AS INTEGER, w AS INTEGER, h AS INTEGER
  50.     DIM sinr AS SINGLE, cosr AS SINGLE, i AS _BYTE
  51.     w = _WIDTH(Image): h = _HEIGHT(Image)
  52.     SELECT CASE mode
  53.         CASE 0 'center
  54.             px(0) = -w \ 2: py(0) = -h \ 2: px(3) = w \ 2: py(3) = -h \ 2
  55.             px(1) = -w \ 2: py(1) = h \ 2: px(2) = w \ 2: py(2) = h \ 2
  56.         CASE 1 'top left
  57.             px(0) = 0: py(0) = 0: px(3) = w: py(3) = 0
  58.             px(1) = 0: py(1) = h: px(2) = w: py(2) = h
  59.         CASE 2 'bottom left
  60.             px(0) = 0: py(0) = -h: px(3) = w: py(3) = -h
  61.             px(1) = 0: py(1) = 0: px(2) = w: py(2) = 0
  62.         CASE 3 'top right
  63.             px(0) = -w: py(0) = 0: px(3) = 0: py(3) = 0
  64.             px(1) = -w: py(1) = h: px(2) = 0: py(2) = h
  65.         CASE 4 'bottom right
  66.             px(0) = -w: py(0) = -h: px(3) = 0: py(3) = -h
  67.             px(1) = -w: py(1) = 0: px(2) = 0: py(2) = 0
  68.     END SELECT
  69.     sinr = SIN(angle / 57.2957795131): cosr = COS(angle / 57.2957795131)
  70.     FOR i = 0 TO 3
  71.         x2 = (px(i) * cosr + sinr * py(i)) + x: y2 = (py(i) * cosr - px(i) * sinr) + y
  72.         px(i) = x2: py(i) = y2
  73.     NEXT
  74.     _MAPTRIANGLE (0, 0)-(0, h - 1)-(w - 1, h - 1), Image TO(px(0), py(0))-(px(1), py(1))-(px(2), py(2))
  75.     _MAPTRIANGLE (0, 0)-(w - 1, 0)-(w - 1, h - 1), Image TO(px(0), py(0))-(px(3), py(3))-(px(2), py(2))
  76.  
  77. FUNCTION TextToImage& (text$, font&, fc&, bfc&, mode AS _BYTE)
  78.     'text$ is the text that we wish to transform into an image.
  79.     'font& is the handle of the font we want to use.
  80.     'fc& is the color of the font we want to use.
  81.     'bfc& is the background color of the font.
  82.  
  83.     'Mode 1 is print forwards
  84.     'Mode 2 is print backwards
  85.     'Mode 3 is print from top to bottom
  86.     'Mode 4 is print from bottom up
  87.     'Mode 0 got lost somewhere, but it's OK.  We check to see if our mode is < 1 or > 4 and compensate automatically if it is to make it one (default).
  88.  
  89.     IF mode < 1 OR mode > 4 THEN mode = 1
  90.     dc& = _DEFAULTCOLOR: bgc& = _BACKGROUNDCOLOR
  91.     D = _DEST
  92.     F = _FONT
  93.     IF font& <> 0 THEN _FONT font&
  94.     IF mode < 3 THEN
  95.         'print the text lengthwise
  96.         w& = _PRINTWIDTH(text$): h& = _FONTHEIGHT
  97.     ELSE
  98.         'print the text vertically
  99.         FOR i = 1 TO LEN(text$)
  100.             IF w& < _PRINTWIDTH(MID$(text$, i, 1)) THEN w& = _PRINTWIDTH(MID$(text$, i, 1))
  101.         NEXT
  102.         h& = _FONTHEIGHT * (LEN(text$))
  103.     END IF
  104.  
  105.     TextToImage& = _NEWIMAGE(w&, h&, 32)
  106.     _DEST TextToImage&
  107.     IF font& <> 0 THEN _FONT font&
  108.     COLOR fc&, bfc&
  109.  
  110.     SELECT CASE mode
  111.         CASE 1
  112.             'Print text forward
  113.             _PRINTSTRING (0, 0), text$
  114.         CASE 2
  115.             'Print text backwards
  116.             temp$ = ""
  117.             FOR i = 0 TO LEN(text$) - 1
  118.                 temp$ = temp$ + MID$(text$, LEN(text$) - i, 1)
  119.             NEXT
  120.             _PRINTSTRING (0, 0), temp$
  121.         CASE 3
  122.             'Print text upwards
  123.             'first lets reverse the text, so it's easy to place
  124.             temp$ = ""
  125.             FOR i = 0 TO LEN(text$) - 1
  126.                 temp$ = temp$ + MID$(text$, LEN(text$) - i, 1)
  127.             NEXT
  128.             'then put it where it belongs
  129.             FOR i = 1 TO LEN(text$)
  130.                 fx = (w& - _PRINTWIDTH(MID$(temp$, i, 1))) / 2 + .99 'This is to center any non-monospaced letters so they look better
  131.                 _PRINTSTRING (fx, _FONTHEIGHT * (i - 1)), MID$(temp$, i, 1)
  132.             NEXT
  133.         CASE 4
  134.             'Print text downwards
  135.             FOR i = 1 TO LEN(text$)
  136.                 fx = (w& - _PRINTWIDTH(MID$(text$, i, 1))) / 2 + .99 'This is to center any non-monospaced letters so they look better
  137.                 _PRINTSTRING (fx, _FONTHEIGHT * (i - 1)), MID$(text$, i, 1)
  138.             NEXT
  139.     END SELECT
  140.     _DEST D
  141.     COLOR dc&, bgc&
  142.     _FONT F
  143.  
  144. FUNCTION TextArrayToImage& (text() AS STRING, font&, fc&, bfc&, mode AS _BYTE)
  145.     'text is the text array that we wish to transform into an image.
  146.     'text(0) tells us how many lines of text we wish to use.
  147.     'font& is the handle of the font we want to use.
  148.     'fc& is the color of the font we want to use.
  149.     'bfc& is the background color of the font.
  150.  
  151.     'Mode 1 is print forwards
  152.     'Mode 2 is print backwards
  153.     'Mode 3 is print from top to bottom
  154.     'Mode 4 is print from bottom up
  155.     'Mode 0 got lost somewhere, but it's OK.  We check to see if our mode is < 1 or > 4 and compensate automatically if it is to make it one (default).
  156.  
  157.     NumberOfLines = VAL(text(0))
  158.  
  159.     IF mode < 1 OR mode > 4 THEN mode = 1
  160.     dc& = _DEFAULTCOLOR: bgc& = _BACKGROUNDCOLOR
  161.     D = _DEST
  162.     F = _FONT
  163.     IF font& <> 0 THEN _FONT font&
  164.     IF mode < 3 THEN
  165.         'print the text lengthwise
  166.         FOR i = 1 TO NumberOfLines
  167.             IF _PRINTWIDTH(text(i)) > w& THEN w& = _PRINTWIDTH(text(i))
  168.         NEXT
  169.         h& = _FONTHEIGHT
  170.         TextArrayToImage& = _NEWIMAGE(w&, h& * NumberOfLines, 32)
  171.     ELSE
  172.         'print the text vertically
  173.         FOR j = 1 TO NumberOfLines
  174.             IF LEN(text(j)) > longestline THEN longestline = LEN(text(j))
  175.             FOR i = 1 TO LEN(text(j))
  176.                 IF w& < _PRINTWIDTH(MID$(text(j), i, 1)) THEN w& = _PRINTWIDTH(MID$(text(j), i, 1))
  177.             NEXT
  178.         NEXT
  179.         h& = _FONTHEIGHT
  180.         TextArrayToImage& = _NEWIMAGE(w& * NumberOfLines, h& * longestline, 32)
  181.     END IF
  182.  
  183.     _DEST TextArrayToImage&
  184.     IF font& <> 0 THEN _FONT font&
  185.     COLOR fc&, bfc&
  186.  
  187.  
  188.     FOR i = 0 TO NumberOfLines - 1
  189.         SELECT CASE mode
  190.             CASE 1
  191.                 'Print text forward
  192.                 _PRINTSTRING (0, i * h&), text(i + 1)
  193.             CASE 2
  194.                 'Print text backwards
  195.                 temp$ = ""
  196.                 FOR j = 0 TO LEN(text(i + 1)) - 1
  197.                     temp$ = temp$ + MID$(text(i + 1), LEN(text(i + 1)) - j, 1)
  198.                 NEXT
  199.                 _PRINTSTRING (0, i * h&), temp$
  200.             CASE 3
  201.                 'Print text upwards
  202.                 'first lets reverse the text, so it's easy to place
  203.                 temp$ = ""
  204.                 FOR j = 0 TO LEN(text(i + 1)) - 1
  205.                     temp$ = temp$ + MID$(text(i + 1), LEN(text(i + 1)) - j, 1)
  206.                 NEXT
  207.                 'then put it where it belongs
  208.                 FOR j = 1 TO LEN(text(i + 1))
  209.                     fx = (w& - _PRINTWIDTH(MID$(temp$, j, 1))) / 2 + .99 'This is to center any non-monospaced letters so they look better
  210.                     _PRINTSTRING (fx + w& * i, _FONTHEIGHT * (j - 1)), MID$(temp$, j, 1)
  211.                 NEXT
  212.             CASE 4
  213.                 'Print text downwards
  214.                 FOR j = 1 TO LEN(text(i + 1))
  215.                     fx = (w& - _PRINTWIDTH(MID$(text(i + 1), j, 1))) / 2 + .99 'This is to center any non-monospaced letters so they look better
  216.                     _PRINTSTRING (fx + w& * i, _FONTHEIGHT * (j - 1)), MID$(text(i + 1), j, 1)
  217.                 NEXT
  218.         END SELECT
  219.     NEXT
  220.     _DEST D
  221.     COLOR dc&, bgc&
  222.     _FONT F
  223.  
  224. FUNCTION ScaleImage& (Image AS LONG, xscale AS SINGLE, yscale AS SINGLE)
  225.     w = _WIDTH(Image): h = _HEIGHT(Image)
  226.     w2 = w * xscale: h2 = h * yscale
  227.     NewImage& = _NEWIMAGE(w2, h2, 32)
  228.     _PUTIMAGE , Image&, NewImage&
  229.     ScaleImage& = NewImage&
  230.  

Print text forward, backwards, up to down, down to up.  Rotate it to display at any angle.  Scale it to any size.  In Steve's Extended Toolset, you'll also see functions which work with arrays of text for moving/scaling whole blocks of text at once as needed, along with several other text related subs and functions.  ;)

And, for an even more flexible way to handle things, check out the print replacement routines which I have over at the other forums: http://qb64.freeforums.net/thread/37/custom-routines-supports-textures-shading

Print with or without wordwrap.  On the same line, or across multiple lines.  Use textures or patterns to color the text...  And it's *FASTER* than QB64's native PRINT routines... 

Put the two routines together and then PrintOut to a new image like TextToImage does, and then ScaleImage and DisplayImage all sorts of fancy looking text in various ways, angles, shades, and custom colors... 

The sky's the limit!

https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Scale and Rotate Text Strings
« Reply #4 on: March 18, 2019, 08:00:56 pm »
Thanks Steve, the textures shading sounds interesting.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Scale and Rotate Text Strings
« Reply #5 on: March 18, 2019, 08:47:50 pm »
Also take a moment to compare RotoZoom to DisplayImage.  They’re both very similar routines, with the exception that DisplayImage has a mode option which allows you to choose which corner you want to place at your X/Y coordinate.  Often, I find myself swapping between the use of centering an image at a particular point, and needing to place the top left corner at that point.  DisplayImage toggles easily between both.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Scale and Rotate Text Strings
« Reply #6 on: March 19, 2019, 10:30:21 am »
Well Steve you have me thinking about adding textures to text. I think I have a way but likely too slow to be practical?
I like to try something my way, if I can, before learning the right way. ;)

BTW with my system you don't need a separate mode for verticals use +-Pi/2 or +-3/2*Pi for rotation and use neg scales for mirror images. You don't even have to be expert in Radian angle measures, just convert Degrees with _D2R(degree angle)

For me, the #1 reason I have to load a separate font is to get larger or smaller font sizes. With these 2 little subs I provide (around 20 lines of actual code), you don't have to load a separate font file, you can just use the default. That saves having to .zip the code into a package to share with others who may not have Windows font files. PLUS as a bonus you can Rotate text!

Not bad for around 20 lines of actual code.

Also for converting Top, Left corner to the centerX, centerY for using the 2 little subs I used this wrapper sub in the 2nd code demo I provided. It takes normal _PRINTSTRING arguments and convert to centerX, centerY and calls drwString for the 16x16 font.
Code: QB64: [Select]
  1. SUB printString (x, y, mess$) 'convert printstring to drwString
  2.     midX = x + (LEN(mess$) * CW) / 2  'CW is Character Width DIM SHARED
  3.     midY = y + 8  
  4.     drwString mess$, _DEFAULTCOLOR, midX, midY, 2, 1, 0
  5.  
  6.