## MS Paint: rotate by scaling/shearing (stretching/skewing)

Post your working scripts, libraries and tools
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

### MS Paint: rotate by scaling/shearing (stretching/skewing)

Here is a script to rotate by an arbitrary angle in MS Paint.

It is based on this video by IronMortality:
Rotate an acute angle in MS Paint - YouTube

The script has been tested on MS Paint (Windows XP and Windows 7 versions).

Code: Select all

``````;==================================================

;MS Paint: rotate by scaling/shearing (stretching/skewing)
;tested on MS Paint (Windows XP version)
;tested on MS Paint (Windows 7 version)

;2 approaches are available, use q or w to trigger

;==================================================

;NOTES: DEFINITION

;Transformation matrix - Wikipedia
;https://en.wikipedia.org/wiki/Transformation_matrix#Examples_in_2D_computer_graphics
;Rotation matrix - Wikipedia
;https://en.wikipedia.org/wiki/Rotation_matrix

;anticlockwise rotation:
;R = [cos(x), -sin(x)]
;    [sin(x),  cos(x)]

;clockwise rotation:
;R = [ cos(x), sin(x)]
;    [-sin(x), cos(x)]

;==================================================

;NOTES: APPROACH 1

;approach 1 based on:
;[demonstrated in video]
;Rotate an acute angle in MS Paint - YouTube
;IronMortality's Blog: MS Paint Rotate Notes
;http://ironmortal.blogspot.co.uk/2015/05/ms-paint-rotate-notes.html
;Step 1: Horizontal skew by 60 degrees
;Step 2: Vertical stretch by 400%
;Step 3: Vertical skew by -60 degrees
;Step 4: Horizontal and vertical stretch by 50%

;based on calculations by IronMortality:
;(note: matrix for clockwise rotation)
;R = [1, tan(x)][1/cos^2(x), 0][   1   , 0][cos(x),   0   ]
;    [0,   1   ][    0     , 1][-tan(x), 1][  0   , cos(x)]
;R = [ cos(x), sin(x)]
;    [-sin(x), cos(x)]

;simplify {{1,tan(x)},{0,1}} . {{1/cos^2(x),0},{0,1}} . {{1,0},{-tan(x),1}} . {{cos(x),0},{0,cos(x)}} - Wolfram|Alpha
;https://www.wolframalpha.com/input/?i=simplify+%7B%7B1,tan(x)%7D,%7B0,1%7D%7D+.+%7B%7B1%2Fcos%5E2(x),0%7D,%7B0,1%7D%7D+.+%7B%7B1,0%7D,%7B-tan(x),1%7D%7D+.+%7B%7Bcos(x),0%7D,%7B0,cos(x)%7D%7D
;does {{1,tan(x)},{0,1}} . {{1/cos^2(x),0},{0,1}} . {{1,0},{-tan(x),1}} . {{cos(x),0},{0,cos(x)}} = {{cos(x),sin(x)},{-sin(x),cos(x)}} - Wolfram|Alpha
;https://www.wolframalpha.com/input/?i=does+%7B%7B1,tan(x)%7D,%7B0,1%7D%7D+.+%7B%7B1%2Fcos%5E2(x),0%7D,%7B0,1%7D%7D+.+%7B%7B1,0%7D,%7B-tan(x),1%7D%7D+.+%7B%7Bcos(x),0%7D,%7B0,cos(x)%7D%7D+%3D+%7B%7Bcos(x),sin(x)%7D,%7B-sin(x),cos(x)%7D%7D

;==================================================

;NOTES: APPROACH 2

;approach 2 based on:
;[mentioned in video description]
;Rotate an acute angle in MS Paint - YouTube
;Rotation matrix - Wikipedia
;https://en.wikipedia.org/wiki/Rotation_matrix#Decomposition_into_shears
;Rotation by Shearing
;http://www.ocf.berkeley.edu/~fricke/projects/israel/paeth/rotation_by_shearing.html
;(note: original text used theta, Chr(952), not 'x')
;Step 1: Horizontal skew by x/2
;Step 2: Vertical skew by -arctan[sin[x]]
;Step 3: Horizontal skew by x/2

;based on Wikipedia 'Rotation matrix' page:
;(note: matrix for anticlockwise rotation)
;decomposition into shears:
;R = [1, -tan(x/2)][  1   , 0][1, -tan(x/2)]
;    [0,     1    ][sin(x), 1][0,     1    ]
;R = [cos(x), -sin(x)]
;    [sin(x),  cos(x)]

;simplify {{1,-tan(x/2)},{0,1}} . {{1,0},{sin(x),1}} . {{1,-tan(x/2)},{0,1}} - Wolfram|Alpha
;https://www.wolframalpha.com/input/?i=simplify+%7B%7B1,-tan(x%2F2)%7D,%7B0,1%7D%7D+.+%7B%7B1,0%7D,%7Bsin(x),1%7D%7D+.+%7B%7B1,-tan(x%2F2)%7D,%7B0,1%7D%7D
;does {{1,-tan(x/2)},{0,1}} . {{1,0},{sin(x),1}} . {{1,-tan(x/2)},{0,1}} = {{cos(x),-sin(x)},{sin(x),cos(x)}} - Wolfram|Alpha
;https://www.wolframalpha.com/input/?i=does+%7B%7B1,-tan(x%2F2)%7D,%7B0,1%7D%7D+.+%7B%7B1,0%7D,%7Bsin(x),1%7D%7D+.+%7B%7B1,-tan(x%2F2)%7D,%7B0,1%7D%7D+%3D+%7B%7Bcos(x),-sin(x)%7D,%7Bsin(x),cos(x)%7D%7D

;==================================================

;SCRIPT

#SingleInstance force

#IfWinActive ahk_class MSPaintApp
q:: ;rotate by shear/scale/shear/scale
w:: ;rotate by 3 shears
WinGet, hWnd, ID, A
WinGetClass, vWinClass, % "ahk_id " hWnd
if !(vWinClass = "MSPaintApp")
return

vApproach := InStr(A_ThisHotkey, "q") ? 1 : 2
vPi := 3.141592653589793
InputBox, vInput,, rotate by what angle?,,,,,,,, 23
if ErrorLevel
return
;angle: put a for anticlockwise, p for pi, r for radians
;(no need for d=degrees or c=clockwise)

vAngle := StrReplace(vInput, "a")

if InStr(vInput, "a")
vAngle *= -1
if InStr(vInput, "p")
vAngle *= vPi
if InStr(vInput, "p") || InStr(vInput, "r")
vAngle := Round(vAngle * (180/vPi))

WinGet, vPPath, ProcessPath, % "ahk_id " hWnd
FileGetVersion, vPVersion, % vPPath
vIsWinXP := (SubStr(vPVersion, 1, 3) = "5.1")

;click Select tool before begin:
;note: if you do 'Edit, Select All', or equivalent,
;before you begin, you may get problems,
;clicking the Select tool avoids this, e.g. problems:
;the selected image expands,
;but the canvas does not expand,
;unless you copy and paste the image
if vIsWinXP
SendMessage, 0x111, 620,,, % "ahk_id " hWnd ;WM_COMMAND := 0x111 ;Select

;==============================

;step 1: rotate by between -45 and 45 degrees
vRotate1 := Mod(vAngle, 90)
if (vRotate1 > 45)
vRotate1 -= 90

vAngleDC := vRotate1
vAngleDA := vAngleDC * -1
vAngleRC := vAngleDC * (vPi/180)
vAngleRA := vAngleRC * -1

if !(vRotate1 = 0)
{
if (vApproach = 1)
{
vMatrix1 := vAngleDC
vMatrix2 := Round((1/(Cos(vAngleRC)**2)) * 100)
vMatrix3 := -vAngleDC
vMatrix4 := Round(Cos(vAngleRC) * 100)
vList := "3,2,4,1"
}
else if (vApproach = 2)
{
vMatrix1 := -Round(-vAngleDC/2)
vMatrix2 := -Round((ATan(Sin(vAngleRC)) * (180/vPi)))
vMatrix3 := -Round(-vAngleDC/2)
vList := "3,4,3"
}

WinActivate, % "ahk_id " hWnd

Loop, Parse, vList, % ","
{
if !WinActive("ahk_id " hWnd)
return

if vIsWinXP
{
PostMessage, 0x111, 37681, 0,, % "ahk_id " hWnd ;Stretch/Skew...
WinWaitActive, Stretch and Skew
hDlg := WinExist()
ControlSetText, % "Edit" A_LoopField, % vMatrix%A_Index%, % "ahk_id " hDlg
if (vApproach = 2) && (A_Index = 4)
ControlSetText, Edit2, % vMatrix4, % "ahk_id " hDlg
ControlSend, ahk_parent, {Enter}, % "ahk_id " hDlg
}
else ;e.g. Windows 7
{
;ControlSend, ahk_parent, ^w, % "ahk_id " hWnd
SendInput, ^w
WinWaitActive, Resize and Skew
hDlg := WinExist()
ControlSetText, % "Edit" A_LoopField, % vMatrix%A_Index%, % "ahk_id " hDlg
if (vApproach = 2) && (A_Index = 4)
ControlSetText, Edit2, % vMatrix4, % "ahk_id " hDlg
ControlSend, ahk_parent, {Enter}, % "ahk_id " hDlg
}

WinWaitActive, % "ahk_id " hWnd
}
}

;==============================

;step 2: rotate by 0/90/180/270 degrees
vRotate2 := Mod(vAngle - vRotate1, 360)

;note: this stage is only supported on MS Paint (Windows XP version)
if RegExMatch(vRotate2, "^(90|180|270)\$")
&& vIsWinXP
{
PostMessage, 0x111, 37680, 0,, % "ahk_id " hWnd ;Flip/Rotate...
WinWaitActive, Flip and Rotate
hDlg := WinExist()

Control, Check,, Button4, % "ahk_id " hDlg
if (vRotate2 = 90)
Control, Check,, Button5, % "ahk_id " hDlg
else if (vRotate2 = 180)
Control, Check,, Button6, % "ahk_id " hDlg
else if (vRotate2 = 270)
Control, Check,, Button7, % "ahk_id " hDlg

ControlSend, ahk_parent, {Enter}, % "ahk_id " hDlg
}
return
#IfWinActive

;==================================================
``````

Some common transformations in linear algebra, using a 2x2 matrix, on 2D graphics, are: reflection, rotation, scaling (stretching), shearing (skewing), but *not* translation. It is mathematically possible to exactly rotate by using shears only, or by combining shears and scalings. The rotations in MS Paint are not perfect because integers are rounded, and because square pixels are not a pure mathematical entity, but the principle is correct.

If you haven't already, I'd suggest getting a copy of MS Paint (Windows XP version).
C:\Windows\System32\mspaint.exe
(AFAIK, you only need the exe files.)

[an explanation of matrix multiplication]
matrix functions - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=64480

[I'd recommend using the Gdip library for doing image rotations]
GDI+ standard library 1.45 by tic - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=6517
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Vh_
Posts: 201
Joined: 17 Mar 2017, 22:06

### Re: MS Paint: rotate by scaling/shearing (stretching/skewing)

Impressive! I tried this in windows 10 and it worked. Fun script, thanks for sharing! edit: added a smiley. rommmcek
Posts: 1007
Joined: 15 Aug 2014, 15:18

### Re: MS Paint: rotate by scaling/shearing (stretching/skewing)

Very nice extension of a rather simple tool (Paint)!

P.s.: I ran into trouble rotating big pics. So I made makeshift fix for rotate by 3 shears (w-Hotkey). Very little tested! (Win10, Dpi: 125%, HD-1920x1080 - if it matters)
Spoiler